worker.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package miner
  2. import (
  3. "fmt"
  4. "math/big"
  5. "sort"
  6. "sync"
  7. "time"
  8. "github.com/ethereum/ethash"
  9. "github.com/ethereum/go-ethereum/core"
  10. "github.com/ethereum/go-ethereum/core/types"
  11. "github.com/ethereum/go-ethereum/ethutil"
  12. "github.com/ethereum/go-ethereum/event"
  13. "github.com/ethereum/go-ethereum/logger"
  14. "github.com/ethereum/go-ethereum/pow"
  15. "github.com/ethereum/go-ethereum/state"
  16. "gopkg.in/fatih/set.v0"
  17. )
  18. var jsonlogger = logger.NewJsonLogger()
  19. type environment struct {
  20. totalUsedGas *big.Int
  21. state *state.StateDB
  22. coinbase *state.StateObject
  23. block *types.Block
  24. ancestors *set.Set
  25. uncles *set.Set
  26. }
  27. func env(block *types.Block, eth core.Backend) *environment {
  28. state := state.New(block.Root(), eth.Db())
  29. env := &environment{
  30. totalUsedGas: new(big.Int),
  31. state: state,
  32. block: block,
  33. ancestors: set.New(),
  34. uncles: set.New(),
  35. coinbase: state.GetOrNewStateObject(block.Coinbase()),
  36. }
  37. for _, ancestor := range eth.ChainManager().GetAncestors(block, 7) {
  38. env.ancestors.Add(string(ancestor.Hash()))
  39. }
  40. return env
  41. }
  42. type Work struct {
  43. Number uint64
  44. Nonce uint64
  45. MixDigest []byte
  46. SeedHash []byte
  47. }
  48. type Agent interface {
  49. Work() chan<- *types.Block
  50. SetWorkCh(chan<- Work)
  51. Stop()
  52. Start()
  53. Pow() pow.PoW
  54. }
  55. type worker struct {
  56. mu sync.Mutex
  57. agents []Agent
  58. recv chan Work
  59. mux *event.TypeMux
  60. quit chan struct{}
  61. pow pow.PoW
  62. eth core.Backend
  63. chain *core.ChainManager
  64. proc *core.BlockProcessor
  65. coinbase []byte
  66. current *environment
  67. mining bool
  68. }
  69. func newWorker(coinbase []byte, eth core.Backend) *worker {
  70. return &worker{
  71. eth: eth,
  72. mux: eth.EventMux(),
  73. recv: make(chan Work),
  74. chain: eth.ChainManager(),
  75. proc: eth.BlockProcessor(),
  76. coinbase: coinbase,
  77. }
  78. }
  79. func (self *worker) start() {
  80. self.mining = true
  81. self.quit = make(chan struct{})
  82. // spin up agents
  83. for _, agent := range self.agents {
  84. agent.Start()
  85. }
  86. go self.update()
  87. go self.wait()
  88. }
  89. func (self *worker) stop() {
  90. self.mining = false
  91. close(self.quit)
  92. }
  93. func (self *worker) register(agent Agent) {
  94. self.agents = append(self.agents, agent)
  95. agent.SetWorkCh(self.recv)
  96. }
  97. func (self *worker) update() {
  98. events := self.mux.Subscribe(core.ChainHeadEvent{}, core.NewMinedBlockEvent{})
  99. timer := time.NewTicker(2 * time.Second)
  100. out:
  101. for {
  102. select {
  103. case event := <-events.Chan():
  104. switch ev := event.(type) {
  105. case core.ChainHeadEvent:
  106. if self.current.block != ev.Block {
  107. self.commitNewWork()
  108. }
  109. case core.NewMinedBlockEvent:
  110. self.commitNewWork()
  111. }
  112. case <-self.quit:
  113. // stop all agents
  114. for _, agent := range self.agents {
  115. agent.Stop()
  116. }
  117. break out
  118. case <-timer.C:
  119. minerlogger.Infoln("Hash rate:", self.HashRate(), "Khash")
  120. }
  121. }
  122. events.Unsubscribe()
  123. }
  124. func (self *worker) wait() {
  125. for {
  126. for work := range self.recv {
  127. // Someone Successfully Mined!
  128. block := self.current.block
  129. if block.Number().Uint64() == work.Number && block.Nonce() == 0 {
  130. self.current.block.SetNonce(work.Nonce)
  131. self.current.block.Header().MixDigest = work.MixDigest
  132. self.current.block.Header().SeedHash = work.SeedHash
  133. jsonlogger.LogJson(&logger.EthMinerNewBlock{
  134. BlockHash: ethutil.Bytes2Hex(block.Hash()),
  135. BlockNumber: block.Number(),
  136. ChainHeadHash: ethutil.Bytes2Hex(block.ParentHeaderHash),
  137. BlockPrevHash: ethutil.Bytes2Hex(block.ParentHeaderHash),
  138. })
  139. if err := self.chain.InsertChain(types.Blocks{self.current.block}); err == nil {
  140. self.mux.Post(core.NewMinedBlockEvent{self.current.block})
  141. } else {
  142. self.commitNewWork()
  143. }
  144. }
  145. break
  146. }
  147. }
  148. }
  149. func (self *worker) push() {
  150. if self.mining {
  151. self.current.block.Header().GasUsed = self.current.totalUsedGas
  152. self.current.block.SetRoot(self.current.state.Root())
  153. // push new work to agents
  154. for _, agent := range self.agents {
  155. agent.Work() <- self.current.block
  156. }
  157. }
  158. }
  159. func (self *worker) commitNewWork() {
  160. self.mu.Lock()
  161. defer self.mu.Unlock()
  162. block := self.chain.NewBlock(self.coinbase)
  163. seednum := ethash.GetSeedBlockNum(block.NumberU64())
  164. block.Header().SeedHash = self.chain.GetBlockByNumber(seednum).SeedHash()
  165. self.current = env(block, self.eth)
  166. parent := self.chain.GetBlock(self.current.block.ParentHash())
  167. self.current.coinbase.SetGasPool(core.CalcGasLimit(parent, self.current.block))
  168. transactions := self.eth.TxPool().GetTransactions()
  169. sort.Sort(types.TxByNonce{transactions})
  170. minerlogger.Infof("committing new work with %d txs\n", len(transactions))
  171. // Keep track of transactions which return errors so they can be removed
  172. var remove types.Transactions
  173. gasLimit:
  174. for _, tx := range transactions {
  175. err := self.commitTransaction(tx)
  176. switch {
  177. case core.IsNonceErr(err):
  178. // Remove invalid transactions
  179. remove = append(remove, tx)
  180. case state.IsGasLimitErr(err):
  181. // Break on gas limit
  182. break gasLimit
  183. }
  184. if err != nil {
  185. minerlogger.Infoln(err)
  186. }
  187. }
  188. self.eth.TxPool().RemoveSet(remove)
  189. self.current.coinbase.AddBalance(core.BlockReward)
  190. self.current.state.Update(ethutil.Big0)
  191. self.push()
  192. }
  193. var (
  194. inclusionReward = new(big.Int).Div(core.BlockReward, big.NewInt(32))
  195. _uncleReward = new(big.Int).Mul(core.BlockReward, big.NewInt(15))
  196. uncleReward = new(big.Int).Div(_uncleReward, big.NewInt(16))
  197. )
  198. func (self *worker) commitUncle(uncle *types.Header) error {
  199. if self.current.uncles.Has(string(uncle.Hash())) {
  200. // Error not unique
  201. return core.UncleError("Uncle not unique")
  202. }
  203. self.current.uncles.Add(string(uncle.Hash()))
  204. if !self.current.ancestors.Has(string(uncle.ParentHash)) {
  205. return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
  206. }
  207. if !self.pow.Verify(types.NewBlockWithHeader(uncle)) {
  208. return core.ValidationError("Uncle's nonce is invalid (= %x)", uncle.Nonce)
  209. }
  210. uncleAccount := self.current.state.GetAccount(uncle.Coinbase)
  211. uncleAccount.AddBalance(uncleReward)
  212. self.current.coinbase.AddBalance(uncleReward)
  213. return nil
  214. }
  215. func (self *worker) commitTransaction(tx *types.Transaction) error {
  216. //fmt.Printf("proc %x %v\n", tx.Hash()[:3], tx.Nonce())
  217. receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true)
  218. if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err)) {
  219. return err
  220. }
  221. self.current.block.AddTransaction(tx)
  222. self.current.block.AddReceipt(receipt)
  223. return nil
  224. }
  225. func (self *worker) HashRate() int64 {
  226. var tot int64
  227. for _, agent := range self.agents {
  228. tot += agent.Pow().GetHashrate()
  229. }
  230. return tot
  231. }