github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/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-wtc 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-wtc 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 "encoding/binary" 21 "net" 22 "strconv" 23 "sync" 24 "sync/atomic" 25 26 "github.com/wtc/go-wtc/consensus" 27 "github.com/wtc/go-wtc/log" 28 ) 29 30 type CpuAgent struct { 31 mu sync.Mutex 32 33 workCh chan *Work 34 stop chan struct{} 35 quitCurrentOp chan struct{} 36 returnCh chan<- *Result 37 serverFound chan uint64 38 39 chain consensus.ChainReader 40 engine consensus.Engine 41 42 isMining int32 // isMining indicates whether the agent is currently mining 43 } 44 45 func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine) *CpuAgent { 46 miner := &CpuAgent{ 47 chain: chain, 48 engine: engine, 49 stop: make(chan struct{}, 1), 50 workCh: make(chan *Work, 1), 51 serverFound: make(chan uint64, 1), 52 } 53 isGpu, _, getport := engine.IsGPU() 54 if isGpu { 55 go startServer(miner.serverFound, getport) 56 } 57 return miner 58 } 59 60 func (self *CpuAgent) Work() chan<- *Work { 61 return self.workCh 62 } 63 func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { 64 self.returnCh = ch 65 } 66 67 func (self *CpuAgent) Stop() { 68 if !atomic.CompareAndSwapInt32(&self.isMining, 1, 0) { 69 return // agent already stopped 70 } 71 self.stop <- struct{}{} 72 done: 73 // Empty work channel 74 for { 75 select { 76 case <-self.workCh: 77 default: 78 break done 79 } 80 } 81 } 82 83 func (self *CpuAgent) Start() { 84 if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) { 85 return // agent already started 86 } 87 go self.update() 88 } 89 90 func (self *CpuAgent) update() { 91 out: 92 for { 93 select { 94 case work := <-self.workCh: 95 self.mu.Lock() 96 if self.quitCurrentOp != nil { 97 close(self.quitCurrentOp) 98 } 99 self.quitCurrentOp = make(chan struct{}) 100 go self.mine(work, self.quitCurrentOp) 101 self.mu.Unlock() 102 case <-self.stop: 103 self.mu.Lock() 104 if self.quitCurrentOp != nil { 105 close(self.quitCurrentOp) 106 self.quitCurrentOp = nil 107 } 108 self.mu.Unlock() 109 break out 110 } 111 } 112 } 113 114 func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) { 115 if result, err := self.engine.Seal(self.chain, work.Block, stop, self.serverFound); result != nil { 116 log.Info("a new block seal finish.", "blockheight", result.Number(), "hash", result.Hash()) 117 self.returnCh <- &Result{work, result} 118 } else { 119 if err != nil { 120 log.Warn("Block sealing failed", "err", err) 121 } 122 self.returnCh <- nil 123 } 124 } 125 126 func (self *CpuAgent) GetHashRate() int64 { 127 if pow, ok := self.engine.(consensus.PoW); ok { 128 return int64(pow.Hashrate()) 129 } 130 return 0 131 } 132 133 func startServer(serverFound chan uint64, listenPort int64) { 134 listenP := strconv.FormatInt(listenPort, 10) 135 //set up socket, listen port 136 netListen, err := net.Listen("tcp", "localhost:"+listenP) 137 if err != nil { 138 //fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 139 panic(err.Error()) 140 } 141 defer netListen.Close() 142 143 for { 144 conn, err := netListen.Accept() 145 if err != nil { 146 continue 147 } 148 149 //Log(conn.RemoteAddr().String(), " tcp connect success") 150 handleConnection(conn, serverFound) 151 } 152 } 153 154 //process connect 155 func handleConnection(conn net.Conn, serverFound chan uint64) { 156 defer conn.Close() 157 buffer := make([]byte, 2048) 158 159 for { 160 161 n, err := conn.Read(buffer) 162 if err != nil { 163 return 164 } 165 t, nonce := handeByte(buffer[:n]) 166 if t == 1 { 167 GPUHashrate = int64(nonce) 168 } else { 169 serverFound <- nonce 170 } 171 172 } 173 174 } 175 176 func handeByte(res []byte) (byte, uint64) { 177 if res[0] == 1 { 178 rate := make([]byte, 0) 179 for _, b := range res[1:] { 180 if b == 0 { 181 break 182 } 183 rate = append(rate, b) 184 } 185 i, err := strconv.Atoi(string(rate)) 186 if err != nil { 187 panic(err) 188 } 189 return res[0], uint64(i) 190 } else { 191 //blockByte := res[:4] 192 //blockNumber := new(big.Int).SetBytes(blockByte) 193 //input := res[4:36] 194 // nonce := new(big.Int).SetBytes(res[36:]) 195 nonce := binary.BigEndian.Uint64(res[36:]) 196 //fmt.Println("blockNumber =", blockNumber, "\nand input =", input, "\nand nonce =", res[36:], nonce) 197 return res[0], nonce 198 } 199 200 }