github.com/ylsGit/go-ethereum@v1.6.5/miner/agent.go (about)

     1  // Copyright 2015 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
    18  
    19  import (
    20  	"sync"
    21  
    22  	"sync/atomic"
    23  
    24  	"github.com/ethereum/go-ethereum/consensus"
    25  	"github.com/ethereum/go-ethereum/log"
    26  )
    27  
    28  type CpuAgent struct {
    29  	mu sync.Mutex
    30  
    31  	workCh        chan *Work
    32  	stop          chan struct{}
    33  	quitCurrentOp chan struct{}
    34  	returnCh      chan<- *Result
    35  
    36  	chain  consensus.ChainReader
    37  	engine consensus.Engine
    38  
    39  	isMining int32 // isMining indicates whether the agent is currently mining
    40  }
    41  
    42  func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine) *CpuAgent {
    43  	miner := &CpuAgent{
    44  		chain:  chain,
    45  		engine: engine,
    46  		stop:   make(chan struct{}, 1),
    47  		workCh: make(chan *Work, 1),
    48  	}
    49  	return miner
    50  }
    51  
    52  func (self *CpuAgent) Work() chan<- *Work            { return self.workCh }
    53  func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { self.returnCh = ch }
    54  
    55  func (self *CpuAgent) Stop() {
    56  	self.stop <- struct{}{}
    57  }
    58  
    59  func (self *CpuAgent) Start() {
    60  	if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) {
    61  		return // agent already started
    62  	}
    63  	go self.update()
    64  }
    65  
    66  func (self *CpuAgent) update() {
    67  out:
    68  	for {
    69  		select {
    70  		case work := <-self.workCh:
    71  			self.mu.Lock()
    72  			if self.quitCurrentOp != nil {
    73  				close(self.quitCurrentOp)
    74  			}
    75  			self.quitCurrentOp = make(chan struct{})
    76  			go self.mine(work, self.quitCurrentOp)
    77  			self.mu.Unlock()
    78  		case <-self.stop:
    79  			self.mu.Lock()
    80  			if self.quitCurrentOp != nil {
    81  				close(self.quitCurrentOp)
    82  				self.quitCurrentOp = nil
    83  			}
    84  			self.mu.Unlock()
    85  			break out
    86  		}
    87  	}
    88  
    89  done:
    90  	// Empty work channel
    91  	for {
    92  		select {
    93  		case <-self.workCh:
    94  		default:
    95  			break done
    96  		}
    97  	}
    98  	atomic.StoreInt32(&self.isMining, 0)
    99  }
   100  
   101  func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
   102  	if result, err := self.engine.Seal(self.chain, work.Block, stop); result != nil {
   103  		log.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash())
   104  		self.returnCh <- &Result{work, result}
   105  	} else {
   106  		if err != nil {
   107  			log.Warn("Block sealing failed", "err", err)
   108  		}
   109  		self.returnCh <- nil
   110  	}
   111  }
   112  
   113  func (self *CpuAgent) GetHashRate() int64 {
   114  	if pow, ok := self.engine.(consensus.PoW); ok {
   115  		return int64(pow.Hashrate())
   116  	}
   117  	return 0
   118  }