remote_agent.go 4.0 KB

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