remote_agent.go 3.9 KB

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