chain_manager.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. package core
  2. import (
  3. "fmt"
  4. "math/big"
  5. "github.com/ethereum/go-ethereum/core/types"
  6. "github.com/ethereum/go-ethereum/ethutil"
  7. "github.com/ethereum/go-ethereum/event"
  8. "github.com/ethereum/go-ethereum/logger"
  9. "github.com/ethereum/go-ethereum/state"
  10. )
  11. var chainlogger = logger.NewLogger("CHAIN")
  12. func AddTestNetFunds(block *types.Block) {
  13. for _, addr := range []string{
  14. "51ba59315b3a95761d0863b05ccc7a7f54703d99",
  15. "e4157b34ea9615cfbde6b4fda419828124b70c78",
  16. "b9c015918bdaba24b4ff057a92a3873d6eb201be",
  17. "6c386a4b26f73c802f34673f7248bb118f97424a",
  18. "cd2a3d9f938e13cd947ec05abc7fe734df8dd826",
  19. "2ef47100e0787b915105fd5e3f4ff6752079d5cb",
  20. "e6716f9544a56c530d868e4bfbacb172315bdead",
  21. "1a26338f0d905e295fccb71fa9ea849ffa12aaf4",
  22. } {
  23. codedAddr := ethutil.Hex2Bytes(addr)
  24. account := block.State().GetAccount(codedAddr)
  25. account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200)
  26. block.State().UpdateStateObject(account)
  27. }
  28. }
  29. func CalcDifficulty(block, parent *types.Block) *big.Int {
  30. diff := new(big.Int)
  31. adjust := new(big.Int).Rsh(parent.Difficulty, 10)
  32. if block.Time >= parent.Time+5 {
  33. diff.Sub(parent.Difficulty, adjust)
  34. } else {
  35. diff.Add(parent.Difficulty, adjust)
  36. }
  37. return diff
  38. }
  39. type ChainManager struct {
  40. //eth EthManager
  41. processor types.BlockProcessor
  42. eventMux *event.TypeMux
  43. genesisBlock *types.Block
  44. // Last known total difficulty
  45. TD *big.Int
  46. LastBlockNumber uint64
  47. CurrentBlock *types.Block
  48. LastBlockHash []byte
  49. transState *state.StateDB
  50. }
  51. func NewChainManager(mux *event.TypeMux) *ChainManager {
  52. bc := &ChainManager{}
  53. bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis))
  54. bc.eventMux = mux
  55. bc.setLastBlock()
  56. bc.transState = bc.State().Copy()
  57. return bc
  58. }
  59. func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
  60. self.processor = proc
  61. }
  62. func (self *ChainManager) State() *state.StateDB {
  63. return self.CurrentBlock.State()
  64. }
  65. func (self *ChainManager) TransState() *state.StateDB {
  66. return self.transState
  67. }
  68. func (bc *ChainManager) setLastBlock() {
  69. data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
  70. if len(data) != 0 {
  71. // Prep genesis
  72. AddTestNetFunds(bc.genesisBlock)
  73. block := types.NewBlockFromBytes(data)
  74. bc.CurrentBlock = block
  75. bc.LastBlockHash = block.Hash()
  76. bc.LastBlockNumber = block.Number.Uint64()
  77. // Set the last know difficulty (might be 0x0 as initial value, Genesis)
  78. bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
  79. } else {
  80. bc.Reset()
  81. }
  82. chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash())
  83. }
  84. // Block creation & chain handling
  85. func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
  86. var root interface{}
  87. hash := ZeroHash256
  88. if bc.CurrentBlock != nil {
  89. root = bc.CurrentBlock.Root()
  90. hash = bc.LastBlockHash
  91. }
  92. block := types.CreateBlock(
  93. root,
  94. hash,
  95. coinbase,
  96. ethutil.BigPow(2, 32),
  97. nil,
  98. "")
  99. parent := bc.CurrentBlock
  100. if parent != nil {
  101. block.Difficulty = CalcDifficulty(block, parent)
  102. block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1)
  103. block.GasLimit = block.CalcGasLimit(bc.CurrentBlock)
  104. }
  105. return block
  106. }
  107. func (bc *ChainManager) Reset() {
  108. AddTestNetFunds(bc.genesisBlock)
  109. bc.genesisBlock.Trie().Sync()
  110. // Prepare the genesis block
  111. bc.write(bc.genesisBlock)
  112. bc.insert(bc.genesisBlock)
  113. bc.CurrentBlock = bc.genesisBlock
  114. bc.SetTotalDifficulty(ethutil.Big("0"))
  115. // Set the last know difficulty (might be 0x0 as initial value, Genesis)
  116. bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
  117. }
  118. func (self *ChainManager) Export() []byte {
  119. chainlogger.Infoln("exporting", self.CurrentBlock.Number, "blocks")
  120. blocks := make(types.Blocks, int(self.CurrentBlock.Number.Int64())+1)
  121. for block := self.CurrentBlock; block != nil; block = self.GetBlock(block.PrevHash) {
  122. blocks[block.Number.Int64()] = block
  123. }
  124. return ethutil.Encode(blocks)
  125. }
  126. func (bc *ChainManager) insert(block *types.Block) {
  127. encodedBlock := block.RlpEncode()
  128. ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
  129. bc.CurrentBlock = block
  130. bc.LastBlockHash = block.Hash()
  131. }
  132. func (bc *ChainManager) write(block *types.Block) {
  133. bc.writeBlockInfo(block)
  134. encodedBlock := block.RlpEncode()
  135. ethutil.Config.Db.Put(block.Hash(), encodedBlock)
  136. }
  137. // Accessors
  138. func (bc *ChainManager) Genesis() *types.Block {
  139. return bc.genesisBlock
  140. }
  141. // Block fetching methods
  142. func (bc *ChainManager) HasBlock(hash []byte) bool {
  143. data, _ := ethutil.Config.Db.Get(hash)
  144. return len(data) != 0
  145. }
  146. func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) {
  147. block := self.GetBlock(hash)
  148. if block == nil {
  149. return
  150. }
  151. // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
  152. for i := uint64(0); i < max; i++ {
  153. chain = append(chain, block.Hash())
  154. if block.Number.Cmp(ethutil.Big0) <= 0 {
  155. break
  156. }
  157. block = self.GetBlock(block.PrevHash)
  158. }
  159. return
  160. }
  161. func (self *ChainManager) GetBlock(hash []byte) *types.Block {
  162. data, _ := ethutil.Config.Db.Get(hash)
  163. if len(data) == 0 {
  164. return nil
  165. }
  166. return types.NewBlockFromBytes(data)
  167. }
  168. func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
  169. block := self.CurrentBlock
  170. for ; block != nil; block = self.GetBlock(block.PrevHash) {
  171. if block.Number.Uint64() == num {
  172. break
  173. }
  174. }
  175. if block != nil && block.Number.Uint64() == 0 && num != 0 {
  176. return nil
  177. }
  178. return block
  179. }
  180. func (bc *ChainManager) SetTotalDifficulty(td *big.Int) {
  181. ethutil.Config.Db.Put([]byte("LTD"), td.Bytes())
  182. bc.TD = td
  183. }
  184. func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
  185. parent := self.GetBlock(block.PrevHash)
  186. if parent == nil {
  187. return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash)
  188. }
  189. parentTd := parent.BlockInfo().TD
  190. uncleDiff := new(big.Int)
  191. for _, uncle := range block.Uncles {
  192. uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
  193. }
  194. td := new(big.Int)
  195. td = td.Add(parentTd, uncleDiff)
  196. td = td.Add(td, block.Difficulty)
  197. return td, nil
  198. }
  199. func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo {
  200. bi := types.BlockInfo{}
  201. data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
  202. bi.RlpDecode(data)
  203. return bi
  204. }
  205. // Unexported method for writing extra non-essential block info to the db
  206. func (bc *ChainManager) writeBlockInfo(block *types.Block) {
  207. bc.LastBlockNumber++
  208. bi := types.BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD}
  209. // For now we use the block hash with the words "info" appended as key
  210. ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode())
  211. }
  212. func (bc *ChainManager) Stop() {
  213. if bc.CurrentBlock != nil {
  214. chainlogger.Infoln("Stopped")
  215. }
  216. }
  217. func (self *ChainManager) InsertChain(chain types.Blocks) error {
  218. for _, block := range chain {
  219. td, messages, err := self.processor.Process(block)
  220. if err != nil {
  221. if IsKnownBlockErr(err) {
  222. continue
  223. }
  224. chainlogger.Infof("block #%v process failed (%x)\n", block.Number, block.Hash()[:4])
  225. chainlogger.Infoln(block)
  226. chainlogger.Infoln(err)
  227. return err
  228. }
  229. self.write(block)
  230. if td.Cmp(self.TD) > 0 {
  231. if block.Number.Cmp(new(big.Int).Add(self.CurrentBlock.Number, ethutil.Big1)) < 0 {
  232. chainlogger.Infof("Split detected. New head #%v (%x), was #%v (%x)\n", block.Number, block.Hash()[:4], self.CurrentBlock.Number, self.CurrentBlock.Hash()[:4])
  233. }
  234. self.SetTotalDifficulty(td)
  235. self.insert(block)
  236. self.transState = self.State().Copy()
  237. //sm.eth.TxPool().RemoveSet(block.Transactions())
  238. }
  239. self.eventMux.Post(NewBlockEvent{block})
  240. self.eventMux.Post(messages)
  241. }
  242. return nil
  243. }