Skip to content

Commit

Permalink
add transient storage
Browse files Browse the repository at this point in the history
  • Loading branch information
charles-cooper authored and fselmo committed Mar 6, 2024
1 parent 07780b1 commit e047fb1
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 3 deletions.
33 changes: 33 additions & 0 deletions eth/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2446,6 +2446,22 @@ class AccountAPI(ABC):
code_hash: Hash32


class TransientStorageAPI(ABC):
@abstractmethod
def get_transient_storage(self, address: Address, slot: int) -> int:
"""
Return the transient storage for ``address`` at slot ``slot``.
"""
...

@abstractmethod
def set_transient_storage(self, address: Address, slot: int, value: int) -> None:
"""
Return the transient storage for ``address`` at slot ``slot``.
"""
...


class AccountDatabaseAPI(ABC):
"""
A class representing a database for accounts.
Expand Down Expand Up @@ -3114,6 +3130,23 @@ def mark_address_warm(self, address: Address) -> None:
"""
...

#
# transient storage
#
@abstractmethod
def get_transient_storage(self, address: Address, slot: int) -> int:
"""
Return the transient storage for ``address`` at slot ``slot``.
"""
...

@abstractmethod
def set_transient_storage(self, address: Address, slot: int, value: int) -> None:
"""
Return the transient storage for ``address`` at slot ``slot``.
"""
...

#
# Access self._chaindb
#
Expand Down
48 changes: 45 additions & 3 deletions eth/vm/forks/cancun/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@
Type,
)

from eth_typing import (
Address,
)

from eth.abc import (
TransactionExecutorAPI,
TransientStorageAPI,
)

from ..shanghai import (
from eth.vm.forks.shanghai import (
ShanghaiState,
)
from eth.vm.transient_mapping import (
TransientStorage,
)

from ..shanghai.state import (
ShanghaiTransactionExecutor,
)
Expand All @@ -18,9 +26,43 @@


class CancunTransactionExecutor(ShanghaiTransactionExecutor):
pass
def build_computation(self, *args, **kwargs):
self.vm_state.reset_transient_storage()
return super().build_computation(*args, **kwargs)


class CancunState(ShanghaiState):
computation_class = CancunComputation
transaction_executor_class: Type[TransactionExecutorAPI] = CancunTransactionExecutor

_transient_storage_class: Type[TransientStorageAPI] = TransientStorage
_transient_storage: TransientStorageAPI = None

@property
def transient_storage(self):
if self._transient_storage is None:
self.reset_transient_storage()

return self._transient_storage

def reset_transient_storage(self):
self._transient_storage = self._transient_storage_class()

def get_transient_storage(self, address: Address, slot: int) -> int:
return self.transient_storage.get_transient_storage(address, slot)

def set_transient_storage(self, address: Address, slot: int, value: int) -> None:
return self.transient_storage.set_transient_storage(address, slot, value)

def snapshot(self):
state_root, checkpoint = super().snapshot()
self.transient_storage.record(checkpoint)
return state_root, checkpoint

def commit(self, snapshot):
super().commit(snapshot)
self.transient_storage.commit(snapshot)

def discard(self, snapshot):
super().discard(snapshot)
self.transient_storage.discard(snapshot)
14 changes: 14 additions & 0 deletions eth/vm/logic/transient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def tstore(computation):
address = computation.msg.storage_address
slot, value = computation.stack_pop_ints(2)

computation.state.set_transient_storage(address, slot, value)


def tload(computation):
address = computation.msg.storage_address
slot = computation.stack_pop1_int()
state = computation.state
value = state.get_transient_storage(address, slot)

computation.push_int(value)
6 changes: 6 additions & 0 deletions eth/vm/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@ def is_address_warm(self, address: Address) -> bool:
def mark_address_warm(self, address: Address) -> None:
self._account_db.mark_address_warm(address)

def get_transient_storage(self, address: Address, slot: int) -> int:
raise AttributeError("No transient_storage has been set for this State")

def set_transient_storage(self, address: Address, slot: int, value: int) -> None:
raise AttributeError("No transient_storage has been set for this State")

#
# Access self._chaindb
#
Expand Down
53 changes: 53 additions & 0 deletions eth/vm/transient_mapping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from eth_utils import (
int_to_big_endian,
)

from eth.abc import (
TransientStorageAPI,
)
from eth.db.backends.memory import (
MemoryDB,
)
from eth.db.journal import (
JournalDB,
)
from eth.typing import (
Address,
)
from eth.validation import (
validate_canonical_address,
validate_uint256,
)


class TransientStorage(TransientStorageAPI):
def __init__(self):
self._transient_storage = JournalDB(MemoryDB())

@staticmethod
def _get_key(address: Address, slot: int) -> bytes:
return address + int_to_big_endian(slot)

def get_transient_storage(self, address: Address, slot: int) -> int:
validate_canonical_address(address)
validate_uint256(slot)

key = self._get_key(address, slot)
return self._transient_storage.get(key, 0)

def set_transient_storage(self, address: Address, slot: int, value: int) -> None:
validate_canonical_address(address)
validate_uint256(slot)
validate_uint256(value)

key = self._get_key(address, slot)
self._transient_storage[key] = value

def record(self, checkpoint):
self._transient_storage.record(checkpoint)

def commit(self, checkpoint):
self._transient_storage.commit(checkpoint)

def discard(self, checkpoint):
self._transient_storage.discard(checkpoint)

0 comments on commit e047fb1

Please sign in to comment.