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("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)
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
|
@ -53,6 +54,19 @@ func New(root common.Hash, db ethdb.Database) (*State, error) {
|
||||||
}, nil
|
}, 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) {
|
func (s *State) PrepareIntermediate(txHash, blockHash common.Hash, txIdx int) {
|
||||||
if s.parent != nil {
|
if s.parent != nil {
|
||||||
s.parent.MarkedTransition = true
|
s.parent.MarkedTransition = true
|
||||||
|
|
@ -79,6 +93,7 @@ func (s *State) Read(address common.Address) (object *StateObject, inCache bool)
|
||||||
if stateObject.deleted {
|
if stateObject.deleted {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
s.loadStateObject(stateObject)
|
||||||
return stateObject, inCache
|
return stateObject, inCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,6 +111,20 @@ func (s *State) Read(address common.Address) (object *StateObject, inCache bool)
|
||||||
return stateObject, false
|
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 {
|
func (s *State) GetOrNewStateObject(address common.Address) *StateObject {
|
||||||
stateObject, inCache := s.Read(address)
|
stateObject, inCache := s.Read(address)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
|
@ -150,6 +179,7 @@ func (s *State) CreateStateObject(address common.Address) *StateObject {
|
||||||
stateObject.SetNonce(StartingNonce)
|
stateObject.SetNonce(StartingNonce)
|
||||||
|
|
||||||
s.StateObjects[address] = stateObject
|
s.StateObjects[address] = stateObject
|
||||||
|
s.localStateObjects[address] = true
|
||||||
|
|
||||||
// If it existed set the balance to the new account
|
// If it existed set the balance to the new account
|
||||||
if so != nil {
|
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 {
|
func (s *State) Delete(address common.Address) bool {
|
||||||
stateObject := s.GetStateObject(address)
|
stateObject := s.GetStateObject(address)
|
||||||
if stateObject != nil {
|
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.balance = new(big.Int)
|
||||||
|
stateObject.dirty = true
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -311,6 +348,8 @@ func (s *State) DeleteStateObject(stateObject *StateObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) UpdateStateObject(stateObject *StateObject) {
|
func (s *State) UpdateStateObject(stateObject *StateObject) {
|
||||||
|
s.loadStateObject(stateObject)
|
||||||
|
|
||||||
addr := stateObject.Address()
|
addr := stateObject.Address()
|
||||||
data, err := rlp.EncodeToBytes(stateObject)
|
data, err := rlp.EncodeToBytes(stateObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -320,7 +359,6 @@ func (s *State) UpdateStateObject(stateObject *StateObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) Reset(root common.Hash) error {
|
func (s *State) Reset(root common.Hash) error {
|
||||||
fmt.Println("reset")
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
tr = s.Trie
|
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.
|
// Flatten flattens the state in to a single new state, including all changes of all ancestors.
|
||||||
func Flatten(s *State) *State {
|
func Flatten(s *State) *State {
|
||||||
// first commit the parent so we can overwrite changes
|
if s.parent == nil {
|
||||||
// later.
|
return s
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
flattenedState := Flatten(s.parent)
|
||||||
|
|
||||||
for address, object := range s.StateObjects {
|
for address, object := range s.StateObjects {
|
||||||
flattenedState.StateObjects[address] = object
|
flattenedState.StateObjects[address] = object
|
||||||
|
|
@ -425,7 +453,8 @@ func (s *State) String() string {
|
||||||
func IntermediateRoot(state *State) common.Hash {
|
func IntermediateRoot(state *State) common.Hash {
|
||||||
s := Flatten(state)
|
s := Flatten(state)
|
||||||
|
|
||||||
for _, stateObject := range s.StateObjects {
|
for address, _ := range s.localStateObjects {
|
||||||
|
stateObject := s.StateObjects[address]
|
||||||
if stateObject.dirty {
|
if stateObject.dirty {
|
||||||
if stateObject.remove {
|
if stateObject.remove {
|
||||||
s.DeleteStateObject(stateObject)
|
s.DeleteStateObject(stateObject)
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,8 @@ type StateObject struct {
|
||||||
remove bool
|
remove bool
|
||||||
deleted bool
|
deleted bool
|
||||||
dirty bool
|
dirty bool
|
||||||
written bool
|
|
||||||
|
root common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateObject(address common.Address, db trie.Database) *StateObject {
|
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() {
|
func (self *StateObject) MarkForDeletion() {
|
||||||
self.remove = true
|
self.remove = true
|
||||||
self.dirty = true
|
self.dirty = true
|
||||||
self.written = false
|
|
||||||
|
|
||||||
if glog.V(logger.Core) {
|
if glog.V(logger.Core) {
|
||||||
glog.Infof("%x: #%d %v X\n", self.Address(), self.nonce, self.balance)
|
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) {
|
func (self *StateObject) SetState(key, value common.Hash) {
|
||||||
self.storage[key] = value
|
self.storage[key] = value
|
||||||
self.dirty = true
|
self.dirty = true
|
||||||
self.written = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the current cached storage to the trie
|
// 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) {
|
if glog.V(logger.Core) {
|
||||||
glog.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount)
|
glog.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount)
|
||||||
}
|
}
|
||||||
c.written = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) SubBalance(amount *big.Int) {
|
func (c *StateObject) SubBalance(amount *big.Int) {
|
||||||
|
|
@ -169,13 +167,11 @@ func (c *StateObject) SubBalance(amount *big.Int) {
|
||||||
if glog.V(logger.Core) {
|
if glog.V(logger.Core) {
|
||||||
glog.Infof("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount)
|
glog.Infof("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount)
|
||||||
}
|
}
|
||||||
c.written = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) SetBalance(amount *big.Int) {
|
func (c *StateObject) SetBalance(amount *big.Int) {
|
||||||
c.balance = amount
|
c.balance = amount
|
||||||
c.dirty = true
|
c.dirty = true
|
||||||
c.written = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) St() Storage {
|
func (c *StateObject) St() Storage {
|
||||||
|
|
@ -229,13 +225,11 @@ func (self *StateObject) SetCode(code []byte) {
|
||||||
self.code = code
|
self.code = code
|
||||||
self.codeHash = crypto.Keccak256(code)
|
self.codeHash = crypto.Keccak256(code)
|
||||||
self.dirty = true
|
self.dirty = true
|
||||||
self.written = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) SetNonce(nonce uint64) {
|
func (self *StateObject) SetNonce(nonce uint64) {
|
||||||
self.nonce = nonce
|
self.nonce = nonce
|
||||||
self.dirty = true
|
self.dirty = true
|
||||||
self.written = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) Nonce() uint64 {
|
func (self *StateObject) Nonce() uint64 {
|
||||||
|
|
@ -300,3 +294,20 @@ func DecodeObject(address common.Address, db trie.Database, data []byte) (*State
|
||||||
obj.codeHash = ext.CodeHash
|
obj.codeHash = ext.CodeHash
|
||||||
return obj, nil
|
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.
|
// and just mark it for deletion in the trie.
|
||||||
stateObject.deleted = true
|
stateObject.deleted = true
|
||||||
state.Trie.Delete(stateObject.Address().Bytes()[:])
|
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
|
// Write any contract code associated with the state object
|
||||||
if len(stateObject.code) > 0 {
|
if len(stateObject.code) > 0 {
|
||||||
if err := db.Put(stateObject.codeHash, stateObject.code); err != nil {
|
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.dirty = false
|
||||||
stateObject.written = true
|
|
||||||
}
|
}
|
||||||
return state.Trie.CommitTo(db)
|
return state.Trie.CommitTo(db)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue