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 }