diff --git a/pyrevm.pyi b/pyrevm.pyi index e125413..5102686 100644 --- a/pyrevm.pyi +++ b/pyrevm.pyi @@ -257,7 +257,7 @@ 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. @@ -265,7 +265,7 @@ class EVM: :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. diff --git a/src/evm.rs b/src/evm.rs index e18d069..a5d835f 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -125,18 +125,18 @@ impl EVM { } /// Get storage value of address at index. - fn storage(&mut self, address: &str, index: U256) -> PyResult> { - 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 { + 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> { - 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 { + 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. @@ -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(()) } @@ -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)) } } diff --git a/src/lib.rs b/src/lib.rs index ec6a876..7967e82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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)] diff --git a/src/utils.rs b/src/utils.rs index 53f68ee..f74fb1e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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 { s.parse::
() @@ -18,8 +18,8 @@ pub(crate) fn addr_or_zero(s: Option<&str>) -> Result { } /// Convert a Rust error into a Python error. -pub(crate) fn pyerr(err: T) -> PyErr { - PyRuntimeError::new_err(format!("{:?}", err)) +pub(crate) fn pyerr(err: T) -> PyErr { + PyRuntimeError::new_err(format!("{err:?}")) } pub(crate) fn from_pybytes(b: &PyBytes) -> PyResult { diff --git a/tests/test_evm.py b/tests/test_evm.py index ed0aef0..6964ae9 100644 --- a/tests/test_evm.py +++ b/tests/test_evm.py @@ -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}, @@ -40,7 +42,7 @@ def test_revm_fork(): evm.message_call( caller=address, to=address2, - value=10000 + value=10000, # data ) @@ -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() @@ -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 @@ -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 @@ -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") @@ -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(): @@ -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)) @@ -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")