mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 14:16:44 +00:00
core, core/state: improved update loops
This commit is contained in:
parent
91ecef628a
commit
08aeea24ba
4 changed files with 81 additions and 26 deletions
|
|
@ -205,6 +205,20 @@ 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("Fast block: #%d [%x…] TD=%v", self.currentFastBlock.Number(), self.currentFastBlock.Hash().Bytes()[:4], fastTd)
|
||||
|
||||
/*
|
||||
st, err := state.New(currentHeader.Root, self.chainDb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
glog.V(logger.Info).Infoln("caching state accounts...")
|
||||
tstart := time.Now()
|
||||
if err := st.LoadAll(); err != nil {
|
||||
return fmt.Errorf("core: could not pre-load account data: %v", err)
|
||||
}
|
||||
self.canonState = st
|
||||
glog.V(logger.Info).Infoln("cached", len(st.StateObjects), "in", time.Since(tstart))
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
|
|
@ -53,6 +54,19 @@ func New(root common.Hash, db ethdb.Database) (*State, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (s *State) LoadAll() error {
|
||||
it := s.Trie.Iterator()
|
||||
for it.Next() {
|
||||
addr := s.Trie.GetKey(it.Key)
|
||||
obj, err := DecodeObjectLazily(common.BytesToAddress(addr), s.Db, it.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.StateObjects[common.BytesToAddress(addr)] = obj
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *State) PrepareIntermediate(txHash, blockHash common.Hash, txIdx int) {
|
||||
if s.parent != nil {
|
||||
s.parent.MarkedTransition = true
|
||||
|
|
@ -79,6 +93,7 @@ func (s *State) Read(address common.Address) (object *StateObject, inCache bool)
|
|||
if stateObject.deleted {
|
||||
return nil, false
|
||||
}
|
||||
s.loadStateObject(stateObject)
|
||||
return stateObject, inCache
|
||||
}
|
||||
|
||||
|
|
@ -96,6 +111,20 @@ func (s *State) Read(address common.Address) (object *StateObject, inCache bool)
|
|||
return stateObject, false
|
||||
}
|
||||
|
||||
func (s *State) loadStateObject(stateObject *StateObject) {
|
||||
if stateObject.trie == nil {
|
||||
var err error
|
||||
if stateObject.trie, err = trie.NewSecure(stateObject.root, s.Db); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !bytes.Equal(stateObject.codeHash, emptyCodeHash) {
|
||||
if stateObject.code, err = s.Db.Get(stateObject.codeHash); err != nil {
|
||||
panic(fmt.Sprintf("can't get code for hash %x: %v", stateObject.codeHash, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) GetOrNewStateObject(address common.Address) *StateObject {
|
||||
stateObject, inCache := s.Read(address)
|
||||
if stateObject != nil {
|
||||
|
|
@ -150,6 +179,7 @@ func (s *State) CreateStateObject(address common.Address) *StateObject {
|
|||
stateObject.SetNonce(StartingNonce)
|
||||
|
||||
s.StateObjects[address] = stateObject
|
||||
s.localStateObjects[address] = true
|
||||
|
||||
// If it existed set the balance to the new account
|
||||
if so != nil {
|
||||
|
|
@ -247,8 +277,15 @@ func (s *State) SetState(address common.Address, stateAddress common.Hash, value
|
|||
func (s *State) Delete(address common.Address) bool {
|
||||
stateObject := s.GetStateObject(address)
|
||||
if stateObject != nil {
|
||||
stateObject.MarkForDeletion()
|
||||
if !s.localStateObjects[address] {
|
||||
stateObject = stateObject.Copy()
|
||||
s.StateObjects[address] = stateObject
|
||||
s.localStateObjects[address] = true
|
||||
}
|
||||
|
||||
stateObject.remove = true
|
||||
stateObject.balance = new(big.Int)
|
||||
stateObject.dirty = true
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
@ -311,6 +348,8 @@ func (s *State) DeleteStateObject(stateObject *StateObject) {
|
|||
}
|
||||
|
||||
func (s *State) UpdateStateObject(stateObject *StateObject) {
|
||||
s.loadStateObject(stateObject)
|
||||
|
||||
addr := stateObject.Address()
|
||||
data, err := rlp.EncodeToBytes(stateObject)
|
||||
if err != nil {
|
||||
|
|
@ -320,7 +359,6 @@ func (s *State) UpdateStateObject(stateObject *StateObject) {
|
|||
}
|
||||
|
||||
func (s *State) Reset(root common.Hash) error {
|
||||
fmt.Println("reset")
|
||||
var (
|
||||
err error
|
||||
tr = s.Trie
|
||||
|
|
@ -390,20 +428,10 @@ func (s *State) Set(o *State) {
|
|||
|
||||
// Flatten flattens the state in to a single new state, including all changes of all ancestors.
|
||||
func Flatten(s *State) *State {
|
||||
// first commit the parent so we can overwrite changes
|
||||
// later.
|
||||
var flattenedState *State
|
||||
if s.parent != nil {
|
||||
flattenedState = Flatten(s.parent)
|
||||
} else {
|
||||
flattenedState = &State{
|
||||
Db: s.Db,
|
||||
Trie: s.Trie,
|
||||
refund: new(big.Int),
|
||||
StateObjects: make(map[common.Address]*StateObject),
|
||||
ownedStateObjects: make(map[common.Address]bool),
|
||||
}
|
||||
if s.parent == nil {
|
||||
return s
|
||||
}
|
||||
flattenedState := Flatten(s.parent)
|
||||
|
||||
for address, object := range s.StateObjects {
|
||||
flattenedState.StateObjects[address] = object
|
||||
|
|
@ -425,7 +453,8 @@ func (s *State) String() string {
|
|||
func IntermediateRoot(state *State) common.Hash {
|
||||
s := Flatten(state)
|
||||
|
||||
for _, stateObject := range s.StateObjects {
|
||||
for address, _ := range s.localStateObjects {
|
||||
stateObject := s.StateObjects[address]
|
||||
if stateObject.dirty {
|
||||
if stateObject.remove {
|
||||
s.DeleteStateObject(stateObject)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ type StateObject struct {
|
|||
remove bool
|
||||
deleted bool
|
||||
dirty bool
|
||||
written bool
|
||||
|
||||
root common.Hash
|
||||
}
|
||||
|
||||
func NewStateObject(address common.Address, db trie.Database) *StateObject {
|
||||
|
|
@ -99,7 +100,6 @@ func NewStateObject(address common.Address, db trie.Database) *StateObject {
|
|||
func (self *StateObject) MarkForDeletion() {
|
||||
self.remove = true
|
||||
self.dirty = true
|
||||
self.written = false
|
||||
|
||||
if glog.V(logger.Core) {
|
||||
glog.Infof("%x: #%d %v X\n", self.Address(), self.nonce, self.balance)
|
||||
|
|
@ -140,7 +140,6 @@ func (self *StateObject) GetState(key common.Hash) common.Hash {
|
|||
func (self *StateObject) SetState(key, value common.Hash) {
|
||||
self.storage[key] = value
|
||||
self.dirty = true
|
||||
self.written = false
|
||||
}
|
||||
|
||||
// Update updates the current cached storage to the trie
|
||||
|
|
@ -160,7 +159,6 @@ func (c *StateObject) AddBalance(amount *big.Int) {
|
|||
if glog.V(logger.Core) {
|
||||
glog.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount)
|
||||
}
|
||||
c.written = false
|
||||
}
|
||||
|
||||
func (c *StateObject) SubBalance(amount *big.Int) {
|
||||
|
|
@ -169,13 +167,11 @@ func (c *StateObject) SubBalance(amount *big.Int) {
|
|||
if glog.V(logger.Core) {
|
||||
glog.Infof("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount)
|
||||
}
|
||||
c.written = false
|
||||
}
|
||||
|
||||
func (c *StateObject) SetBalance(amount *big.Int) {
|
||||
c.balance = amount
|
||||
c.dirty = true
|
||||
c.written = false
|
||||
}
|
||||
|
||||
func (c *StateObject) St() Storage {
|
||||
|
|
@ -229,13 +225,11 @@ func (self *StateObject) SetCode(code []byte) {
|
|||
self.code = code
|
||||
self.codeHash = crypto.Keccak256(code)
|
||||
self.dirty = true
|
||||
self.written = false
|
||||
}
|
||||
|
||||
func (self *StateObject) SetNonce(nonce uint64) {
|
||||
self.nonce = nonce
|
||||
self.dirty = true
|
||||
self.written = false
|
||||
}
|
||||
|
||||
func (self *StateObject) Nonce() uint64 {
|
||||
|
|
@ -300,3 +294,20 @@ func DecodeObject(address common.Address, db trie.Database, data []byte) (*State
|
|||
obj.codeHash = ext.CodeHash
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// DecodeObjectLazily decodes an RLP-encoded state object.
|
||||
func DecodeObjectLazily(address common.Address, db trie.Database, data []byte) (*StateObject, error) {
|
||||
var (
|
||||
obj = &StateObject{address: address, db: db, storage: make(Storage)}
|
||||
ext extStateObject
|
||||
err error
|
||||
)
|
||||
if err = rlp.DecodeBytes(data, &ext); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obj.root = ext.Root
|
||||
obj.nonce = ext.Nonce
|
||||
obj.balance = ext.Balance
|
||||
obj.codeHash = ext.CodeHash
|
||||
return obj, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ func stateCommit(state *State, db trie.DatabaseWriter) (common.Hash, error) {
|
|||
// and just mark it for deletion in the trie.
|
||||
stateObject.deleted = true
|
||||
state.Trie.Delete(stateObject.Address().Bytes()[:])
|
||||
} else if !stateObject.written {
|
||||
// Delete the object from the cache.
|
||||
// delete(state.StateObjects, address)
|
||||
} else {
|
||||
// Write any contract code associated with the state object
|
||||
if len(stateObject.code) > 0 {
|
||||
if err := db.Put(stateObject.codeHash, stateObject.code); err != nil {
|
||||
|
|
@ -60,7 +62,6 @@ func stateCommit(state *State, db trie.DatabaseWriter) (common.Hash, error) {
|
|||
|
||||
}
|
||||
stateObject.dirty = false
|
||||
stateObject.written = true
|
||||
}
|
||||
return state.Trie.CommitTo(db)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue