aboutsummaryrefslogtreecommitdiffstats
path: root/core/state/statedb.go
diff options
context:
space:
mode:
authorJeffrey Wilcke <jeffrey@ethereum.org>2016-10-20 19:36:29 +0800
committerJeffrey Wilcke <jeffrey@ethereum.org>2016-11-13 17:44:04 +0800
commit445feaeef58bd89a113743dccf6fd5df55cde6fa (patch)
tree6c692a0989800f005a94bde2d372fcbe1f7630a1 /core/state/statedb.go
parent932d973e36ff0d41a6005b93d2d4ff1b4430fb04 (diff)
downloadgo-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.go27
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 {