miner.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package ethminer
  2. import (
  3. "bytes"
  4. "github.com/ethereum/eth-go/ethchain"
  5. "github.com/ethereum/eth-go/ethlog"
  6. "github.com/ethereum/eth-go/ethutil"
  7. "github.com/ethereum/eth-go/ethwire"
  8. "sort"
  9. )
  10. var logger = ethlog.NewLogger("MINER")
  11. type Miner struct {
  12. pow ethchain.PoW
  13. ethereum ethchain.EthManager
  14. coinbase []byte
  15. reactChan chan ethutil.React
  16. txs ethchain.Transactions
  17. uncles []*ethchain.Block
  18. block *ethchain.Block
  19. powChan chan []byte
  20. powQuitChan chan ethutil.React
  21. quitChan chan bool
  22. }
  23. func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
  24. reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
  25. powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
  26. powQuitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread
  27. quitChan := make(chan bool, 1)
  28. ethereum.Reactor().Subscribe("newBlock", reactChan)
  29. ethereum.Reactor().Subscribe("newTx:pre", reactChan)
  30. // We need the quit chan to be a Reactor event.
  31. // The POW search method is actually blocking and if we don't
  32. // listen to the reactor events inside of the pow itself
  33. // The miner overseer will never get the reactor events themselves
  34. // Only after the miner will find the sha
  35. ethereum.Reactor().Subscribe("newBlock", powQuitChan)
  36. ethereum.Reactor().Subscribe("newTx:pre", powQuitChan)
  37. miner := Miner{
  38. pow: &ethchain.EasyPow{},
  39. ethereum: ethereum,
  40. coinbase: coinbase,
  41. reactChan: reactChan,
  42. powChan: powChan,
  43. powQuitChan: powQuitChan,
  44. quitChan: quitChan,
  45. }
  46. // Insert initial TXs in our little miner 'pool'
  47. miner.txs = ethereum.TxPool().Flush()
  48. miner.block = ethereum.BlockChain().NewBlock(miner.coinbase)
  49. return miner
  50. }
  51. func (miner *Miner) Start() {
  52. // Prepare inital block
  53. //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
  54. go miner.listener()
  55. logger.Infoln("Started")
  56. }
  57. func (miner *Miner) listener() {
  58. out:
  59. for {
  60. select {
  61. case <-miner.quitChan:
  62. logger.Infoln("Stopped")
  63. break out
  64. case chanMessage := <-miner.reactChan:
  65. if block, ok := chanMessage.Resource.(*ethchain.Block); ok {
  66. //logger.Infoln("Got new block via Reactor")
  67. if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 {
  68. // TODO: Perhaps continue mining to get some uncle rewards
  69. //logger.Infoln("New top block found resetting state")
  70. // Filter out which Transactions we have that were not in this block
  71. var newtxs []*ethchain.Transaction
  72. for _, tx := range miner.txs {
  73. found := false
  74. for _, othertx := range block.Transactions() {
  75. if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 {
  76. found = true
  77. }
  78. }
  79. if found == false {
  80. newtxs = append(newtxs, tx)
  81. }
  82. }
  83. miner.txs = newtxs
  84. // Setup a fresh state to mine on
  85. //miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
  86. } else {
  87. if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
  88. logger.Infoln("Adding uncle block")
  89. miner.uncles = append(miner.uncles, block)
  90. }
  91. }
  92. }
  93. if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok {
  94. found := false
  95. for _, ctx := range miner.txs {
  96. if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found {
  97. break
  98. }
  99. }
  100. if found == false {
  101. // Undo all previous commits
  102. miner.block.Undo()
  103. // Apply new transactions
  104. miner.txs = append(miner.txs, tx)
  105. }
  106. }
  107. default:
  108. miner.mineNewBlock()
  109. }
  110. }
  111. }
  112. func (self *Miner) Stop() {
  113. logger.Infoln("Stopping...")
  114. self.quitChan <- true
  115. close(self.powQuitChan)
  116. close(self.quitChan)
  117. }
  118. func (self *Miner) mineNewBlock() {
  119. stateManager := self.ethereum.StateManager()
  120. self.block = self.ethereum.BlockChain().NewBlock(self.coinbase)
  121. // Apply uncles
  122. if len(self.uncles) > 0 {
  123. self.block.SetUncles(self.uncles)
  124. }
  125. // Sort the transactions by nonce in case of odd network propagation
  126. sort.Sort(ethchain.TxByNonce{self.txs})
  127. // Accumulate all valid transactions and apply them to the new state
  128. // Error may be ignored. It's not important during mining
  129. parent := self.ethereum.BlockChain().GetBlock(self.block.PrevHash)
  130. coinbase := self.block.State().GetOrNewStateObject(self.block.Coinbase)
  131. coinbase.SetGasPool(self.block.CalcGasLimit(parent))
  132. receipts, txs, unhandledTxs, err := stateManager.ProcessTransactions(coinbase, self.block.State(), self.block, self.block, self.txs)
  133. if err != nil {
  134. logger.Debugln(err)
  135. }
  136. self.txs = append(txs, unhandledTxs...)
  137. // Set the transactions to the block so the new SHA3 can be calculated
  138. self.block.SetReceipts(receipts, txs)
  139. // Accumulate the rewards included for this block
  140. stateManager.AccumelateRewards(self.block.State(), self.block)
  141. self.block.State().Update()
  142. logger.Infof("Mining on block. Includes %v transactions", len(self.txs))
  143. // Find a valid nonce
  144. self.block.Nonce = self.pow.Search(self.block, self.powQuitChan)
  145. if self.block.Nonce != nil {
  146. err := self.ethereum.StateManager().Process(self.block, false)
  147. if err != nil {
  148. logger.Infoln(err)
  149. } else {
  150. self.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{self.block.Value().Val})
  151. logger.Infof("🔨 Mined block %x\n", self.block.Hash())
  152. logger.Infoln(self.block)
  153. // Gather the new batch of transactions currently in the tx pool
  154. self.txs = self.ethereum.TxPool().CurrentTransactions()
  155. }
  156. }
  157. }