github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/miner/agent.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package miner
    13  
    14  import (
    15  	"sync"
    16  
    17  	"sync/atomic"
    18  
    19  	"github.com/Sberex/go-sberex/consensus"
    20  	"github.com/Sberex/go-sberex/log"
    21  )
    22  
    23  type CpuAgent struct {
    24  	mu sync.Mutex
    25  
    26  	workCh        chan *Work
    27  	stop          chan struct{}
    28  	quitCurrentOp chan struct{}
    29  	returnCh      chan<- *Result
    30  
    31  	chain  consensus.ChainReader
    32  	engine consensus.Engine
    33  
    34  	isMining int32 // isMining indicates whether the agent is currently mining
    35  }
    36  
    37  func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine) *CpuAgent {
    38  	miner := &CpuAgent{
    39  		chain:  chain,
    40  		engine: engine,
    41  		stop:   make(chan struct{}, 1),
    42  		workCh: make(chan *Work, 1),
    43  	}
    44  	return miner
    45  }
    46  
    47  func (self *CpuAgent) Work() chan<- *Work            { return self.workCh }
    48  func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { self.returnCh = ch }
    49  
    50  func (self *CpuAgent) Stop() {
    51  	if !atomic.CompareAndSwapInt32(&self.isMining, 1, 0) {
    52  		return // agent already stopped
    53  	}
    54  	self.stop <- struct{}{}
    55  done:
    56  	// Empty work channel
    57  	for {
    58  		select {
    59  		case <-self.workCh:
    60  		default:
    61  			break done
    62  		}
    63  	}
    64  }
    65  
    66  func (self *CpuAgent) Start() {
    67  	if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) {
    68  		return // agent already started
    69  	}
    70  	go self.update()
    71  }
    72  
    73  func (self *CpuAgent) update() {
    74  out:
    75  	for {
    76  		select {
    77  		case work := <-self.workCh:
    78  			self.mu.Lock()
    79  			if self.quitCurrentOp != nil {
    80  				close(self.quitCurrentOp)
    81  			}
    82  			self.quitCurrentOp = make(chan struct{})
    83  			go self.mine(work, self.quitCurrentOp)
    84  			self.mu.Unlock()
    85  		case <-self.stop:
    86  			self.mu.Lock()
    87  			if self.quitCurrentOp != nil {
    88  				close(self.quitCurrentOp)
    89  				self.quitCurrentOp = nil
    90  			}
    91  			self.mu.Unlock()
    92  			break out
    93  		}
    94  	}
    95  }
    96  
    97  func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
    98  	if result, err := self.engine.Seal(self.chain, work.Block, stop); result != nil {
    99  		log.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash())
   100  		self.returnCh <- &Result{work, result}
   101  	} else {
   102  		if err != nil {
   103  			log.Warn("Block sealing failed", "err", err)
   104  		}
   105  		self.returnCh <- nil
   106  	}
   107  }
   108  
   109  func (self *CpuAgent) GetHashRate() int64 {
   110  	if pow, ok := self.engine.(consensus.PoW); ok {
   111  		return int64(pow.Hashrate())
   112  	}
   113  	return 0
   114  }