Skip to content

Commit f310a20

Browse files
committed
Count number of self-destructs in optimized state (closes #1240)
1 parent 74080b2 commit f310a20

File tree

1 file changed

+15
-11
lines changed

1 file changed

+15
-11
lines changed

src/ethereum_optimized/state_db.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
module to use an optimized database backed state.
1414
"""
1515
import logging
16+
from collections import defaultdict
1617
from dataclasses import dataclass
1718
from importlib import import_module
1819
from typing import Any, ClassVar, Dict, List, Optional, Set, cast
@@ -77,7 +78,7 @@ class State:
7778
db: Any
7879
dirty_accounts: Dict[Address, Optional[Account_]]
7980
dirty_storage: Dict[Address, Dict[Bytes32, U256]]
80-
destroyed_accounts: Set[Address]
81+
destroyed_accounts: Dict[Address, Uint]
8182
tx_restore_points: List[int]
8283
journal: List[Any]
8384
created_accounts: Set[Address]
@@ -91,7 +92,7 @@ def __init__(self, path: Optional[str] = None) -> None:
9192
self.db = rust_pyspec_glue.DB(path)
9293
self.dirty_accounts = {}
9394
self.dirty_storage = {}
94-
self.destroyed_accounts = set()
95+
self.destroyed_accounts = defaultdict(lambda: Uint(0))
9596
self.tx_restore_points = []
9697
self.journal = []
9798
self.created_accounts = set()
@@ -184,14 +185,15 @@ def flush(state: State) -> None:
184185
"""
185186
if state.tx_restore_points:
186187
raise Exception("In a non-db transaction")
187-
for address in state.destroyed_accounts:
188-
state.db.destroy_storage(address)
188+
for address, count in state.destroyed_accounts.items():
189+
if count:
190+
state.db.destroy_storage(address)
189191
for address, account in state.dirty_accounts.items():
190192
state.db.set_account(address, account)
191193
for address, storage in state.dirty_storage.items():
192194
for key, value in storage.items():
193195
state.db.set_storage(address, key, value)
194-
state.destroyed_accounts = set()
196+
state.destroyed_accounts.clear()
195197
state.dirty_accounts.clear()
196198
state.dirty_storage.clear()
197199

@@ -205,7 +207,7 @@ def rollback_db_transaction(state: State) -> None:
205207
state.db.rollback_mutable()
206208
state.dirty_accounts.clear()
207209
state.dirty_storage.clear()
208-
state.destroyed_accounts = set()
210+
state.destroyed_accounts.clear()
209211

210212
def _begin_transaction(state: State) -> None:
211213
"""
@@ -291,8 +293,10 @@ def _rollback_transaction(state: State) -> None:
291293
state.dirty_storage[item[0]][item[1]] = item[2]
292294
elif type(item[1]) is dict:
293295
# Restore storage that was destroyed by `destroy_storage()`
294-
state.destroyed_accounts.remove(item[0])
295-
state.dirty_storage[item[0]] = item[1]
296+
state.destroyed_accounts[item[0]] -= Uint(1)
297+
if state.destroyed_accounts[item[0]] == 0:
298+
state.dirty_storage[item[0]] = item[1]
299+
del state.destroyed_accounts[item[0]]
296300
else:
297301
# Revert a change to an account
298302
if item[1] is Unmodified:
@@ -338,7 +342,7 @@ def get_storage(state: State, address: Address, key: Bytes32) -> U256:
338342
):
339343
return state.dirty_storage[address][key]
340344

341-
if address in state.destroyed_accounts:
345+
if state.destroyed_accounts[address]:
342346
return U256(0)
343347
else:
344348
return U256(state.db.get_storage(address, key))
@@ -410,7 +414,7 @@ def destroy_storage(state: State, address: Address) -> None:
410414
See `state`.
411415
"""
412416
state.journal.append((address, state.dirty_storage.pop(address, {})))
413-
state.destroyed_accounts.add(address)
417+
state.destroyed_accounts[address] += Uint(1)
414418
set_account(state, address, get_account_optional(state, address))
415419

416420
@add_item(patches)
@@ -430,7 +434,7 @@ def account_has_storage(state: State, address: Address) -> bool:
430434
if v != U256(0):
431435
return True
432436

433-
if address in state.destroyed_accounts:
437+
if state.destroyed_accounts[address]:
434438
return False
435439

436440
return state.db.has_storage(address)

0 commit comments

Comments
 (0)