github.com/klaytn/klaytn@v1.12.1/work/agent.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from miner/agent.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package work 22 23 import ( 24 "sync" 25 "sync/atomic" 26 27 "github.com/klaytn/klaytn/common" 28 "github.com/klaytn/klaytn/consensus" 29 ) 30 31 type CpuAgent struct { 32 mu sync.Mutex 33 34 workCh chan *Task 35 stop chan struct{} 36 quitCurrentOp chan struct{} 37 returnCh chan<- *Result 38 39 chain consensus.ChainReader 40 engine consensus.Engine 41 42 isMining int32 // isMining indicates whether the agent is currently mining 43 44 nodetype common.ConnType 45 } 46 47 func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine, nodetype common.ConnType) *CpuAgent { 48 miner := &CpuAgent{ 49 chain: chain, 50 engine: engine, 51 stop: make(chan struct{}, 1), 52 workCh: make(chan *Task, 1), 53 nodetype: nodetype, 54 } 55 return miner 56 } 57 58 func (self *CpuAgent) Work() chan<- *Task { return self.workCh } 59 func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { self.returnCh = ch } 60 61 func (self *CpuAgent) Stop() { 62 if !atomic.CompareAndSwapInt32(&self.isMining, 1, 0) { 63 return // agent already stopped 64 } 65 self.stop <- struct{}{} 66 done: 67 // Empty work channel 68 for { 69 select { 70 case <-self.workCh: 71 default: 72 break done 73 } 74 } 75 } 76 77 func (self *CpuAgent) Start() { 78 if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) { 79 return // agent already started 80 } 81 go self.update() 82 } 83 84 func (self *CpuAgent) update() { 85 out: 86 for { 87 select { 88 case work := <-self.workCh: 89 self.mu.Lock() 90 if self.quitCurrentOp != nil { 91 close(self.quitCurrentOp) 92 } 93 self.quitCurrentOp = make(chan struct{}) 94 go self.mine(work, self.quitCurrentOp) 95 self.mu.Unlock() 96 case <-self.stop: 97 self.mu.Lock() 98 if self.quitCurrentOp != nil { 99 close(self.quitCurrentOp) 100 self.quitCurrentOp = nil 101 } 102 self.mu.Unlock() 103 break out 104 } 105 } 106 } 107 108 func (self *CpuAgent) mine(work *Task, stop <-chan struct{}) { 109 // TODO-Klaytn drop or missing tx and remove mining on PN and EN 110 if self.nodetype != common.CONSENSUSNODE { 111 ResultChGauge.Update(ResultChGauge.Value() + 1) 112 self.returnCh <- &Result{work, nil} 113 return 114 } 115 116 if result, err := self.engine.Seal(self.chain, work.Block, stop); result != nil { 117 logger.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash()) 118 119 ResultChGauge.Update(ResultChGauge.Value() + 1) 120 self.returnCh <- &Result{work, result} 121 } else { 122 if err != nil { 123 logger.Warn("Block sealing failed", "err", err) 124 } 125 ResultChGauge.Update(ResultChGauge.Value() + 1) 126 self.returnCh <- nil 127 } 128 } 129 130 func (self *CpuAgent) GetHashRate() int64 { 131 if pow, ok := self.engine.(consensus.PoW); ok { 132 return int64(pow.Hashrate()) 133 } 134 return 0 135 }