core, core/state: WIP cache all teh things

This commit is contained in:
Jeffrey Wilcke 2016-09-23 02:24:06 +02:00
parent 08aeea24ba
commit d010b982ae
6 changed files with 46 additions and 29 deletions

View file

@ -136,6 +136,7 @@ participating.
utils.OlympicFlag, utils.OlympicFlag,
utils.FastSyncFlag, utils.FastSyncFlag,
utils.CacheFlag, utils.CacheFlag,
utils.StateCacheFlag,
utils.LightKDFFlag, utils.LightKDFFlag,
utils.JSpathFlag, utils.JSpathFlag,
utils.ListenPortFlag, utils.ListenPortFlag,

View file

@ -74,6 +74,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.FastSyncFlag, utils.FastSyncFlag,
utils.LightKDFFlag, utils.LightKDFFlag,
utils.CacheFlag, utils.CacheFlag,
utils.StateCacheFlag,
}, },
}, },
{ {

View file

@ -144,6 +144,10 @@ var (
Usage: "Megabytes of memory allocated to internal caching (min 16MB / database forced)", Usage: "Megabytes of memory allocated to internal caching (min 16MB / database forced)",
Value: 128, Value: 128,
} }
StateCacheFlag = cli.BoolFlag{
Name: "statecache",
Usage: "Caches the last known state before syncing with the network. Uses significantly more memory.",
}
FastSyncFlag = cli.BoolFlag{ FastSyncFlag = cli.BoolFlag{
Name: "fast", Name: "fast",
Usage: "Enable fast syncing through state downloads", Usage: "Enable fast syncing through state downloads",

View file

@ -107,6 +107,8 @@ type BlockChain struct {
pow pow.PoW pow pow.PoW
processor Processor // block processor interface processor Processor // block processor interface
validator Validator // block and state validator interface validator Validator // block and state validator interface
canonState *state.State
} }
// NewBlockChain returns a fully initialised block chain using information // NewBlockChain returns a fully initialised block chain using information
@ -205,19 +207,23 @@ func (self *BlockChain) loadLastState() error {
glog.V(logger.Info).Infof("Last block: #%d [%x…] TD=%v", self.currentBlock.Number(), self.currentBlock.Hash().Bytes()[:4], blockTd) glog.V(logger.Info).Infof("Last block: #%d [%x…] TD=%v", self.currentBlock.Number(), self.currentBlock.Hash().Bytes()[:4], blockTd)
glog.V(logger.Info).Infof("Fast block: #%d [%x…] TD=%v", self.currentFastBlock.Number(), self.currentFastBlock.Hash().Bytes()[:4], fastTd) glog.V(logger.Info).Infof("Fast block: #%d [%x…] TD=%v", self.currentFastBlock.Number(), self.currentFastBlock.Hash().Bytes()[:4], fastTd)
/* return nil
st, err := state.New(currentHeader.Root, self.chainDb) }
if err != nil {
return err func (bc *BlockChain) PreloadState() error {
} currentHeader := bc.currentBlock.Header()
glog.V(logger.Info).Infoln("caching state accounts...")
tstart := time.Now() st, err := state.New(currentHeader.Root, bc.chainDb)
if err := st.LoadAll(); err != nil { if err != nil {
return fmt.Errorf("core: could not pre-load account data: %v", err) return err
} }
self.canonState = st glog.V(logger.Info).Infoln("caching state accounts...")
glog.V(logger.Info).Infoln("cached", len(st.StateObjects), "in", time.Since(tstart)) tstart := time.Now()
*/ if err := st.LoadAll(); err != nil {
return fmt.Errorf("core: could not pre-load account data: %v", err)
}
bc.canonState = st
glog.V(logger.Info).Infoln("cached", len(st.StateObjects), "in", time.Since(tstart))
return nil return nil
} }
@ -905,12 +911,17 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
return i, err return i, err
} }
parent := self.GetBlock(block.ParentHash(), block.NumberU64()-1)
// Create a new statedb using the parent block and report an // Create a new statedb using the parent block and report an
// error if it fails. // error if it fails.
if st == nil { if st == nil {
st, err = state.New(self.GetBlock(block.ParentHash(), block.NumberU64()-1).Root(), self.chainDb) if self.canonState != nil && parent.Root() == common.BytesToHash(self.canonState.Trie.Root()) {
st = self.canonState
} else {
st, err = state.New(parent.Root(), self.chainDb)
}
} else { } else {
err = st.Reset(chain[i-1].Root()) err = st.Reset(parent.Root())
} }
if err != nil { if err != nil {
reportBlock(block, err) reportBlock(block, err)
@ -928,10 +939,8 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
reportBlock(block, err) reportBlock(block, err)
return i, err return i, err
} }
tstart := time.Now()
// flatten the state before committing. // flatten the state before committing.
st = state.Flatten(st) st = state.Flatten(st)
fmt.Println("reduce took", time.Since(tstart))
// Write state changes to database // Write state changes to database
_, err = state.Commit(st) _, err = state.Commit(st)
if err != nil { if err != nil {
@ -972,6 +981,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil { if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil {
return i, err return i, err
} }
self.canonState = st
case SideStatTy: case SideStatTy:
if glog.V(logger.Detail) { if glog.V(logger.Detail) {
glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart)) glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))

