github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/miner/remote_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 "math/big" 21 "sync" 22 "time" 23 24 "github.com/ethereum/ethash" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/logger" 27 "github.com/ethereum/go-ethereum/logger/glog" 28 ) 29 30 type hashrate struct { 31 ping time.Time 32 rate uint64 33 } 34 35 type RemoteAgent struct { 36 mu sync.Mutex 37 38 quit chan struct{} 39 workCh chan *Work 40 returnCh chan<- *Result 41 42 currentWork *Work 43 work map[common.Hash]*Work 44 45 hashrateMu sync.RWMutex 46 hashrate map[common.Hash]hashrate 47 } 48 49 func NewRemoteAgent() *RemoteAgent { 50 agent := &RemoteAgent{work: make(map[common.Hash]*Work), hashrate: make(map[common.Hash]hashrate)} 51 52 return agent 53 } 54 55 func (a *RemoteAgent) SubmitHashrate(id common.Hash, rate uint64) { 56 a.hashrateMu.Lock() 57 defer a.hashrateMu.Unlock() 58 59 a.hashrate[id] = hashrate{time.Now(), rate} 60 } 61 62 func (a *RemoteAgent) Work() chan<- *Work { 63 return a.workCh 64 } 65 66 func (a *RemoteAgent) SetReturnCh(returnCh chan<- *Result) { 67 a.returnCh = returnCh 68 } 69 70 func (a *RemoteAgent) Start() { 71 a.quit = make(chan struct{}) 72 a.workCh = make(chan *Work, 1) 73 go a.maintainLoop() 74 } 75 76 func (a *RemoteAgent) Stop() { 77 close(a.quit) 78 close(a.workCh) 79 } 80 81 // GetHashRate returns the accumulated hashrate of all identifier combined 82 func (a *RemoteAgent) GetHashRate() (tot int64) { 83 a.hashrateMu.RLock() 84 defer a.hashrateMu.RUnlock() 85 86 // this could overflow 87 for _, hashrate := range a.hashrate { 88 tot += int64(hashrate.rate) 89 } 90 return 91 } 92 93 func (a *RemoteAgent) GetWork() [3]string { 94 a.mu.Lock() 95 defer a.mu.Unlock() 96 97 var res [3]string 98 99 if a.currentWork != nil { 100 block := a.currentWork.Block 101 102 res[0] = block.HashNoNonce().Hex() 103 seedHash, _ := ethash.GetSeedHash(block.NumberU64()) 104 res[1] = common.BytesToHash(seedHash).Hex() 105 // Calculate the "target" to be returned to the external miner 106 n := big.NewInt(1) 107 n.Lsh(n, 255) 108 n.Div(n, block.Difficulty()) 109 n.Lsh(n, 1) 110 res[2] = common.BytesToHash(n.Bytes()).Hex() 111 112 a.work[block.HashNoNonce()] = a.currentWork 113 } 114 115 return res 116 } 117 118 // Returns true or false, but does not indicate if the PoW was correct 119 func (a *RemoteAgent) SubmitWork(nonce uint64, mixDigest, hash common.Hash) bool { 120 a.mu.Lock() 121 defer a.mu.Unlock() 122 123 // Make sure the work submitted is present 124 if a.work[hash] != nil { 125 block := a.work[hash].Block.WithMiningResult(nonce, mixDigest) 126 a.returnCh <- &Result{a.work[hash], block} 127 128 delete(a.work, hash) 129 130 return true 131 } else { 132 glog.V(logger.Info).Infof("Work was submitted for %x but no pending work found\n", hash) 133 } 134 135 return false 136 } 137 138 func (a *RemoteAgent) maintainLoop() { 139 ticker := time.Tick(5 * time.Second) 140 141 out: 142 for { 143 select { 144 case <-a.quit: 145 break out 146 case work := <-a.workCh: 147 a.mu.Lock() 148 a.currentWork = work 149 a.mu.Unlock() 150 case <-ticker: 151 // cleanup 152 a.mu.Lock() 153 for hash, work := range a.work { 154 if time.Since(work.createdAt) > 7*(12*time.Second) { 155 delete(a.work, hash) 156 } 157 } 158 a.mu.Unlock() 159 160 a.hashrateMu.Lock() 161 for id, hashrate := range a.hashrate { 162 if time.Since(hashrate.ping) > 10*time.Second { 163 delete(a.hashrate, id) 164 } 165 } 166 a.hashrateMu.Unlock() 167 } 168 } 169 }