Skip to content

Commit

Permalink
fix: use sload for storage
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed May 5, 2024
1 parent 8eeb365 commit c311345
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 36 deletions.
4 changes: 2 additions & 2 deletions pyrevm.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,15 @@ class EVM:
:param balance: The balance.
"""

def storage(self: "EVM", address: str, index: int) -> Optional[int]:
def storage(self: "EVM", address: str, index: int) -> int:
"""
Returns the storage value of the given address at the given index.
:param address: The address.
:param index: The index.
:return: The storage value.
"""

def block_hash(self: "EVM", number: int) -> Optional[bytes]:
def block_hash(self: "EVM", number: int) -> bytes:
"""
Returns the block hash of the given number.
:param number: The number.
Expand Down
34 changes: 15 additions & 19 deletions src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,18 @@ impl EVM {
}

/// Get storage value of address at index.
fn storage(&mut self, address: &str, index: U256) -> PyResult<Option<U256>> {
let (account, _) = self.context.load_account(addr(address)?).map_err(pyerr)?;
Ok(account.storage.get(&index).map(|s| s.present_value))
fn storage(&mut self, address: &str, index: U256) -> PyResult<U256> {
let address = addr(address)?;
// `sload` expects the account to be already loaded.
let _ = self.context.load_account(address).map_err(pyerr)?;
let (value, _) = self.context.sload(address, index).map_err(pyerr)?;
Ok(value)
}

/// Get block hash by block number.
fn block_hash(&mut self, number: U256, py: Python<'_>) -> PyResult<Option<PyObject>> {
let bytes = self.context.block_hash(number).map_err(pyerr)?;
if bytes.is_empty() {
return Ok(None);
}
Ok(Some(PyBytes::new(py, bytes.as_ref()).into()))
fn block_hash(&mut self, number: U256, py: Python<'_>) -> PyResult<PyObject> {
let hash = self.context.block_hash(number).map_err(pyerr)?;
Ok(PyBytes::new(py, hash.as_ref()).into())
}

/// Inserts the provided account information in the database at the specified address.
Expand All @@ -153,14 +153,10 @@ impl EVM {

/// Set the balance of a given address.
fn set_balance(&mut self, address: &str, balance: U256) -> PyResult<()> {
let address_ = addr(address)?;
let account = {
let (account, _) = self.context.load_account(address_).map_err(pyerr)?;
account.info.balance = balance;
account.clone()
};
self.context.journaled_state.state.insert(address_, account);
self.context.journaled_state.touch(&address_);
let address = addr(address)?;
let (account, _) = self.context.load_account(address).map_err(pyerr)?;
account.info.balance = balance;
self.context.journaled_state.touch(&address);
Ok(())
}

Expand Down Expand Up @@ -342,10 +338,10 @@ impl EVM {
if let Output::Create(out, address) = output {
Ok((out, address.unwrap()))
} else {
Err(pyerr(output.clone()))
Err(pyerr(output))
}
} else {
Err(pyerr(result.clone()))
Err(pyerr(result))
}
}

Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![warn(unreachable_pub)]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![deny(unused_must_use, rust_2018_idioms)]
#![allow(non_local_definitions)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![allow(clippy::too_many_arguments)]

Expand Down
6 changes: 3 additions & 3 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use pyo3::types::PyBytes;
use pyo3::{exceptions::PyTypeError, prelude::*};
use revm::precompile::B256;
use revm::primitives::{fake_exponential as revm_fake_exponential, Address};
use std::fmt::Debug;
use std::fmt;

pub(crate) fn addr(s: &str) -> Result<Address, PyErr> {
s.parse::<Address>()
Expand All @@ -18,8 +18,8 @@ pub(crate) fn addr_or_zero(s: Option<&str>) -> Result<Address, PyErr> {
}

/// Convert a Rust error into a Python error.
pub(crate) fn pyerr<T: Debug>(err: T) -> PyErr {
PyRuntimeError::new_err(format!("{:?}", err))
pub(crate) fn pyerr<T: fmt::Debug>(err: T) -> PyErr {
PyRuntimeError::new_err(format!("{err:?}"))
}

pub(crate) fn from_pybytes(b: &PyBytes) -> PyResult<B256> {
Expand Down
41 changes: 29 additions & 12 deletions tests/test_evm.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import json
import os

from pyrevm import EVM, Env, BlockEnv, AccountInfo, TxEnv
from pyrevm import EVM, AccountInfo, BlockEnv, Env, TxEnv

from tests.utils import load_contract_bin, encode_uint, encode_address
import pytest

from tests.utils import encode_address, encode_uint, load_contract_bin

address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" # vitalik.eth
address2 = "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"

# use your own key during development to avoid rate limiting the CI job
fork_url = os.getenv("FORK_URL") or "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"
fork_url = (
os.getenv("FORK_URL")
or "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"
)

KWARG_CASES = [
{"fork_url": fork_url},
Expand Down Expand Up @@ -40,7 +42,7 @@ def test_revm_fork():
evm.message_call(
caller=address,
to=address2,
value=10000
value=10000,
# data
)

Expand All @@ -51,6 +53,13 @@ def test_revm_fork():
assert info.balance == 10000


def test_fork_storage():
weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
evm = EVM(fork_url=fork_url, fork_block="latest")
value = evm.storage(weth, 0)
assert value is not None and value > 0


def test_deploy():
evm = EVM()

Expand All @@ -65,13 +74,13 @@ def test_deploy():

assert deployed_at == "0x3e4ea2156166390f880071d94458efb098473311"
deployed_code = evm.get_code(deployed_at)
assert deployed_code.hex().rstrip('0') in code.hex()
assert deployed_code.hex().rstrip("0") in code.hex()
assert evm.basic(deployed_at).code.hex() == deployed_code.hex()

result = evm.message_call(
address,
deployed_at,
calldata=b'\xc2\x98Ux' # ==method_id('foo()')
calldata=b"\xc2\x98Ux", # ==method_id('foo()')
)
assert int(result.hex(), 16) == 123

Expand All @@ -92,7 +101,10 @@ def test_balances():


def test_balances_fork():
evm = EVM(fork_url=fork_url, fork_block="0x3b01f793ed1923cd82df5fe345b3e12211aedd514c8546e69efd6386dc0c9a97")
evm = EVM(
fork_url=fork_url,
fork_block="0x3b01f793ed1923cd82df5fe345b3e12211aedd514c8546e69efd6386dc0c9a97",
)

vb_before = evm.basic(address)
assert vb_before.balance == 955628344913799071315
Expand Down Expand Up @@ -215,7 +227,7 @@ def test_blueprint():
# bytecode based on vyper `@external def foo() -> uint256: return 123`
bytecode = load_contract_bin("blueprint.bin")

bytecode = b"\xFE\x71\x00" + bytecode
bytecode = b"\xfe\x71\x00" + bytecode
bytecode_len = len(bytecode)
bytecode_len_hex = hex(bytecode_len)[2:].rjust(4, "0")

Expand All @@ -224,7 +236,7 @@ def test_blueprint():
deploy_bytecode = deploy_preamble + bytecode

deployer_address = evm.deploy(address, deploy_bytecode)
assert evm.basic(deployer_address).code.hex().rstrip('0') in deploy_bytecode.hex()
assert evm.basic(deployer_address).code.hex().rstrip("0") in deploy_bytecode.hex()


def test_block_setters():
Expand All @@ -251,7 +263,10 @@ def test_tx_setters():
assert evm.env.tx.blob_hashes == [b"1" * 32]


@pytest.mark.parametrize("excess_blob_gas,expected_fee", [(0, 1), (10**3, 1), (2**24, 152), (2**26, 537070730)])
@pytest.mark.parametrize(
"excess_blob_gas,expected_fee",
[(0, 1), (10**3, 1), (2**24, 152), (2**26, 537070730)],
)
def test_get_blobbasefee(excess_blob_gas, expected_fee):
evm = EVM()
evm.set_block_env(BlockEnv(excess_blob_gas=excess_blob_gas))
Expand Down Expand Up @@ -295,5 +310,7 @@ def test_call_reverting(kwargs):
value=10,
)

assert evm.get_code(deploy_address), "The code should still be deployed after revert"
assert evm.get_code(
deploy_address
), "The code should still be deployed after revert"
assert str(err.value).startswith("Transaction(LackOfFundForMaxFee")

0 comments on commit c311345

Please sign in to comment.