diff options
author | Jeffrey Wilcke <jeffrey@ethereum.org> | 2016-10-20 19:36:29 +0800 |
---|---|---|
committer | Jeffrey Wilcke <jeffrey@ethereum.org> | 2016-11-13 17:44:04 +0800 |
commit | 445feaeef58bd89a113743dccf6fd5df55cde6fa (patch) | |
tree | 6c692a0989800f005a94bde2d372fcbe1f7630a1 /core/state/statedb.go | |
parent | 932d973e36ff0d41a6005b93d2d4ff1b4430fb04 (diff) | |
download | go-tangerine-445feaeef58bd89a113743dccf6fd5df55cde6fa.tar.gz go-tangerine-445feaeef58bd89a113743dccf6fd5df55cde6fa.tar.zst go-tangerine-445feaeef58bd89a113743dccf6fd5df55cde6fa.zip |
core, core/state, trie: EIP158, reprice & skip empty account write
This commit implements EIP158 part 1, 2, 3 & 4
1. If an account is empty it's no longer written to the trie. An empty
account is defined as (balance=0, nonce=0, storage=0, code=0).
2. Delete an empty account if it's touched
3. An empty account is redefined as either non-existent or empty.
4. Zero value calls and zero value suicides no longer consume the 25k
reation costs.
params: moved core/config to params
Signed-off-by: Jeffrey Wilcke <jeffrey@ethereum.org>
Diffstat (limited to 'core/state/statedb.go')
-rw-r--r-- | core/state/statedb.go | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/core/state/statedb.go b/core/state/statedb.go index ae106e03b..1c4af0295 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -213,6 +213,13 @@ func (self *StateDB) Exist(addr common.Address) bool { return self.GetStateObject(addr) != nil } +// Empty returns whether the state object is either non-existant +// or empty according to the EIP161 specification (balance = nonce = code = 0) +func (self *StateDB) Empty(addr common.Address) bool { + so := self.GetStateObject(addr) + return so == nil || so.empty() +} + func (self *StateDB) GetAccount(addr common.Address) vm.Account { return self.GetStateObject(addr) } @@ -516,10 +523,10 @@ func (self *StateDB) GetRefund() *big.Int { // 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 { +func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { for addr, _ := range s.stateObjectsDirty { stateObject := s.stateObjects[addr] - if stateObject.suicided { + if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) { s.deleteStateObject(stateObject) } else { stateObject.updateRoot(s.db) @@ -553,17 +560,17 @@ func (s *StateDB) DeleteSuicides() { } // Commit commits all state changes to the database. -func (s *StateDB) Commit() (root common.Hash, err error) { - root, batch := s.CommitBatch() +func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) { + root, batch := s.CommitBatch(deleteEmptyObjects) return root, batch.Write() } // 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) { +func (s *StateDB) CommitBatch(deleteEmptyObjects bool) (root common.Hash, batch ethdb.Batch) { batch = s.db.NewBatch() - root, _ = s.commit(batch) + root, _ = s.commit(batch, deleteEmptyObjects) glog.V(logger.Debug).Infof("Trie cache stats: %d misses, %d unloads", trie.CacheMisses(), trie.CacheUnloads()) return root, batch @@ -575,16 +582,18 @@ func (s *StateDB) clearJournalAndRefund() { s.refund = new(big.Int) } -func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) { +func (s *StateDB) commit(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) { defer s.clearJournalAndRefund() // Commit objects to the trie. for addr, stateObject := range s.stateObjects { - if stateObject.suicided { + _, isDirty := s.stateObjectsDirty[addr] + switch { + case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()): // If the object has been removed, don't bother syncing it // and just mark it for deletion in the trie. s.deleteStateObject(stateObject) - } else if _, ok := s.stateObjectsDirty[addr]; ok { + case isDirty: // Write any contract code associated with the state object if stateObject.code != nil && stateObject.dirtyCode { if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil { |