From a2d5a60418e70ce56112381dffdd121cc678a1b6 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 18 Aug 2015 14:14:45 +0200 Subject: core, core/state: batch-based state sync --- core/state/statedb.go | 86 +++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'core/state/statedb.go') diff --git a/core/state/statedb.go b/core/state/statedb.go index c2bc99564..4233c763b 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -35,7 +35,6 @@ import ( type StateDB struct { db ethdb.Database trie *trie.SecureTrie - root common.Hash stateObjects map[string]*StateObject @@ -56,7 +55,6 @@ func New(root common.Hash, db ethdb.Database) *StateDB { glog.Errorf("can't create state trie with root %x: %v", root[:], err) } return &StateDB{ - root: root, db: db, trie: tr, stateObjects: make(map[string]*StateObject), @@ -204,7 +202,6 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) { if len(stateObject.CodeHash()) > 0 { self.db.Put(stateObject.CodeHash(), stateObject.code) } - addr := stateObject.Address() self.trie.Update(addr[:], stateObject.RlpEncode()) } @@ -215,6 +212,7 @@ func (self *StateDB) DeleteStateObject(stateObject *StateObject) { addr := stateObject.Address() self.trie.Delete(addr[:]) + //delete(self.stateObjects, addr.Str()) } // Retrieve a state object given my the address. Nil if not found @@ -311,65 +309,67 @@ func (self *StateDB) Set(state *StateDB) { self.logSize = state.logSize } -func (s *StateDB) Root() common.Hash { - return s.trie.Hash() -} - -// Syncs the trie and all siblings -func (s *StateDB) Sync() { - // Sync all nested states +// IntermediateRoot computes the current root hash of the state trie. +// It is called in between transactions to get the root hash that +// goes into transaction receipts. +func (s *StateDB) IntermediateRoot() common.Hash { + s.refund = new(big.Int) for _, stateObject := range s.stateObjects { - stateObject.trie.Commit() - } - - s.trie.Commit() - - s.Empty() -} - -func (self *StateDB) Empty() { - self.stateObjects = make(map[string]*StateObject) - self.refund = new(big.Int) -} - -func (self *StateDB) Refunds() *big.Int { - return self.refund -} - -// SyncIntermediate updates the intermediate state and all mid steps -func (self *StateDB) SyncIntermediate() { - self.refund = new(big.Int) - - for _, stateObject := range self.stateObjects { if stateObject.dirty { if stateObject.remove { - self.DeleteStateObject(stateObject) + s.DeleteStateObject(stateObject) } else { stateObject.Update() - - self.UpdateStateObject(stateObject) + s.UpdateStateObject(stateObject) } stateObject.dirty = false } } + return s.trie.Hash() } -// SyncObjects syncs the changed objects to the trie -func (self *StateDB) SyncObjects() { - self.trie, _ = trie.NewSecure(self.root, self.db) +// Commit commits all state changes to the database. +func (s *StateDB) Commit() (root common.Hash, err error) { + return s.commit(s.db) +} + +// CommitBatch commits all state changes to a write batch but does not +// execute the batch. It is used to validate state changes against +// the root hash stored in a block. +func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) { + batch = s.db.NewBatch() + root, _ = s.commit(batch) + return root, batch +} - self.refund = new(big.Int) +func (s *StateDB) commit(db trie.DatabaseWriter) (common.Hash, error) { + s.refund = new(big.Int) - for _, stateObject := range self.stateObjects { + for _, stateObject := range s.stateObjects { if stateObject.remove { - self.DeleteStateObject(stateObject) + // If the object has been removed, don't bother syncing it + // and just mark it for deletion in the trie. + s.DeleteStateObject(stateObject) } else { + // Write any storage changes in the state object to its trie. stateObject.Update() - - self.UpdateStateObject(stateObject) + // Commit the trie of the object to the batch. + // This updates the trie root internally, so + // getting the root hash of the storage trie + // through UpdateStateObject is fast. + if _, err := stateObject.trie.CommitTo(db); err != nil { + return common.Hash{}, err + } + // Update the object in the account trie. + s.UpdateStateObject(stateObject) } stateObject.dirty = false } + return s.trie.CommitTo(db) +} + +func (self *StateDB) Refunds() *big.Int { + return self.refund } // Debug stuff -- cgit v1.2.3