github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/miner/miner.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:40</date>
    10  //</624450100424347648>
    11  
    12  
    13  //Package Miner实现以太坊块创建和挖掘。
    14  package miner
    15  
    16  import (
    17  	"fmt"
    18  	"sync/atomic"
    19  	"time"
    20  
    21  	"github.com/ethereum/go-ethereum/common"
    22  	"github.com/ethereum/go-ethereum/consensus"
    23  	"github.com/ethereum/go-ethereum/core"
    24  	"github.com/ethereum/go-ethereum/core/state"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/eth/downloader"
    27  	"github.com/ethereum/go-ethereum/event"
    28  	"github.com/ethereum/go-ethereum/log"
    29  	"github.com/ethereum/go-ethereum/params"
    30  )
    31  
    32  //后端包装挖掘所需的所有方法。
    33  type Backend interface {
    34  	BlockChain() *core.BlockChain
    35  	TxPool() *core.TxPool
    36  }
    37  
    38  //Miner创建块并搜索工作证明值。
    39  type Miner struct {
    40  	mux      *event.TypeMux
    41  	worker   *worker
    42  	coinbase common.Address
    43  	eth      Backend
    44  	engine   consensus.Engine
    45  	exitCh   chan struct{}
    46  
    47  canStart    int32 //can start指示是否可以启动挖掘操作
    48  shouldStart int32 //should start指示是否应在同步后启动
    49  }
    50  
    51  func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, recommit time.Duration, gasFloor, gasCeil uint64, isLocalBlock func(block *types.Block) bool) *Miner {
    52  	miner := &Miner{
    53  		eth:      eth,
    54  		mux:      mux,
    55  		engine:   engine,
    56  		exitCh:   make(chan struct{}),
    57  		worker:   newWorker(config, engine, eth, mux, recommit, gasFloor, gasCeil, isLocalBlock),
    58  		canStart: 1,
    59  	}
    60  	go miner.update()
    61  
    62  	return miner
    63  }
    64  
    65  //更新可以跟踪下载程序事件。请注意,这是一种一次性更新循环。
    66  //一旦广播“完成”或“失败”,事件将被取消注册,并且
    67  //循环已退出。这是为了防止一个主要的安全漏洞,外部方可以在其中阻止您
    68  //只要DOS继续,就停止您的挖掘操作。
    69  func (self *Miner) update() {
    70  	events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
    71  	defer events.Unsubscribe()
    72  
    73  	for {
    74  		select {
    75  		case ev := <-events.Chan():
    76  			if ev == nil {
    77  				return
    78  			}
    79  			switch ev.Data.(type) {
    80  			case downloader.StartEvent:
    81  				atomic.StoreInt32(&self.canStart, 0)
    82  				if self.Mining() {
    83  					self.Stop()
    84  					atomic.StoreInt32(&self.shouldStart, 1)
    85  					log.Info("Mining aborted due to sync")
    86  				}
    87  			case downloader.DoneEvent, downloader.FailedEvent:
    88  				shouldStart := atomic.LoadInt32(&self.shouldStart) == 1
    89  
    90  				atomic.StoreInt32(&self.canStart, 1)
    91  				atomic.StoreInt32(&self.shouldStart, 0)
    92  				if shouldStart {
    93  					self.Start(self.coinbase)
    94  				}
    95  //立即停止并忽略所有其他挂起事件
    96  				return
    97  			}
    98  		case <-self.exitCh:
    99  			return
   100  		}
   101  	}
   102  }
   103  
   104  func (self *Miner) Start(coinbase common.Address) {
   105  	atomic.StoreInt32(&self.shouldStart, 1)
   106  	self.SetEtherbase(coinbase)
   107  
   108  	if atomic.LoadInt32(&self.canStart) == 0 {
   109  		log.Info("Network syncing, will start miner afterwards")
   110  		return
   111  	}
   112  	self.worker.start()
   113  }
   114  
   115  func (self *Miner) Stop() {
   116  	self.worker.stop()
   117  	atomic.StoreInt32(&self.shouldStart, 0)
   118  }
   119  
   120  func (self *Miner) Close() {
   121  	self.worker.close()
   122  	close(self.exitCh)
   123  }
   124  
   125  func (self *Miner) Mining() bool {
   126  	return self.worker.isRunning()
   127  }
   128  
   129  func (self *Miner) HashRate() uint64 {
   130  	if pow, ok := self.engine.(consensus.PoW); ok {
   131  		return uint64(pow.Hashrate())
   132  	}
   133  	return 0
   134  }
   135  
   136  func (self *Miner) SetExtra(extra []byte) error {
   137  	if uint64(len(extra)) > params.MaximumExtraDataSize {
   138  		return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
   139  	}
   140  	self.worker.setExtra(extra)
   141  	return nil
   142  }
   143  
   144  //setrecommittinterval设置密封工作重新提交的间隔。
   145  func (self *Miner) SetRecommitInterval(interval time.Duration) {
   146  	self.worker.setRecommitInterval(interval)
   147  }
   148  
   149  //挂起返回当前挂起的块和关联状态。
   150  func (self *Miner) Pending() (*types.Block, *state.StateDB) {
   151  	return self.worker.pending()
   152  }
   153  
   154  //PendingBlock返回当前挂起的块。
   155  //
   156  //注意,要访问挂起块和挂起状态
   157  //同时,请使用pending(),因为pending状态可以
   158  //在多个方法调用之间切换
   159  func (self *Miner) PendingBlock() *types.Block {
   160  	return self.worker.pendingBlock()
   161  }
   162  
   163  func (self *Miner) SetEtherbase(addr common.Address) {
   164  	self.coinbase = addr
   165  	self.worker.setEtherbase(addr)
   166  }
   167