View file

@ -23,7 +23,7 @@ type State struct {
parent *State parent *State
StateObjects map[common.Address]*StateObject StateObjects map[common.Address]*StateObject
ownedStateObjects map[common.Address]bool localStateObjects map[common.Address]bool
refund *big.Int refund *big.Int
logIdx uint logIdx uint
@ -49,7 +49,7 @@ func New(root common.Hash, db ethdb.Database) (*State, error) {
Db: db, Db: db,
Trie: tr, Trie: tr,
StateObjects: make(map[common.Address]*StateObject), StateObjects: make(map[common.Address]*StateObject),
ownedStateObjects: make(map[common.Address]bool), localStateObjects: make(map[common.Address]bool),
refund: new(big.Int), refund: new(big.Int),
}, nil }, nil
} }
@ -128,10 +128,10 @@ func (s *State) loadStateObject(stateObject *StateObject) {
func (s *State) GetOrNewStateObject(address common.Address) *StateObject { func (s *State) GetOrNewStateObject(address common.Address) *StateObject {
stateObject, inCache := s.Read(address) stateObject, inCache := s.Read(address)
if stateObject != nil { if stateObject != nil {
if !inCache || !s.ownedStateObjects[address] { if !inCache || !s.localStateObjects[address] {
stateObject = stateObject.Copy() stateObject = stateObject.Copy()
s.StateObjects[address] = stateObject s.StateObjects[address] = stateObject
s.ownedStateObjects[address] = true s.localStateObjects[address] = true
} }
return stateObject return stateObject
} }
@ -141,7 +141,7 @@ func (s *State) GetOrNewStateObject(address common.Address) *StateObject {
stateObject.SetNonce(StartingNonce) stateObject.SetNonce(StartingNonce)
s.StateObjects[address] = stateObject s.StateObjects[address] = stateObject
s.ownedStateObjects[address] = true s.localStateObjects[address] = true
} }
return stateObject return stateObject
} }
@ -372,9 +372,8 @@ func (s *State) Reset(root common.Hash) error {
Db: s.Db, Db: s.Db,
Trie: tr, Trie: tr,
StateObjects: s.StateObjects, StateObjects: s.StateObjects,
ownedStateObjects: s.ownedStateObjects, localStateObjects: make(map[common.Address]bool),
//StateObjects: make(map[common.Address]*StateObject), //StateObjects: make(map[common.Address]*StateObject),
//ownedStateObjects: make(map[common.Address]bool),
refund: new(big.Int), refund: new(big.Int),
} }
return nil return nil
@ -415,7 +414,7 @@ func Fork(parent *State) *State {
parent: parent, parent: parent,
StateObjects: make(map[common.Address]*StateObject), StateObjects: make(map[common.Address]*StateObject),
ownedStateObjects: make(map[common.Address]bool), localStateObjects: make(map[common.Address]bool),
refund: new(big.Int), refund: new(big.Int),
logIdx: parent.logIdx, logIdx: parent.logIdx,
logs: nil, logs: nil,
@ -435,8 +434,8 @@ func Flatten(s *State) *State {
for address, object := range s.StateObjects { for address, object := range s.StateObjects {
flattenedState.StateObjects[address] = object flattenedState.StateObjects[address] = object
if s.ownedStateObjects[address] { if s.localStateObjects[address] {
flattenedState.ownedStateObjects[address] = true flattenedState.localStateObjects[address] = true
} }
} }
@ -447,7 +446,7 @@ func Flatten(s *State) *State {
} }
func (s *State) String() string { func (s *State) String() string {
return fmt.Sprintf("objects: %d owned: %d", len(s.StateObjects), len(s.ownedStateObjects)) return fmt.Sprintf("objects: %d owned: %d", len(s.StateObjects), len(s.localStateObjects))
} }
func IntermediateRoot(state *State) common.Hash { func IntermediateRoot(state *State) common.Hash {

View file

@ -27,7 +27,9 @@ func CommitBatch(state *State) (common.Hash, ethdb.Batch) {
func stateCommit(state *State, db trie.DatabaseWriter) (common.Hash, error) { func stateCommit(state *State, db trie.DatabaseWriter) (common.Hash, error) {
// make sure the state is flattened before committing // make sure the state is flattened before committing
state = Flatten(state) state = Flatten(state)
for _, stateObject := range state.StateObjects { for address, _ := range state.localStateObjects {
stateObject := state.StateObjects[address]
//for _, stateObject := range state.StateObjects {
if stateObject.remove { if stateObject.remove {
// If the object has been removed, don't bother syncing it // If the object has been removed, don't bother syncing it
// and just mark it for deletion in the trie. // and just mark it for deletion in the trie.