worker.go 6.6 KB

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