aboutsummaryrefslogtreecommitdiffstats
path: root/core/chain_manager.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/chain_manager.go')
-rw-r--r--core/chain_manager.go104
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)
}
+*/