github.com/niluplatform/go-nilu@v1.7.4-0.20200912082737-a0cb0776d52c/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/NiluPlatform/go-nilu/consensus"
    25  	"github.com/NiluPlatform/go-nilu/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  	if !atomic.CompareAndSwapInt32(&self.isMining, 1, 0) {
    57  		return // agent already stopped
    58  	}
    59  	self.stop <- struct{}{}
    60  done:
    61  	// Empty work channel
    62  	for {
    63  		select {
    64  		case <-self.workCh:
    65  		default:
    66  			break done
    67  		}
    68  	}
    69  }
    70  
    71  func (self *CpuAgent) Start() {
    72  	if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) {
    73  		return // agent already started
    74  	}
    75  	go self.update()
    76  }
    77  
    78  func (self *CpuAgent) update() {
    79  out:
    80  	for {
    81  		select {
    82  		case work := <-self.workCh:
    83  			self.mu.Lock()
    84  			if self.quitCurrentOp != nil {
    85  				close(self.quitCurrentOp)
    86  			}
    87  			self.quitCurrentOp = make(chan struct{})
    88  			go self.mine(work, self.quitCurrentOp)
    89  			self.mu.Unlock()
    90  		case <-self.stop:
    91  			self.mu.Lock()
    92  			if self.quitCurrentOp != nil {
    93  				close(self.quitCurrentOp)
    94  				self.quitCurrentOp = nil
    95  			}
    96  			self.mu.Unlock()
    97  			break out
    98  		}
    99  	}
   100  }
   101  
   102  func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
   103  	if result, err := self.engine.Seal(self.chain, work.Block, stop); result != nil {
   104  		log.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash())
   105  		self.returnCh <- &Result{work, result}
   106  	} else {
   107  		if err != nil {
   108  			log.Warn("Block sealing failed", "err", err)
   109  		}
   110  		self.returnCh <- nil
   111  	}
   112  }
   113  
   114  func (self *CpuAgent) GetHashRate() int64 {
   115  	if pow, ok := self.engine.(consensus.PoW); ok {
   116  		return int64(pow.Hashrate())
   117  	}
   118  	return 0
   119  }