github.com/karalabe/go-ethereum@v0.8.5/core/chain_manager.go (about) 1 package core 2 3 import ( 4 "bytes" 5 "fmt" 6 "math/big" 7 "sync" 8 9 "github.com/ethereum/go-ethereum/core/types" 10 "github.com/ethereum/go-ethereum/ethutil" 11 "github.com/ethereum/go-ethereum/event" 12 "github.com/ethereum/go-ethereum/logger" 13 "github.com/ethereum/go-ethereum/rlp" 14 "github.com/ethereum/go-ethereum/state" 15 ) 16 17 var chainlogger = logger.NewLogger("CHAIN") 18 19 type ChainEvent struct { 20 Block *types.Block 21 Td *big.Int 22 } 23 24 type StateQuery interface { 25 GetAccount(addr []byte) *state.StateObject 26 } 27 28 func CalcDifficulty(block, parent *types.Block) *big.Int { 29 diff := new(big.Int) 30 31 adjust := new(big.Int).Rsh(parent.Difficulty(), 10) 32 if block.Time() >= parent.Time()+8 { 33 diff.Sub(parent.Difficulty(), adjust) 34 } else { 35 diff.Add(parent.Difficulty(), adjust) 36 } 37 38 return diff 39 } 40 41 func CalculateTD(block, parent *types.Block) *big.Int { 42 uncleDiff := new(big.Int) 43 for _, uncle := range block.Uncles() { 44 uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) 45 } 46 47 // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty 48 td := new(big.Int) 49 td = td.Add(parent.Td, uncleDiff) 50 td = td.Add(td, block.Header().Difficulty) 51 52 return td 53 } 54 55 func CalcGasLimit(parent, block *types.Block) *big.Int { 56 if block.Number().Cmp(big.NewInt(0)) == 0 { 57 return ethutil.BigPow(10, 6) 58 } 59 60 // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 61 62 previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit()) 63 current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5)) 64 curInt := new(big.Int).Div(current.Num(), current.Denom()) 65 66 result := new(big.Int).Add(previous, curInt) 67 result.Div(result, big.NewInt(1024)) 68 69 min := big.NewInt(125000) 70 71 return ethutil.BigMax(min, result) 72 } 73 74 type ChainManager struct { 75 //eth EthManager 76 db ethutil.Database 77 processor types.BlockProcessor 78 eventMux *event.TypeMux 79 genesisBlock *types.Block 80 // Last known total difficulty 81 mu sync.RWMutex 82 tsmu sync.RWMutex 83 td *big.Int 84 currentBlock *types.Block 85 lastBlockHash []byte 86 87 transState *state.StateDB 88 } 89 90 func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager { 91 bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux} 92 bc.setLastBlock() 93 bc.transState = bc.State().Copy() 94 95 return bc 96 } 97 98 func (self *ChainManager) Td() *big.Int { 99 self.mu.RLock() 100 defer self.mu.RUnlock() 101 102 return self.td 103 } 104 105 func (self *ChainManager) LastBlockHash() []byte { 106 self.mu.RLock() 107 defer self.mu.RUnlock() 108 109 return self.lastBlockHash 110 } 111 112 func (self *ChainManager) CurrentBlock() *types.Block { 113 self.mu.RLock() 114 defer self.mu.RUnlock() 115 116 return self.currentBlock 117 } 118 119 func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { 120 self.mu.RLock() 121 defer self.mu.RUnlock() 122 123 return self.td, self.currentBlock.Hash(), self.Genesis().Hash() 124 } 125 126 func (self *ChainManager) SetProcessor(proc types.BlockProcessor) { 127 self.processor = proc 128 } 129 130 func (self *ChainManager) State() *state.StateDB { 131 return state.New(self.CurrentBlock().Root(), self.db) 132 } 133 134 func (self *ChainManager) TransState() *state.StateDB { 135 self.tsmu.RLock() 136 defer self.tsmu.RUnlock() 137 138 return self.transState 139 } 140 141 func (self *ChainManager) setTransState(statedb *state.StateDB) { 142 self.transState = statedb 143 } 144 145 func (bc *ChainManager) setLastBlock() { 146 data, _ := bc.db.Get([]byte("LastBlock")) 147 if len(data) != 0 { 148 var block types.Block 149 rlp.Decode(bytes.NewReader(data), &block) 150 bc.currentBlock = &block 151 bc.lastBlockHash = block.Hash() 152 153 // Set the last know difficulty (might be 0x0 as initial value, Genesis) 154 bc.td = ethutil.BigD(bc.db.LastKnownTD()) 155 } else { 156 bc.Reset() 157 } 158 159 chainlogger.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td) 160 } 161 162 // Block creation & chain handling 163 func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { 164 bc.mu.RLock() 165 defer bc.mu.RUnlock() 166 167 var root []byte 168 parentHash := ZeroHash256 169 170 if bc.currentBlock != nil { 171 root = bc.currentBlock.Header().Root 172 parentHash = bc.lastBlockHash 173 } 174 175 block := types.NewBlock( 176 parentHash, 177 coinbase, 178 root, 179 ethutil.BigPow(2, 32), 180 nil, 181 "") 182 block.SetUncles(nil) 183 block.SetTransactions(nil) 184 block.SetReceipts(nil) 185 186 parent := bc.currentBlock 187 if parent != nil { 188 header := block.Header() 189 header.Difficulty = CalcDifficulty(block, parent) 190 header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) 191 header.GasLimit = CalcGasLimit(parent, block) 192 193 } 194 195 return block 196 } 197 198 func (bc *ChainManager) Reset() { 199 bc.mu.Lock() 200 defer bc.mu.Unlock() 201 202 for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) { 203 bc.db.Delete(block.Hash()) 204 } 205 206 // Prepare the genesis block 207 bc.write(bc.genesisBlock) 208 bc.insert(bc.genesisBlock) 209 bc.currentBlock = bc.genesisBlock 210 211 bc.setTotalDifficulty(ethutil.Big("0")) 212 } 213 214 func (self *ChainManager) Export() []byte { 215 self.mu.RLock() 216 defer self.mu.RUnlock() 217 218 chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number) 219 220 blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1) 221 for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) { 222 blocks[block.NumberU64()] = block 223 } 224 225 return ethutil.Encode(blocks) 226 } 227 228 func (bc *ChainManager) insert(block *types.Block) { 229 encodedBlock := ethutil.Encode(block) 230 bc.db.Put([]byte("LastBlock"), encodedBlock) 231 bc.currentBlock = block 232 bc.lastBlockHash = block.Hash() 233 } 234 235 func (bc *ChainManager) write(block *types.Block) { 236 encodedBlock := ethutil.Encode(block.RlpDataForStorage()) 237 bc.db.Put(block.Hash(), encodedBlock) 238 } 239 240 // Accessors 241 func (bc *ChainManager) Genesis() *types.Block { 242 return bc.genesisBlock 243 } 244 245 // Block fetching methods 246 func (bc *ChainManager) HasBlock(hash []byte) bool { 247 data, _ := bc.db.Get(hash) 248 return len(data) != 0 249 } 250 251 func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) { 252 block := self.GetBlock(hash) 253 if block == nil { 254 return 255 } 256 257 // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list) 258 for i := uint64(0); i < max; i++ { 259 parentHash := block.Header().ParentHash 260 block = self.GetBlock(parentHash) 261 if block == nil { 262 chainlogger.Infof("GetBlockHashesFromHash Parent UNKNOWN %x\n", parentHash) 263 break 264 } 265 266 chain = append(chain, block.Hash()) 267 if block.Header().Number.Cmp(ethutil.Big0) <= 0 { 268 break 269 } 270 } 271 fmt.Printf("get hash %x (%d)\n", hash, len(chain)) 272 273 return 274 } 275 276 func (self *ChainManager) GetBlock(hash []byte) *types.Block { 277 data, _ := self.db.Get(hash) 278 if len(data) == 0 { 279 return nil 280 } 281 var block types.Block 282 if err := rlp.Decode(bytes.NewReader(data), &block); err != nil { 283 fmt.Println(err) 284 return nil 285 } 286 287 return &block 288 } 289 290 func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) { 291 for i := 0; block != nil && i < length; i++ { 292 uncles = append(uncles, block.Uncles()...) 293 block = self.GetBlock(block.ParentHash()) 294 } 295 296 return 297 } 298 299 func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks []*types.Block) { 300 for i := 0; i < length; i++ { 301 block = self.GetBlock(block.ParentHash()) 302 if block == nil { 303 break 304 } 305 306 blocks = append(blocks, block) 307 } 308 309 return 310 } 311 312 func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { 313 self.mu.RLock() 314 defer self.mu.RUnlock() 315 316 var block *types.Block 317 318 if num <= self.currentBlock.Number().Uint64() { 319 block = self.currentBlock 320 for ; block != nil; block = self.GetBlock(block.Header().ParentHash) { 321 if block.Header().Number.Uint64() == num { 322 break 323 } 324 } 325 } 326 327 return block 328 } 329 330 func (bc *ChainManager) setTotalDifficulty(td *big.Int) { 331 bc.db.Put([]byte("LTD"), td.Bytes()) 332 bc.td = td 333 } 334 335 func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) { 336 parent := self.GetBlock(block.Header().ParentHash) 337 if parent == nil { 338 return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.Header().ParentHash) 339 } 340 341 parentTd := parent.Td 342 343 uncleDiff := new(big.Int) 344 for _, uncle := range block.Uncles() { 345 uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) 346 } 347 348 td := new(big.Int) 349 td = td.Add(parentTd, uncleDiff) 350 td = td.Add(td, block.Header().Difficulty) 351 352 return td, nil 353 } 354 355 func (bc *ChainManager) Stop() { 356 if bc.CurrentBlock != nil { 357 chainlogger.Infoln("Stopped") 358 } 359 } 360 361 func (self *ChainManager) InsertChain(chain types.Blocks) error { 362 self.tsmu.Lock() 363 defer self.tsmu.Unlock() 364 365 for _, block := range chain { 366 td, err := self.processor.Process(block) 367 if err != nil { 368 if IsKnownBlockErr(err) { 369 continue 370 } 371 372 h := block.Header() 373 chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4]) 374 chainlogger.Infoln(block) 375 chainlogger.Infoln(err) 376 return err 377 } 378 block.Td = td 379 380 var chain, split bool 381 self.mu.Lock() 382 { 383 self.write(block) 384 cblock := self.currentBlock 385 if td.Cmp(self.td) > 0 { 386 if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 { 387 chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td) 388 split = true 389 } 390 391 self.setTotalDifficulty(td) 392 self.insert(block) 393 394 chain = true 395 } 396 } 397 self.mu.Unlock() 398 399 if chain { 400 self.eventMux.Post(ChainEvent{block, td}) 401 } 402 403 if split { 404 self.setTransState(state.New(block.Root(), self.db)) 405 self.eventMux.Post(ChainSplitEvent{block}) 406 } 407 } 408 409 return nil 410 } 411 412 // Satisfy state query interface 413 func (self *ChainManager) GetAccount(addr []byte) *state.StateObject { 414 return self.State().GetAccount(addr) 415 }