diff options
Diffstat (limited to 'core/chain_manager.go')
-rw-r--r-- | core/chain_manager.go | 104 |
1 files changed, 62 insertions, 42 deletions
diff --git a/core/chain_manager.go b/core/chain_manager.go index 64ea8957d..1bc8edea6 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -3,6 +3,7 @@ package core import ( "bytes" "fmt" + "io" "math/big" "sync" @@ -22,6 +23,8 @@ var ( blockNumPre = []byte("block-num-") ) +const blockCacheLimit = 10000 + type StateQuery interface { GetAccount(addr []byte) *state.StateObject } @@ -37,8 +40,8 @@ func CalcDifficulty(block, parent *types.Header) *big.Int { diff.Sub(parent.Difficulty, adjust) } - if diff.Cmp(GenesisDiff) < 0 { - return GenesisDiff + if diff.Cmp(min) < 0 { + return min } return diff @@ -86,20 +89,30 @@ type ChainManager struct { tsmu sync.RWMutex td *big.Int currentBlock *types.Block - lastBlockHash []byte + lastBlockHash common.Hash transState *state.StateDB txState *state.ManagedState + cache *BlockCache + quit chan struct{} } func NewChainManager(blockDb, stateDb common.Database, mux *event.TypeMux) *ChainManager { - bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{})} + bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{}), cache: NewBlockCache(blockCacheLimit)} bc.setLastBlock() bc.transState = bc.State().Copy() // Take ownership of this particular state bc.txState = state.ManageState(bc.State().Copy()) + + // load in last `blockCacheLimit` - 1 blocks. Last block is the current. + ancestors := bc.GetAncestors(bc.currentBlock, blockCacheLimit-1) + ancestors = append(ancestors, bc.currentBlock) + for _, block := range ancestors { + bc.cache.Push(block) + } + go bc.update() return bc @@ -112,7 +125,7 @@ func (self *ChainManager) Td() *big.Int { return self.td } -func (self *ChainManager) LastBlockHash() []byte { +func (self *ChainManager) LastBlockHash() common.Hash { self.mu.RLock() defer self.mu.RUnlock() @@ -126,7 +139,7 @@ func (self *ChainManager) CurrentBlock() *types.Block { return self.currentBlock } -func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { +func (self *ChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) { self.mu.RLock() defer self.mu.RUnlock() @@ -168,7 +181,7 @@ func (self *ChainManager) setTransState(statedb *state.StateDB) { func (bc *ChainManager) setLastBlock() { data, _ := bc.blockDb.Get([]byte("LastBlock")) if len(data) != 0 { - block := bc.GetBlock(data) + block := bc.GetBlock(common.BytesToHash(data)) bc.currentBlock = block bc.lastBlockHash = block.Hash() @@ -182,12 +195,14 @@ func (bc *ChainManager) setLastBlock() { } // Block creation & chain handling -func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { +func (bc *ChainManager) NewBlock(coinbase common.Address) *types.Block { bc.mu.RLock() defer bc.mu.RUnlock() - var root []byte - parentHash := ZeroHash256 + var ( + root common.Hash + parentHash common.Hash + ) if bc.currentBlock != nil { root = bc.currentBlock.Header().Root @@ -234,7 +249,7 @@ func (bc *ChainManager) Reset() { } func (bc *ChainManager) removeBlock(block *types.Block) { - bc.blockDb.Delete(append(blockHashPre, block.Hash()...)) + bc.blockDb.Delete(append(blockHashPre, block.Hash().Bytes()...)) } func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { @@ -252,35 +267,34 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { bc.currentBlock = bc.genesisBlock } -func (self *ChainManager) Export() []byte { +// Export writes the active chain to the given writer. +func (self *ChainManager) Export(w io.Writer) error { self.mu.RLock() defer self.mu.RUnlock() - chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number) - - blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1) for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) { - blocks[block.NumberU64()] = block + if err := block.EncodeRLP(w); err != nil { + return err + } } - - return common.Encode(blocks) + return nil } func (bc *ChainManager) insert(block *types.Block) { - //encodedBlock := common.Encode(block) - bc.blockDb.Put([]byte("LastBlock"), block.Hash()) + bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes()) bc.currentBlock = block bc.lastBlockHash = block.Hash() key := append(blockNumPre, block.Number().Bytes()...) - bc.blockDb.Put(key, bc.lastBlockHash) + bc.blockDb.Put(key, bc.lastBlockHash.Bytes()) + // Push block to cache + bc.cache.Push(block) } func (bc *ChainManager) write(block *types.Block) { - encodedBlock := common.Encode(block.RlpDataForStorage()) - - key := append(blockHashPre, block.Hash()...) - bc.blockDb.Put(key, encodedBlock) + enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block)) + key := append(blockHashPre, block.Hash().Bytes()...) + bc.blockDb.Put(key, enc) } // Accessors @@ -289,12 +303,12 @@ func (bc *ChainManager) Genesis() *types.Block { } // Block fetching methods -func (bc *ChainManager) HasBlock(hash []byte) bool { - data, _ := bc.blockDb.Get(append(blockHashPre, hash...)) +func (bc *ChainManager) HasBlock(hash common.Hash) bool { + data, _ := bc.blockDb.Get(append(blockHashPre, hash[:]...)) return len(data) != 0 } -func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) { +func (self *ChainManager) GetBlockHashesFromHash(hash common.Hash, max uint64) (chain []common.Hash) { block := self.GetBlock(hash) if block == nil { return @@ -317,18 +331,21 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain return } -func (self *ChainManager) GetBlock(hash []byte) *types.Block { - data, _ := self.blockDb.Get(append(blockHashPre, hash...)) +func (self *ChainManager) GetBlock(hash common.Hash) *types.Block { + if block := self.cache.Get(hash); block != nil { + return block + } + + data, _ := self.blockDb.Get(append(blockHashPre, hash[:]...)) if len(data) == 0 { return nil } - var block types.Block + var block types.StorageBlock if err := rlp.Decode(bytes.NewReader(data), &block); err != nil { - fmt.Println(err) + chainlogger.Errorf("invalid block RLP for hash %x: %v", hash, err) return nil } - - return &block + return (*types.Block)(&block) } func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { @@ -340,7 +357,7 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { return nil } - return self.GetBlock(key) + return self.GetBlock(common.BytesToHash(key)) } func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) { @@ -418,7 +435,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } h := block.Header() - chainlogger.Infof("INVALID block #%v (%x)\n", h.Number, h.Hash()[:4]) + chainlogger.Infof("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes()[:4]) chainlogger.Infoln(err) chainlogger.Debugln(block) return err @@ -435,7 +452,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { // At this point it's possible that a different chain (fork) becomes the new canonical chain. if td.Cmp(self.td) > 0 { if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, common.Big1)) < 0 { - 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) + chash := cblock.Hash() + hash := block.Hash() + chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, hash[:4], td, cblock.Header().Number, chash[:4], self.td) queue[i] = ChainSplitEvent{block, logs} queueEvent.splitCount++ @@ -445,10 +464,10 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.insert(block) jsonlogger.LogJson(&logger.EthChainNewHead{ - BlockHash: common.Bytes2Hex(block.Hash()), + BlockHash: block.Hash().Hex(), BlockNumber: block.Number(), - ChainHeadHash: common.Bytes2Hex(cblock.Hash()), - BlockPrevHash: common.Bytes2Hex(block.ParentHash()), + ChainHeadHash: cblock.Hash().Hex(), + BlockPrevHash: block.ParentHash().Hex(), }) self.setTransState(state.New(block.Root(), self.stateDb)) @@ -465,7 +484,6 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } - // XXX put this in a goroutine? go self.eventMux.Post(queueEvent) return nil @@ -505,7 +523,9 @@ out: } } +/* // Satisfy state query interface -func (self *ChainManager) GetAccount(addr []byte) *state.StateObject { +func (self *ChainManager) GetAccount(addr common.Hash) *state.StateObject { return self.State().GetAccount(addr) } +*/ |