From 8072dbdc6594ceac0fcc0181d701e580eb94e5f4 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Mon, 3 Jul 2023 12:52:17 -0600 Subject: [PATCH 1/7] book workflow --- .github/workflows/book.yml | 126 +++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 .github/workflows/book.yml diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml new file mode 100644 index 0000000000..746ab3d543 --- /dev/null +++ b/.github/workflows/book.yml @@ -0,0 +1,126 @@ +name: book +on: + push: + branches: [main] + pull_request: + branches: [main] + merge_group: + +jobs: + test: + runs-on: ubuntu-latest + name: test + + steps: + - uses: actions/checkout@v3 + + - name: Install mdbook + run: | + mkdir mdbook + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.14/mdbook-v0.4.14-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + echo `pwd`/mdbook >> $GITHUB_PATH + + - name: Install mdbook-template + run: | + mkdir mdbook-template + curl -sSL https://github.com/sgoudham/mdbook-template/releases/latest/download/mdbook-template-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook-template + echo `pwd`/mdbook-template >> $GITHUB_PATH + + - name: Run tests + run: mdbook test + + lint: + runs-on: ubuntu-latest + name: lint + + steps: + - uses: actions/checkout@v3 + + - name: Install mdbook-linkcheck + run: | + mkdir mdbook-linkcheck + curl -sSL -o mdbook-linkcheck.zip https://github.com/Michael-F-Bryan/mdbook-linkcheck/releases/latest/download/mdbook-linkcheck.x86_64-unknown-linux-gnu.zip + unzip mdbook-linkcheck.zip -d ./mdbook-linkcheck + chmod +x `pwd`/mdbook-linkcheck/mdbook-linkcheck + echo `pwd`/mdbook-linkcheck >> $GITHUB_PATH + + - name: Run linkcheck + run: mdbook-linkcheck --standalone + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Install toolchain + uses: dtolnay/rust-toolchain@nightly + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + + - name: Install mdbook + run: | + mkdir mdbook + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.14/mdbook-v0.4.14-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + echo `pwd`/mdbook >> $GITHUB_PATH + + - name: Install mdbook-template + run: | + mkdir mdbook-template + curl -sSL https://github.com/sgoudham/mdbook-template/releases/latest/download/mdbook-template-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook-template + echo `pwd`/mdbook-template >> $GITHUB_PATH + + - name: Build book + run: mdbook build + + - name: Build docs + run: RUSTDOCFLAGS="--enable-index-page -Zunstable-options" cargo +nightly doc --all --no-deps + + - name: Move docs to book folder + run: | + mv target/doc target/book/docs + + - name: Archive artifact + shell: sh + run: | + chmod -c -R +rX "target/book" | + while read line; do + echo "::warning title=Invalid file permissions automatically fixed::$line" + done + tar \ + --dereference --hard-dereference \ + --directory "target/book" \ + -cvf "$RUNNER_TEMP/artifact.tar" \ + --exclude=.git \ + --exclude=.github \ + . + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: github-pages + path: ${{ runner.temp }}/artifact.tar + retention-days: 1 + if-no-files-found: error + + deploy: + # Only deploy if a push to main + if: github.ref_name == 'main' && github.event_name == 'push' + runs-on: ubuntu-latest + needs: [test, lint, build] + + # Grant GITHUB_TOKEN the permissions required to make a Pages deployment + permissions: + pages: write + id-token: write + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 \ No newline at end of file From 0a7ee46fe24f1f21292992831a628a6cf1f0a99b Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Mon, 3 Jul 2023 13:06:24 -0600 Subject: [PATCH 2/7] mdbook lint --- book.toml | 6 +++++- documentation/src/crates/interpreter.md | 2 +- documentation/src/crates/interpreter/interpreter.md | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) delete mode 100644 documentation/src/crates/interpreter/interpreter.md diff --git a/book.toml b/book.toml index 5f56a60e04..0cb2a10b63 100644 --- a/book.toml +++ b/book.toml @@ -1,6 +1,10 @@ [book] -authors = ["Colin, Waylon Jepsen"] +authors = ["Colin Roberts, Waylon Jepsen"] language = "en" multilingual = false src = "documentation/src" title = "Rust EVM" + + +[output.linkcheck] +follow-web-links = true \ No newline at end of file diff --git a/documentation/src/crates/interpreter.md b/documentation/src/crates/interpreter.md index 21ec644c8b..901f3cc897 100644 --- a/documentation/src/crates/interpreter.md +++ b/documentation/src/crates/interpreter.md @@ -9,7 +9,7 @@ Modules: - [inner_models](./interpreter/inner_models.md): Based on the name, this module could contain the inner data structures or models used in the EVM implementation. - [instruction_result](./interpreter/instruction_result.md): This module likely contains definitions related to the result of instruction execution. - [instructions](./interpreter/instructions.md): This module is expected to include the definitions of the EVM opcodes (instructions). -- [interpreter](./interpreter/interpreter.md): This module would contain the Interpreter struct and related functionality for executing EVM instructions. + External Crates: diff --git a/documentation/src/crates/interpreter/interpreter.md b/documentation/src/crates/interpreter/interpreter.md deleted file mode 100644 index 1d687daae0..0000000000 --- a/documentation/src/crates/interpreter/interpreter.md +++ /dev/null @@ -1 +0,0 @@ -# interpreter From bccecb4920c4bfe3eebc7fd60303f81d72abe231 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Mon, 3 Jul 2023 13:20:14 -0600 Subject: [PATCH 3/7] mdbook build optional --- book.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/book.toml b/book.toml index 0cb2a10b63..835363e927 100644 --- a/book.toml +++ b/book.toml @@ -7,4 +7,5 @@ title = "Rust EVM" [output.linkcheck] +optional = true follow-web-links = true \ No newline at end of file From d6727737d5cf8245354f4fac1175840075a58139 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Fri, 18 Aug 2023 08:28:23 -0700 Subject: [PATCH 4/7] Update introduction.md --- documentation/src/introduction.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/documentation/src/introduction.md b/documentation/src/introduction.md index 559586f3c8..f46bc9c615 100644 --- a/documentation/src/introduction.md +++ b/documentation/src/introduction.md @@ -7,11 +7,12 @@ The project hase 4 main crates that are used to build the revm. The crates are: - `revm`: The main EVM library. -- `revm-primitives`: Primitive data types. -- `revm-interpreter`: Execution loop with instructions. -- `revm-precompile`: EVM precompiles. +- `primitives`: Primitive data types. +- `interpreter`: Execution loop with instructions. +- `precompile`: EVM precompiles. ## Binaries -- `revme`: A CLI binary, used for running state test json. +- `revme`: A CLI binary, used for running state test json. Currently it is used to run ethereum tests: +* statetest: takes path to folder where ethereum statetest json can be found. It recursively searches for all json files and execute them. This is how I run all https://github.com/ethereum/tests to check if revm is compliant. Example `revme statests test/GenericEvmTest/` - `revm-test`: test binaries with contracts; used mostly to check performance. From be21182b1c33c197181f5b67c2533999ccd36f86 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Fri, 18 Aug 2023 10:39:17 -0700 Subject: [PATCH 5/7] interpreter primitives + precompiles mdbook test, doctests --- README.md | 8 + crates/primitives/src/bits.rs | 2 - crates/primitives/src/result.rs | 2 +- crates/primitives/src/specification.rs | 2 +- crates/primitives/src/utilities.rs | 4 +- crates/revm/src/evm.rs | 12 ++ crates/revm/src/inspector/tracer_eip3155.rs | 2 +- documentation/src/SUMMARY.md | 2 +- documentation/src/crates/interpreter.md | 17 +- documentation/src/crates/interpreter/gas.md | 42 ++--- documentation/src/crates/interpreter/host.md | 18 +- .../src/crates/interpreter/inner_models.md | 93 ++-------- .../crates/interpreter/instruction_result.md | 79 +------- .../src/crates/interpreter/instructions.md | 48 +---- .../src/crates/precompile/point_evaluation.md | 6 + documentation/src/crates/primitives/bits.md | 10 +- .../src/crates/primitives/bytecode.md | 3 +- .../src/crates/primitives/constants.md | 8 +- .../src/crates/primitives/database.md | 4 +- .../src/crates/primitives/environment.md | 2 +- documentation/src/crates/primitives/log.md | 2 +- .../src/crates/primitives/precompile.md | 2 +- documentation/src/crates/primitives/result.md | 2 +- .../src/crates/primitives/specifications.md | 2 +- documentation/src/crates/primitives/state.md | 2 +- documentation/src/crates/primitives/utils.md | 2 +- documentation/src/crates/revm.md | 30 +-- documentation/src/crates/revm/evm.md | 67 +------ documentation/src/crates/revm/evm_impl.md | 115 +++++------- documentation/src/crates/revm/inspector.md | 62 ------- .../src/crates/revm/journaled_state.md | 175 +++++------------- documentation/src/examples.md | 130 ------------- documentation/src/introduction.md | 20 +- examples/fork_ref_transact.rs | 1 + 34 files changed, 221 insertions(+), 755 deletions(-) create mode 100644 documentation/src/crates/precompile/point_evaluation.md delete mode 100644 documentation/src/examples.md diff --git a/README.md b/README.md index dd9f20b351..1ee9784e35 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,14 @@ cargo run -p revm --features ethersdb --example fork_ref_transact (If you want to add your project to the list, ping me or open the PR) +# Documentation + +To serve the mdbook documentation, ensure you have mdbook installed (if not install it with cargo) and then run: + +```shell +mdbook serve documentation +``` + # Contact There is public telegram group: https://t.me/+Ig4WDWOzikA3MzA0 diff --git a/crates/primitives/src/bits.rs b/crates/primitives/src/bits.rs index 45ac577d8c..31b7d69ba7 100644 --- a/crates/primitives/src/bits.rs +++ b/crates/primitives/src/bits.rs @@ -1,5 +1,3 @@ -#![allow(clippy::incorrect_clone_impl_on_copy_type)] - use derive_more::{AsRef, Deref}; use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions}; diff --git a/crates/primitives/src/result.rs b/crates/primitives/src/result.rs index d38604f979..d5a59aaaed 100644 --- a/crates/primitives/src/result.rs +++ b/crates/primitives/src/result.rs @@ -39,7 +39,7 @@ pub enum ExecutionResult { impl ExecutionResult { /// Returns if transaction execution is successful. /// 1 indicates success, 0 indicates revert. - /// https://eips.ethereum.org/EIPS/eip-658 + /// pub fn is_success(&self) -> bool { matches!(self, Self::Success { .. }) } diff --git a/crates/primitives/src/specification.rs b/crates/primitives/src/specification.rs index cb6e7102eb..460f377803 100644 --- a/crates/primitives/src/specification.rs +++ b/crates/primitives/src/specification.rs @@ -1,5 +1,5 @@ /// SpecId and their activation block -/// Information was obtained from: https://github.com/ethereum/execution-specs +/// Information was obtained from: #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, enumn::N)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/primitives/src/utilities.rs b/crates/primitives/src/utilities.rs index ff5d364c80..e03be20f6b 100644 --- a/crates/primitives/src/utilities.rs +++ b/crates/primitives/src/utilities.rs @@ -11,7 +11,7 @@ pub fn keccak256(input: &[u8]) -> B256 { B256(Keccak256::digest(input)[..].try_into().unwrap()) } -/// Returns the address for the legacy `CREATE` scheme: [`CreateScheme::Create`] +/// Returns the address for the legacy `CREATE` scheme: [`crate::env::CreateScheme::Create`] pub fn create_address(caller: B160, nonce: u64) -> B160 { let mut stream = rlp::RlpStream::new_list(2); stream.append(&caller.0.as_ref()); @@ -20,7 +20,7 @@ pub fn create_address(caller: B160, nonce: u64) -> B160 { B160(out[12..].try_into().unwrap()) } -/// Returns the address for the `CREATE2` scheme: [`CreateScheme::Create2`] +/// Returns the address for the `CREATE2` scheme: [`crate::env::CreateScheme::Create2`] pub fn create2_address(caller: B160, code_hash: B256, salt: U256) -> B160 { let mut hasher = Keccak256::new(); hasher.update([0xff]); diff --git a/crates/revm/src/evm.rs b/crates/revm/src/evm.rs index 298b09b18a..76f223bfa4 100644 --- a/crates/revm/src/evm.rs +++ b/crates/revm/src/evm.rs @@ -25,6 +25,18 @@ use revm_precompile::Precompiles; /// want to update anything on it. It enabled `transact_ref` and `inspect_ref` functions /// * Database+DatabaseCommit allow directly committing changes of transaction. it enabled `transact_commit` /// and `inspect_commit` +/// +/// /// # Example +/// +/// ``` +/// # use revm::EVM; // Assuming this struct is in 'your_crate_name' +/// # struct SomeDatabase; // Mocking a database type for the purpose of this example +/// # struct Env; // Assuming the type Env is defined somewhere +/// +/// let evm: EVM = EVM::new(); +/// assert!(evm.db.is_none()); +/// ``` +/// #[derive(Clone)] pub struct EVM { pub env: Env, diff --git a/crates/revm/src/inspector/tracer_eip3155.rs b/crates/revm/src/inspector/tracer_eip3155.rs index 45fd8094a2..463fd3ce4a 100644 --- a/crates/revm/src/inspector/tracer_eip3155.rs +++ b/crates/revm/src/inspector/tracer_eip3155.rs @@ -1,4 +1,4 @@ -//! Inspector that support tracing of EIP-3155 https://eips.ethereum.org/EIPS/eip-3155 +//! Inspector that support tracing of EIP-3155 use crate::inspectors::GasInspector; use crate::interpreter::{CallInputs, CreateInputs, Gas, InstructionResult}; diff --git a/documentation/src/SUMMARY.md b/documentation/src/SUMMARY.md index 0257edd061..de50a57ba7 100644 --- a/documentation/src/SUMMARY.md +++ b/documentation/src/SUMMARY.md @@ -12,7 +12,6 @@ - [inner_models](./crates/interpreter/inner_models.md) - [instruction_result](./crates/interpreter/instruction_result.md) - [instructions](./crates/interpreter/instructions.md) -- [Examples](./examples.md) - [Primitives](./crates/primitives.md) - [database](./crates/primitives/database.md) - [result](./crates/primitives/result.md) @@ -32,3 +31,4 @@ - [Identity function](./crates/precompile/identity.md) - [Modular Exponentiation](./crates/precompile/modexp.md) - [Secp256k1](./crates/precompile/secp256k1.md) + - [Point Evaluation](./crates/precompile/point_evaluation.md) diff --git a/documentation/src/crates/interpreter.md b/documentation/src/crates/interpreter.md index 901f3cc897..3146c282ee 100644 --- a/documentation/src/crates/interpreter.md +++ b/documentation/src/crates/interpreter.md @@ -5,10 +5,10 @@ The `interpreter` crate is concerned with the execution of the EVM opcodes and s Modules: - [gas](./interpreter/gas.md): This module deals with handling the gas mechanics in the EVM, such as calculating gas costs for operations. -- [host](./interpreter/host.md): This module defines the `Host` trait, and any types or functions that the host machine (the machine running the EVM). -- [inner_models](./interpreter/inner_models.md): Based on the name, this module could contain the inner data structures or models used in the EVM implementation. -- [instruction_result](./interpreter/instruction_result.md): This module likely contains definitions related to the result of instruction execution. -- [instructions](./interpreter/instructions.md): This module is expected to include the definitions of the EVM opcodes (instructions). +- [host](./interpreter/host.md): This module defines the evm context `Host` trait. +- [inner_models](./interpreter/inner_models.md): This module contains the inner data structures used in the EVM implementation. +- [instruction_result](./interpreter/instruction_result.md): This module contains definitions related to the result of instruction execution. +- [instructions](./interpreter/instructions.md): This module includes the definitions of the EVM opcodes (instructions). External Crates: @@ -18,9 +18,8 @@ External Crates: Constants: -- `USE_GAS`: This constant determines whether gas measurement should be used. It's set to false if the no_gas_measuring feature is enabled. +- `USE_GAS`: This constant determines whether gas measurement should be used. It's set to false if the `no_gas_measuring` feature is enabled. -Re-exported Types: -Several types and functions are re-exported for easier access by users of this library, such as Gas, Host, InstructionResult, OpCode, Interpreter, Memory, Stack, and others. This allows users to import these items directly from the library root instead of from their individual modules. -Re-exported Crate: -revm_primitives: This crate is re-exported, likely providing primitive types or functionality used in the EVM implementation. +Re-exports: +- Several types and functions are re-exported for easier access by users of this library, such as `Gas`, `Host`, `InstructionResult`, `OpCode`, `Interpreter`, `Memory`, `Stack`, and others. This allows users to import these items directly from the library root instead of from their individual modules. +- revm_primitives: This crate is re-exported, providing primitive types or functionality used in the EVM implementation. diff --git a/documentation/src/crates/interpreter/gas.md b/documentation/src/crates/interpreter/gas.md index 131ba9e65f..cebad5eed2 100644 --- a/documentation/src/crates/interpreter/gas.md +++ b/documentation/src/crates/interpreter/gas.md @@ -2,33 +2,18 @@ The `gas.rs` module in this Rust EVM implementation manages the concept of "gas" within the Ethereum network. In Ethereum, "gas" signifies the computational effort needed to execute operations, whether a simple transfer of ether or the execution of a smart contract function. Each operation carries a gas cost, and transactions must specify the maximum amount of gas they are willing to consume. -## `Gas` Struct - -The `Gas` struct represents the gas state for a particular operation or transaction. The struct is defined as follows: - -```rust -#[derive(Clone, Copy, Debug)] -pub struct Gas { - /// Gas Limit - limit: u64, - /// used+memory gas. - all_used_gas: u64, - /// Used gas without memory - used: u64, - /// Used gas for memory expansion - memory: u64, - /// Refunded gas. This gas is used only at the end of execution. - refunded: i64, -} -``` - -### Fields in `Gas` Struct - -- `limit`: The maximum amount of gas allowed for the operation or transaction. -- `all_used_gas`: The total gas used, inclusive of memory expansion costs. -- `used`: The gas used, excluding memory expansion costs. -- `memory`: The gas used for memory expansion. -- `refunded`: The gas refunded. Certain operations in Ethereum allow for gas refunds, up to half the gas used by a transaction. +## Data Structures +- `Gas` Struct + + The `Gas` struct represents the gas state for a particular operation or transaction. The struct is defined as follows: + + ### Fields in `Gas` Struct + + - `limit`: The maximum amount of gas allowed for the operation or transaction. + - `all_used_gas`: The total gas used, inclusive of memory expansion costs. + - `used`: The gas used, excluding memory expansion costs. + - `memory`: The gas used for memory expansion. + - `refunded`: The gas refunded. Certain operations in Ethereum allow for gas refunds, up to half the gas used by a transaction. ## Methods of the `Gas` Struct @@ -42,6 +27,3 @@ The `Gas` struct also includes several methods to manage the gas state. Here's a - `record_memory`: This method works similarly to `record_cost`, but specifically for memory expansion gas. It only updates the state if the new memory gas usage is greater than the current usage. - `gas_refund`: Increases the refunded gas by a specified amount. -## Importance of the `Gas` Struct - -These features of the `Gas` struct allow for effective management and tracking of the gas cost associated with executing EVM operations. This is a key part of ensuring that smart contracts and transactions adhere to the resource constraints of the Ethereum network, since overconsumption of resources could potentially lead to network congestion. \ No newline at end of file diff --git a/documentation/src/crates/interpreter/host.md b/documentation/src/crates/interpreter/host.md index 8063b8ad84..a3a7f0ab39 100644 --- a/documentation/src/crates/interpreter/host.md +++ b/documentation/src/crates/interpreter/host.md @@ -2,23 +2,8 @@ The `host.rs` module in this Rust EVM implementation defines a crucial trait `Host`. The `Host` trait outlines an interface for the interaction of the EVM interpreter with its environment (or "host"), encompassing essential operations such as account and storage access, creating logs, and invoking transactions. -## `Host` Trait -The `Host` trait provides the definition for all the methods that any EVM host must implement. It's a crucial bridge between the EVM and its environment, allowing the EVM to interact with blockchain state. - -```rust -pub trait Host { - fn step(&mut self, interpreter: &mut Interpreter) -> InstructionResult; - fn step_end( - &mut self, - interpreter: &mut Interpreter, - ret: InstructionResult, - ) -> InstructionResult; - // ... (other methods omitted for brevity) -} -``` - -## Key Methods of the `Host` Trait +## Trait Methods - `step` & `step_end`: These methods manage the execution of EVM opcodes. The `step` method is invoked before executing an opcode, while `step_end` is invoked after. These methods can modify the EVM state or halt execution based on certain conditions. @@ -38,6 +23,5 @@ pub trait Host { - `create` & `call`: These methods handle the creation of new smart contracts and the invocation of smart contract functions, respectively. -## Importance of the `Host` Trait The `Host` trait provides a standard interface that any host environment for the EVM must implement. This abstraction allows the EVM code to interact with the state of the Ethereum network in a generic way, thereby enhancing modularity and interoperability. Different implementations of the `Host` trait can be used to simulate different environments for testing or for connecting to different Ethereum-like networks. \ No newline at end of file diff --git a/documentation/src/crates/interpreter/inner_models.md b/documentation/src/crates/interpreter/inner_models.md index 7a1c0f353f..daaacc21d6 100644 --- a/documentation/src/crates/interpreter/inner_models.md +++ b/documentation/src/crates/interpreter/inner_models.md @@ -1,94 +1,29 @@ # The `inner_models.rs` Module in the Rust Ethereum Virtual Machine (EVM) -The `inner_models.rs` module within this Rust EVM implementation encompasses a collection of structs and enums that are used as internal models within the EVM. These models represent various aspects of EVM operations such as call and create inputs, call context, value transfers, and the result of self-destruction operations. +The `inner_models.rs` module within this Rust EVM implementation encompasses a collection of datastructures used as internal models within the EVM. These models represent various aspects of EVM operations such as call and create inputs, call context, value transfers, and the result of self-destruction operations. -## `CallInputs` Struct +## Data Structures -The `CallInputs` struct is used to encapsulate the inputs to a smart contract call in the EVM. +- `CallInputs` Struct -```rust -pub struct CallInputs { - pub contract: B160, - pub transfer: Transfer, - pub input: Bytes, - pub gas_limit: u64, - pub context: CallContext, - pub is_static: bool, -} -``` + The `CallInputs` struct is used to encapsulate the inputs to a smart contract call in the EVM. This struct includes the target contract address, the value to be transferred (if any), the input data, the gas limit for the call, the call context, and a boolean indicating if the call is a static call (a read-only operation). -This struct includes the target contract address, the value to be transferred (if any), the input data, the gas limit for the call, the call context, and a boolean indicating if the call is a static call (a read-only operation). +- `CreateInputs` Struct -## `CreateInputs` Struct + The `CreateInputs` struct encapsulates the inputs for creating a new smart contract. This includes the address of the creator, the creation scheme, the value to be transferred, the initialization code for the new contract, and the gas limit for the creation operation. -The `CreateInputs` struct encapsulates the inputs for creating a new smart contract. +- `CallScheme` Enum -```rust -pub struct CreateInputs { - pub caller: B160, - pub scheme: CreateScheme, - pub value: U256, - pub init_code: Bytes, - pub gas_limit: u64, -} -``` + The `CallScheme` enum represents the type of call being made to a smart contract. The different types of calls (`CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL`) represent different modes of interaction with a smart contract, each with its own semantics concerning the treatment of the message sender, value transfer, and the context in which the called code executes. -This includes the address of the creator, the creation scheme, the value to be transferred, the initialization code for the new contract, and the gas limit for the creation operation. +- `CallContext` Struct -## `CallScheme` Enum + The `CallContext` struct encapsulates the context of a smart contract call. This includes the executing contract's address, the caller's address, the address from which the contract code was loaded, the apparent value of the call (for `DELEGATECALL` and `CALLCODE`), and the call scheme. -The `CallScheme` enum represents the type of call being made to a smart contract. +- `Transfer` Struct -```rust -pub enum CallScheme { - Call, - CallCode, - DelegateCall, - StaticCall, -} -``` + The `Transfer` struct represents a value transfer between two accounts. -The different types of calls (`CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL`) represent different modes of interaction with a smart contract, each with its own semantics concerning the treatment of the message sender, value transfer, and the context in which the called code executes. +- `SelfDestructResult` Struct -## `CallContext` Struct - -The `CallContext` struct encapsulates the context of a smart contract call. - -```rust -pub struct CallContext { - pub address: B160, - pub caller: B160, - pub code_address: B160, - pub apparent_value: U256, - pub scheme: CallScheme, -} -``` - -This includes the executing contract's address, the caller's address, the address from which the contract code was loaded, the apparent value of the call (for `DELEGATECALL` and `CALLCODE`), and the call scheme. - -## `Transfer` Struct - -The `Transfer` struct represents a value transfer between two accounts. - -```rust -pub struct Transfer { - pub source: B160, - pub target: B160, - pub value: U256, -} -``` - -## `SelfDestructResult` Struct - -Finally, the `SelfDestructResult` struct captures the result of a self-destruction operation on a contract. - -```rust -pub struct SelfDestructResult { - pub had_value: bool, - pub target_exists: bool, - pub is_cold: bool, - pub previously_destroyed: bool, -} -``` - -In summary, the `inner_models.rs` module provides several crucial data structures that facilitate the representation and handling of various EVM operations and their associated data within this Rust EVM implementation. \ No newline at end of file + The `SelfDestructResult` struct captures the result of a self-destruction operation on a contract. In summary, the `inner_models.rs` module provides several crucial data structures that facilitate the representation and handling of various EVM operations and their associated data within this Rust EVM implementation. \ No newline at end of file diff --git a/documentation/src/crates/interpreter/instruction_result.md b/documentation/src/crates/interpreter/instruction_result.md index b371b6261d..b2b6b4e0c1 100644 --- a/documentation/src/crates/interpreter/instruction_result.md +++ b/documentation/src/crates/interpreter/instruction_result.md @@ -1,80 +1,19 @@ # The `instruction_result.rs` Module -The `instruction_result.rs` module of this Rust EVM implementation includes the definitions of the enumerations `InstructionResult` and `SuccessOrHalt`, which represent the possible outcomes of EVM instruction execution, and functions to work with these types. +The `instruction_result.rs` module of this Rust EVM implementation includes the definitions of the `InstructionResult` and `SuccessOrHalt` enum, which represent the possible outcomes of EVM instruction execution, and functions to work with these types. -## `InstructionResult` Enum +- `InstructionResult` Enum -The `InstructionResult` enum categorizes the different types of results that can arise from executing an EVM instruction. This enumeration uses the `#[repr(u8)]` attribute, meaning its variants have an explicit storage representation of an 8-bit unsigned integer. + The `InstructionResult` enum categorizes the different types of results that can arise from executing an EVM instruction. This enumeration uses the `#[repr(u8)]` attribute, meaning its variants have an explicit storage representation of an 8-bit unsigned integer. The different instruction results represent outcomes such as successful continuation, stop, return, self-destruction, reversion, deep call, out of funds, out of gas, and various error conditions. -```rust -pub enum InstructionResult { - Continue = 0x00, - Stop = 0x01, - Return = 0x02, - SelfDestruct = 0x03, - Revert = 0x20, - CallTooDeep = 0x21, - OutOfFund = 0x22, - OutOfGas = 0x50, - // more variants... -} -``` +- `SuccessOrHalt` Enum -The different instruction results represent outcomes such as successful continuation, stop, return, self-destruction, reversion, deep call, out of funds, out of gas, and various error conditions. + The `SuccessOrHalt` enum represents the outcome of a transaction execution, distinguishing successful operations, reversion, halting conditions, fatal external errors, and internal continuation. It also provides several methods to check the kind of result and to extract the value of the successful evaluation or halt. -## `SuccessOrHalt` Enum +- `From for SuccessOrHalt` Implementation -The `SuccessOrHalt` enum represents the outcome of a transaction execution, distinguishing successful operations, reversion, halting conditions, fatal external errors, and internal continuation. + This implementation provides a way to convert an `InstructionResult` into a `SuccessOrHalt`. It maps each instruction result to the corresponding `SuccessOrHalt` variant. -```rust -pub enum SuccessOrHalt { - Success(Eval), - Revert, - Halt(Halt), - FatalExternalError, - InternalContinue, -} -``` +- Macros for returning instruction results -It also provides several methods to check the kind of result and to extract the value of the successful evaluation or halt. - -## `From for SuccessOrHalt` Implementation - -This implementation provides a way to convert an `InstructionResult` into a `SuccessOrHalt`. It maps each instruction result to the corresponding `SuccessOrHalt` variant. - -```rust -impl From for SuccessOrHalt { - fn from(result: InstructionResult) -> Self { - match result { - InstructionResult::Continue => Self::InternalContinue, - InstructionResult::Stop => Self::Success(Eval::Stop), - // more match arms... - } - } -} -``` - -## Macros for returning instruction results - -Finally, the module provides two macros, `return_ok!` and `return_revert!`, which simplify returning some common sets of instruction results. - -```rust -#[macro_export] -macro_rules! return_ok { - () => { - InstructionResult::Continue - | InstructionResult::Stop - | InstructionResult::Return - | InstructionResult::SelfDestruct - }; -} - -#[macro_export] -macro_rules! return_revert { - () => { - InstructionResult::Revert | InstructionResult::CallTooDeep | InstructionResult::OutOfFund - }; -} -``` - -In summary, the `instruction_result.rs` module is essential to the interpretation of EVM instructions, as it outlines the possible outcomes and provides means to handle these outcomes within the Rust EVM implementation. + The module provides two macros, `return_ok!` and `return_revert!`, which simplify returning some common sets of instruction results. diff --git a/documentation/src/crates/interpreter/instructions.md b/documentation/src/crates/interpreter/instructions.md index c69b660e91..7835718131 100644 --- a/documentation/src/crates/interpreter/instructions.md +++ b/documentation/src/crates/interpreter/instructions.md @@ -1,59 +1,15 @@ # The `instruction.rs` Module in the Rust Ethereum Virtual Machine (EVM) -The `instruction.rs` module in this Rust EVM implementation plays a key role in interpreting EVM bytecode. It provides the definition of the `Instruction` struct, as well as the `Opcode` enumeration and the `execute` function, which runs a specific instruction. +The `instruction.rs` module defines interpretation mappings for EVM bytecode. It provides the definition of the `Instruction` struct, as well as the `Opcode` enumeration and the `execute` function, which runs a specific instruction. ## `Opcode` Enum The `Opcode` enum represents the opcodes that are available in the Ethereum Virtual Machine. Each variant corresponds to an operation that can be performed, such as addition, multiplication, subtraction, jumps, and memory operations. -```rust -pub enum Opcode { - STOP = 0x00, - ADD, - MUL, - SUB, - // more variants... -} -``` - ## `Instruction` Struct The `Instruction` struct represents a single instruction in the EVM. It contains the opcode, which is the operation to be performed, and a list of bytes representing the operands for the instruction. -```rust -pub struct Instruction { - opcode: Opcode, - bytes: Vec, -} -``` - -## Submodules - -The `instruction.rs` module also contains several submodules. These submodules are responsible for executing specific categories of operations: - -- `arithmetic`: This submodule handles arithmetic operations like addition, multiplication, subtraction, etc. -- `bitwise`: This submodule handles bitwise operations such as `bitand`, `bitor`, and `not`. -- `control`: Manages control flow operations for the instruction pointer such as jumps. -- `host`: Handles interactions with the EVM environment with functions like `call`, `create`, and `selfdestruct`. -- `host_env`: Manages interactions with host environment variables such as `chainid` and `gasprice`. -- `memory`: Handles memory operations such as reads and writes via `mload` and `mstore`. -- `opcode`: Gives the implementation of individual opcodes and defines the ISA for the EVM. -- `stack`: Handles the stack machine interface for the EVM with functions like `push`, `pop`, and `swap`. -- `system`: Handles the data for calldata interaction with the EVM and implements functions like `address`, `caller`, and `calldataload`. - ## `execute` Function -The `execute` function interprets an instruction. It uses the opcode to determine what operation to perform and then performs the operation using the operands in the instruction. - -```rust -pub fn execute(instruction: Instruction) -> Result<(), EvmError> { - match instruction.opcode { - Opcode::STOP => Ok(()), - Opcode::ADD => arithmetic::add(instruction.bytes), - Opcode::MUL => arithmetic::mul(instruction.bytes), - // more match arms... - } -} -``` - -In conclusion, the `instruction.rs` module is a key part of the EVM implementation in Rust. It is responsible for defining the instructions that can be executed and the function that interprets these instructions. \ No newline at end of file +The `execute` function interprets an instruction. It uses the opcode to determine what operation to perform and then performs the operation using the operands in the instruction. \ No newline at end of file diff --git a/documentation/src/crates/precompile/point_evaluation.md b/documentation/src/crates/precompile/point_evaluation.md new file mode 100644 index 0000000000..1b69919280 --- /dev/null +++ b/documentation/src/crates/precompile/point_evaluation.md @@ -0,0 +1,6 @@ +# Point Evaluation Precompile + +This precompile is introduced in [EIP4844](https://eips.ethereum.org/EIPS/eip-4844) and is used to verify KZG commitments of blobspace. The precompile allows for efficient verification of commitments to blog transactions. The blob-space transaction contains a large amount of data that cannot be accessed by EVM execution, but has a commitment that can be accessed and verified. The EIP is designed to be forward compatible with danksharding architecture while giving L2s access to cheaper L1 commitments. This precompiled contract resides at the hardcoded Ethereum address `0x000000000000000000000000000000000000000A`. + + +A useful resource is the python refrence implementation for the precompile, which can be found [here](https://github.com/ethereum/consensus-specs/blob/86fb82b221474cc89387fa6436806507b3849d88/specs/deneb/polynomial-commitments.md). This implementation uses the [c-kzg](https://github.com/ethereum/c-kzg-4844) audited foriegn function interface bindings from the Ethereum Foundation. \ No newline at end of file diff --git a/documentation/src/crates/primitives/bits.md b/documentation/src/crates/primitives/bits.md index fb4ca94f41..e30b1d9e24 100644 --- a/documentation/src/crates/primitives/bits.md +++ b/documentation/src/crates/primitives/bits.md @@ -1,15 +1,13 @@ -# bits +# Bits -This module houses the definitions for fixed-size bit arrays, `B160` and `B256`, showcasing its role in managing bits-related operations, to represent 256-bit and 160-bit fixed-size hashes respectively. These are defined using the `construct_fixed_hash!` macro from the `fixed_hash` crate. +This module houses the definitions for fixed-size bit arrays, `B160` and `B256`, to represent 256-bit and 160-bit fixed-size hashes respectively. These are defined using the `construct_fixed_hash!` macro from the `fixed_hash` crate. The `AsRef` and `Deref` traits from `derive_more` crate are derived for both of these structures, providing convenient methods for converting these types to and from references of their underlying data. -The `Arbitrary` trait from the `arbitrary` crate and the `PropTestArbitrary` trait from `proptest_derive` crate are derived conditionally when either testing or the "arbitrary" feature is enabled. These traits are used for property testing, a form of testing where random inputs are generated and used to validate certain properties of your code. +The `Arbitrary` trait from the `arbitrary` crate and the `PropTestArbitrary` trait from `proptest_derive` crate are derived conditionally when either testing or the "arbitrary" feature is enabled. -The code also provides conversions between `B256`, `B160` and various other types such as `u64`, `primitive_types::H256`, `primitive_types::H160`, `primitive_types::U256`, and `ruint::aliases::U256`. The `impl` From blocks specify how to convert from one type to another. +The module provides conversions between `B256`, `B160` and various other types such as `u64`, `primitive_types::H256`, `primitive_types::H160`, `primitive_types::U256`, and `ruint::aliases::U256`. The `impl` From blocks specify how to convert from one type to another. `impl_fixed_hash_conversions!` macro is used to define conversions between `B256` and `B160` types. If the "serde" feature is enabled, the Serialize and Deserialize traits from the serde crate are implemented for `B256` and `B160` using a custom serialization method that outputs/reads these types as hexadecimal strings. This includes a custom serialization/deserialization module for handling hexadecimal data. - -This module (serialize) provides functionality to serialize a slice of bytes to a hexadecimal string, and deserialize a hexadecimal string to a byte vector with size checks. It handles both "0x" prefixed and non-prefixed hexadecimal strings. It also provides functions to convert raw bytes to hexadecimal strings and vice versa, handling potential errors related to non-hexadecimal characters. The module also defines the `ExpectedLen` enum which is used to specify the expected length of the byte vectors during deserialization. diff --git a/documentation/src/crates/primitives/bytecode.md b/documentation/src/crates/primitives/bytecode.md index 07ac86f6d7..03f7356a20 100644 --- a/documentation/src/crates/primitives/bytecode.md +++ b/documentation/src/crates/primitives/bytecode.md @@ -1,6 +1,5 @@ -# bytecode +# Bytecode -Entrusted with tasks related to EVM bytecode, handling operations like parsing, interpretation, and transformation. This module defines structures and methods to manipulate Ethereum bytecode and manage its state. It's built around three main components: `JumpMap`, `BytecodeState`, and `Bytecode`. The `JumpMap` structure stores a map of valid `jump` destinations within a given Ethereum bytecode sequence. It is essentially an `Arc` (Atomic Reference Counter) wrapping a `BitVec` (bit vector), which can be accessed and modified using the defined methods, such as `as_slice()`, `from_slice()`, and `is_valid()`. diff --git a/documentation/src/crates/primitives/constants.md b/documentation/src/crates/primitives/constants.md index 880319df2c..893b067f09 100644 --- a/documentation/src/crates/primitives/constants.md +++ b/documentation/src/crates/primitives/constants.md @@ -1,7 +1,7 @@ -# constants +# Constants -Holds constant values used throughout the system. This module defines important constants that help limit and manage resources in the Ethereum Virtual Machine (EVM). These limits are integral to maintaining the efficiency, security, and future extensibility of the EVM. The constants include `STACK_LIMIT` and `CALL_STACK_LIMIT`, which restrict the size of the interpreter stack and the EVM call stack, respectively. Both are set to 1024. +Holds constant values used throughout the system. This module defines important constants that help limit and manage resources in the Ethereum Virtual Machine (EVM). The constants include `STACK_LIMIT` and `CALL_STACK_LIMIT`, which restrict the size of the interpreter stack and the EVM call stack, respectively. Both are set to 1024. -A vital constant established here is `MAX_CODE_SIZE`, which is set according to [EIP-170](https://eips.ethereum.org/EIPS/eip-170)'s specification. [EIP-170](https://eips.ethereum.org/EIPS/eip-170) imposes a maximum limit on the contract code size to mitigate potential vulnerabilities and inefficiencies in Ethereum. Without this cap, the act of calling a contract can trigger costly operations that scale with the size of the contract's code. These operations include reading the code from disk, preprocessing the code for VM execution, and adding data to the block's proof-of-validity. By implementing `MAX_CODE_SIZE` (set to `0x6000` or ~25kb), the EVM ensures that the cost of these operations remains manageable, even under high gas levels that could be encountered in the future. [EIP-170](https://eips.ethereum.org/EIPS/eip-170)'s implementation thus offers crucial protection against potential DoS attacks and maintains efficiency, especially for future light clients verifying proofs of validity or invalidity. +The module also defines `MAX_CODE_SIZE`, which is set according to [EIP-170](https://eips.ethereum.org/EIPS/eip-170)'s specification. [EIP-170](https://eips.ethereum.org/EIPS/eip-170) imposes a maximum limit on the contract code size to mitigate potential vulnerabilities and inefficiencies in Ethereum. Without this cap, the act of calling a contract can trigger costly operations that scale with the size of the contract's code. These operations include reading the code from disk, preprocessing the code for VM execution, and adding data to the block's proof-of-validity. By implementing `MAX_CODE_SIZE` (set to `0x6000` or ~25kb), the EVM ensures that the cost of these operations remains manageable, even under high gas levels that could be encountered in the future. [EIP-170](https://eips.ethereum.org/EIPS/eip-170)'s implementation thus offers crucial protection against potential DoS attacks and maintains efficiency, especially for future light clients verifying proofs of validity or invalidity. -Another essential constant defined here is `MAX_INITCODE_SIZE`, set in accordance with [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860). [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860) extends EIP-170 by introducing a maximum size limit for initialization code (initcode) and enforcing a gas charge for every 32-byte chunk of initcode, to account for the cost of jump destination analysis. Before [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860), initcode analysis during contract creation wasn't metered, nor was there an upper limit for its size, resulting in potential inefficiencies and vulnerabilities. By setting `MAX_INITCODE_SIZE` to 2 \* `MAX_CODE_SIZE` and introducing the said gas charge, [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860) ensures that the cost of initcode analysis scales proportionately with its size. This constant, therefore, facilitates fair charging, simplifies EVM engines by setting explicit limits, and helps to create an extendable cost system for the future. +Another constant defined here is `MAX_INITCODE_SIZE`, set in accordance with [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860). [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860) extends EIP-170 by introducing a maximum size limit for initialization code (initcode) and enforcing a gas charge for every 32-byte chunk of initcode, to account for the cost of jump destination analysis. Before [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860), initcode analysis during contract creation wasn't metered, nor was there an upper limit for its size, resulting in potential inefficiencies and vulnerabilities. By setting `MAX_INITCODE_SIZE` to 2 \* `MAX_CODE_SIZE` and introducing the said gas charge, [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860) ensures that the cost of initcode analysis scales proportionately with its size. This constant, therefore, facilitates fair charging, simplifies EVM engines by setting explicit limits, and helps to create an extendable cost system for the future. diff --git a/documentation/src/crates/primitives/database.md b/documentation/src/crates/primitives/database.md index 65003c7e47..e28e08cd30 100644 --- a/documentation/src/crates/primitives/database.md +++ b/documentation/src/crates/primitives/database.md @@ -1,6 +1,6 @@ -# database +# Database -As its name suggests, it's responsible for database operations. This module is where the blockchain's state persistence is managed. +Responsible for database operations. This module is where the blockchain's state persistence is managed. The module defines three primary traits (`Database`, `DatabaseCommit`, and `DatabaseRef`), a structure `RefDBWrapper`, and their associated methods. The `Database` trait defines an interface for mutable interaction with the database. It has a generic associated type `Error` to handle different kinds of errors that might occur during these interactions. It provides methods to retrieve basic account information (`basic`), retrieve account code by its hash (`code_by_hash`), retrieve the storage value of an address at a certain index (`storage`), and retrieve the block hash for a certain block number (`block_hash`). diff --git a/documentation/src/crates/primitives/environment.md b/documentation/src/crates/primitives/environment.md index 82b7c41d00..8c5469bd3c 100644 --- a/documentation/src/crates/primitives/environment.md +++ b/documentation/src/crates/primitives/environment.md @@ -1,4 +1,4 @@ -# environment +# Environment A significant module that manages the execution environment of the EVM. The module containts objects and methods associated with processing transactions and blocks within such a blockchain environment. It defines several structures: `Env`, `BlockEnv`, `TxEnv`, `CfgEnv`, `TransactTo`, and `CreateScheme`. These structures contain various fields representing the block data, transaction data, environmental configurations, transaction recipient details, and the method of contract creation respectively. diff --git a/documentation/src/crates/primitives/log.md b/documentation/src/crates/primitives/log.md index d01ed568ad..f24e319939 100644 --- a/documentation/src/crates/primitives/log.md +++ b/documentation/src/crates/primitives/log.md @@ -1,4 +1,4 @@ -# log +# Log This piece of Rust code defines a structure called Log which represents an Ethereum log entry. These logs are integral parts of the Ethereum network and are typically produced by smart contracts during execution. Each Log has three components: diff --git a/documentation/src/crates/primitives/precompile.md b/documentation/src/crates/primitives/precompile.md index 6b84532892..965068d4d8 100644 --- a/documentation/src/crates/primitives/precompile.md +++ b/documentation/src/crates/primitives/precompile.md @@ -1,6 +1,6 @@ # precompile -This module implements precompiled contracts in the EVM, adding a layer of pre-set functionalities. These are documented in the prior section. The module defines the types and the enum that are used to handle precompiled contracts. +This module implements precompiled contracts in the EVM, adding a layer of pre-set functionalities. These are documented in more detail in the next section. The module defines the types and the enum that are used to handle precompiled contracts. `PrecompileResult`: This is a type alias for a `Result` type. The `Ok` variant of this type contains a tuple (`u64`, `Vec`), where the `u64` integer likely represents gas used by the precompiled contract, and the `Vec` holds the output data. The Err variant contains a PrecompileError. diff --git a/documentation/src/crates/primitives/result.md b/documentation/src/crates/primitives/result.md index d14eef45d1..647a35aa48 100644 --- a/documentation/src/crates/primitives/result.md +++ b/documentation/src/crates/primitives/result.md @@ -1,4 +1,4 @@ -# result +# Result At the core of this module is the `ExecutionResult` enum, which describes the possible outcomes of an EVM execution: `Success`, `Revert`, and `Halt`. `Success` represents a successful transaction execution, and it holds important information such as the reason for `success` (an Eval enum), the gas used, the gas refunded, a vector of logs (`Vec`), and the output of the execution. This aligns with the stipulation in [EIP-658](https://eips.ethereum.org/EIPS/eip-658) that introduces a status code in the receipt of a transaction, indicating whether the top-level call was successful or failed. diff --git a/documentation/src/crates/primitives/specifications.md b/documentation/src/crates/primitives/specifications.md index 87a101979b..7b3873fb02 100644 --- a/documentation/src/crates/primitives/specifications.md +++ b/documentation/src/crates/primitives/specifications.md @@ -1,4 +1,4 @@ -# specifications +# Specifications Holds data related to Ethereum's technical specifications, serving as a reference point for Ethereum's rules and procedures obtained from the [Ethereum execution specifications](https://github.com/ethereum/execution-specs). The module is primarily used to enumerate and handle Ethereum's network upgrades or "hard forks" within the Ethereum Virtual Machine (EVM). These hard forks are referred to as `SpecId` in the code, representing different phases of Ethereum's development. diff --git a/documentation/src/crates/primitives/state.md b/documentation/src/crates/primitives/state.md index 084e6ef723..ce6cc83c4e 100644 --- a/documentation/src/crates/primitives/state.md +++ b/documentation/src/crates/primitives/state.md @@ -1,4 +1,4 @@ -# state +# State Manages the EVM's state, including account balances, contract storage, and more. diff --git a/documentation/src/crates/primitives/utils.md b/documentation/src/crates/primitives/utils.md index 00a364ca3c..bd6a1261ae 100644 --- a/documentation/src/crates/primitives/utils.md +++ b/documentation/src/crates/primitives/utils.md @@ -1,4 +1,4 @@ -# utilities +# Utilities This Rust module provides utility functions and constants for handling Keccak hashing (used in Ethereum) and creating Ethereum addresses via legacy and `CREATE2` methods. It also includes serialization and deserialization methods for hexadecimal strings representing byte arrays. diff --git a/documentation/src/crates/revm.md b/documentation/src/crates/revm.md index 071e49efd0..d85be6329b 100644 --- a/documentation/src/crates/revm.md +++ b/documentation/src/crates/revm.md @@ -4,30 +4,30 @@ The `crate` is focused on the implementation of Ethereum Virtual Machine (EVM) i Modules: -- [db](#): This module includes structures and functions for database interaction. -- [evm](#): This module is concerned with the Ethereum Virtual Machine (EVM) implementation. -- [evm_impl](#): This module likely includes more specific or complex implementations related to the EVM. -- [inspector](#): This module introduces the `Inspector` trait and its implementations for observing the EVM execution. -- [journaled_state](#): This module manages the state of the EVM and implements a journaling system to handle changes and reverts. +- `db`: This module includes structures and functions for database interaction. +- `evm`: This module contains a Struct that takes Database and enabled transact to update state directly to database. Additionally it allows user to set all environment parameters. +- `evm_impl`: This module includes more specific implementations related to the EVM regarding state transitions. +- `inspector`: This module introduces the `Inspector` trait and its implementations for observing the EVM execution. +- `journaled_state`: This module manages the state of the EVM and implements a journaling system to handle changes and reverts. External Crates: -- alloc: The alloc crate is used to provide the ability to allocate memory on the heap. It's a part of Rust's standard library that can be used in environments without a full host OS. +- `alloc`: The alloc crate is used to provide the ability to allocate memory on the heap. It's a part of Rust's standard library that can be used in environments without a full host OS. Constants: -- USE_GAS: This constant determines whether gas measurement should be used. It's set to false if the no_gas_measuring feature is enabled. +- `USE_GAS`: This constant determines whether gas measurement should be used. It's set to false if the no_gas_measuring feature is enabled. Re-exported Crates: -- revm_precompile: This crate is re-exported, likely providing the precompiled contracts used in the EVM implementation. -- revm_interpreter: This crate is re-exported, providing the execution engine for EVM opcodes. -- revm_interpreter::primitives: This module from the `revm_interpreter` crate is re-exported, providing primitive types or functionality used in the EVM implementation. +- `revm_precompile`: This crate is re-exported, providing the precompiled contracts used in the EVM implementation. +- `revm_interpreter`: This crate is re-exported, providing the execution engine for EVM opcodes. +- `revm_interpreter`::primitives: This module from the `revm_interpreter` crate is re-exported, providing primitive types or functionality used in the EVM implementation. Re-exported Types: -- Database, DatabaseCommit, InMemoryDB: These types from the `db` module are re-exported for handling the database operations. -- EVM: The EVM struct from the `evm` module is re-exported, serving as the main interface to the EVM implementation. -- EVMData: The EVMData struct from the `evm_impl` module is re-exported, likely providing data structures to encapsulate EVM execution data. -- JournalEntry, JournaledState: These types from the `journaled_state` module are re-exported, providing the journaling system for the EVM state. -- inspectors, Inspector: The `Inspector` trait and its implementations from the `inspector` module are re-exported for observing the EVM execution. +- `Database`, `DatabaseCommit`, `InMemoryDB`: These types from the `db` module are re-exported for handling the database operations. +- `EVM`: The `EVM` struct from the `evm` module is re-exported, serving as the main interface to the EVM implementation. +- `EVMData`: The `EVMData` struct from the `evm_impl` module is re-exported, likely providing data structures to encapsulate EVM execution data. +- `JournalEntry`, `JournaledState`: These types from the `journaled_state` module are re-exported, providing the journaling system for the EVM state. +- `inspectors`, `Inspector`: The `Inspector` trait and its implementations from the `inspector` module are re-exported for observing the EVM execution. diff --git a/documentation/src/crates/revm/evm.md b/documentation/src/crates/revm/evm.md index 128b0a36f7..c63d6f70e2 100644 --- a/documentation/src/crates/revm/evm.md +++ b/documentation/src/crates/revm/evm.md @@ -2,19 +2,12 @@ This document provides the documentation for the `EVM` module. -## Struct `EVM` +## The `EVM` -The primary struct in this module is `EVM`. The `EVM` struct takes a database and enables `transact` to update the state directly to the database. Additionally, it allows the user to set all environment parameters. +The primary struct in this module is `EVM`. The EVM struct is generic over a type DB. This means that when you use the EVM struct, you can specify the type that DB should represent. It adds flexibility to the struct, allowing it to store different types of databases or data structures in the db field depending on the use case. The `EVM` struct enables `transact` to update the state directly to the database. Additionally, it allows the user to set all environment parameters. -```rust -#[derive(Clone)] -pub struct EVM { - pub env: Env, - pub db: Option, -} -``` -The parameters that can be set are divided between Config, Block, and Transaction (tx). For transacting on the EVM, you can call `transact_commit` that will automatically apply changes to the database. +The parameters that can be set are divided between `Config`, `Block`, and `Transaction` (tx). For transacting on the EVM, you can call `transact_commit` that will automatically apply changes to the database. ## Database Abstractions @@ -24,57 +17,3 @@ You can implement the traits Database, DatabaseRef or Database + DatabaseCommit - `DatabaseRef`: Takes a reference on the object, this is useful if you only have a reference on the state and don't want to update anything on it. It enables `transact_ref` and `inspect_ref` functions. - `Database + DatabaseCommit`: Allows directly committing changes of a transaction. It enables `transact_commit` and `inspect_commit` functions. -## Functions - -Below are the key functions provided by the `EVM` struct. - -### `transact_commit()` - -This function is used to execute a transaction and apply the result to the database. - -```rust -pub fn transact_commit(&mut self) -> Result> { - let ResultAndState { result, state } = self.transact()?; - self.db.as_mut().unwrap().commit(state); - Ok(result) -} -``` - -### `inspect_commit()` - -This function is used to inspect a transaction and commit changes to the database. - -```rust -pub fn inspect_commit>( - &mut self, - inspector: INSP, -) -> Result> { - let ResultAndState { result, state } = self.inspect(inspector)?; - self.db.as_mut().unwrap().commit(state); - Ok(result) -} -``` - -### `transact()` - -This function executes a transaction without writing to the DB and returns the change state. - -```rust -pub fn transact(&mut self) -> EVMResult { - if let Some(db) = self.db.as_mut() { - let mut noop = NoOpInspector {}; - let out = evm_inner::(&mut self.env, db, &mut noop).transact(); - out - } else { - panic!("Database needs to be set"); - } -} -``` - -### `inspect()` - -This function executes a transaction with a given inspector, without writing to the DB, and returns the change state. - -```rust -pub fn inspect>(&mut -``` diff --git a/documentation/src/crates/revm/evm_impl.md b/documentation/src/crates/revm/evm_impl.md index d782811efb..08d849e61b 100644 --- a/documentation/src/crates/revm/evm_impl.md +++ b/documentation/src/crates/revm/evm_impl.md @@ -2,112 +2,91 @@ This module implements the Ethereum Virtual Machine (EVM), a stack-based virtual machine that executes Ethereum smart contracts. -## `run_interpreter` +- `run_interpreter` -This function is responsible for setting up and running the interpreter for a specific contract. + This method is responsible for setting up and running the interpreter for a specific contract. -- `contract`: A `Contract` instance that the interpreter will execute. -- `gas_limit`: A `u64` that determines the maximum amount of gas that the execution can consume. -- `is_static`: A boolean flag indicating if the execution is static. Static executions cannot modify the state. + - `contract`: A `Contract` instance that the interpreter will execute. + - `gas_limit`: A `u64` that determines the maximum amount of gas that the execution can consume. + - `is_static`: A boolean flag indicating if the execution is static. Static executions cannot modify the state. -The function returns a tuple containing the result of the execution and the interpreter instance. The result is an `InstructionResult` enumeration value that indicates if the execution was successful or if an error occurred. + The method returns a tuple containing the result of the execution and the interpreter instance. The result is an `InstructionResult` enumeration value that indicates if the execution was successful or if an error occurred. -For example + This creates a contract with a specific bytecode and a gas price, then runs the interpreter on this contract with a specified gas limit. The is_static flag is set to false which means the execution can modify the state. The stack machine implements the following instructions: -```rust -let contract = Contract::new(bytecode, U256::from(10)); -let gas_limit = 1000000_u64; -let is_static = false; -let (exit_reason, interpreter) = evm.run_interpreter(contract, gas_limit, is_static); -``` +- `call_precompile` -This creates a contract with a specific bytecode and a gas price, then runs the interpreter on this contract with a specified gas limit. The is_static flag is set to false which means the execution can modify the state. + This method handles the execution of precompiled contracts. These are a special set of contracts that are part of the Ethereum protocol and implemented in native code for efficiency. -## `call_precompile` + - `gas`: A `Gas` instance representing the amount of gas available for execution. + - `contract`: The address of the precompiled contract in the form of a `B160` instance. + - `input_data`: The input data for the contract as a `Bytes` instance. -This function handles the execution of precompiled contracts. These are a special set of contracts that are part of the Ethereum protocol and implemented in native code for efficiency. + The method returns a tuple containing the result of the contract execution, the remaining gas, and any output data as a `Bytes` instance. -- `gas`: A `Gas` instance representing the amount of gas available for execution. -- `contract`: The address of the precompiled contract in the form of a `B160` instance. -- `input_data`: The input data for the contract as a `Bytes` instance. +- `call_inner` -The function returns a tuple containing the result of the contract execution, the remaining gas, and any output data as a `Bytes` instance. + This method performs a contract call within the EVM. -For example + - `inputs`: A mutable reference to a `CallInputs` instance, which contains all the necessary information for the contract call. -```rust -let gas = Gas::new(1000000); -let contract = B160::zero(); -let input_data = Bytes::from("input data"); -let (exit_reason, gas, output) = evm.call_precompile(gas, contract, input_data); -``` + The method returns a tuple containing the result of the call (as an `InstructionResult`), the remaining gas (as a `Gas` instance), and any output data from the call (as a `Bytes` instance). -This executes a precompiled contract with a specified gas limit and input data. +## Host Implementation -## `call_inner` +The `Host` trait provides an interface that allows the EVM to interact with the external world. It contains methods to access environmental information, manipulate account balances, and interact with contract code and storage. -This function performs a contract call within the EVM. +The `EVMImpl` struct implements this `Host` trait. -- `inputs`: A mutable reference to a `CallInputs` instance, which contains all the necessary information for the contract call. +- `step` & `step_end` -The function returns a tuple containing the result of the call (as an `InstructionResult`), the remaining gas (as a `Gas` instance), and any output data from the call (as a `Bytes` instance). + These methods are used to control the interpreter's execution. They move the interpreter forward one step, allowing the user to inspect the state of the interpreter after each individual operation. + These control the execution of the interpreter, allowing step-by-step execution and inspection. -for example +- `env` -```rust - let mut inputs = CallInputs { - gas_limit: 1000000, - // other parameters... -}; -let (exit_reason, gas, output) = evm.call_inner(&mut inputs); -``` + This method returns a mutable reference to the environment information that the EVM uses for its execution. The `Env` struct contains details about the current block, such as the timestamp, block number, difficulty, and gas limit. -## Host Implementation - -The `Host` trait provides an interface that allows the EVM to interact with the external world. It contains methods to access environmental information, manipulate account balances, and interact with contract code and storage. +- `block_hash` -The `EVMImpl` struct implements this `Host` trait. The methods provided by this trait interface are as follows: + This method retrieves the hash of a block given its number. It's typically used within smart contracts for actions like random number generation. -## `step` & `step_end` +- `load_account` -These methods are used to control the interpreter's execution. They move the interpreter forward one step, allowing the user to inspect the state of the interpreter after each individual operation. + This method loads the account associated with a given address and returns information about the account's existence and if it's a contract. -for example +- `balance` -```rust -let mut interpreter = Interpreter::new(contract, gas_limit, is_static); -let result = evm.step(&mut interpreter); -let result_end = evm.step_end(&mut interpreter, result); -``` + This method retrieves the balance of an Ethereum account given its address. It returns a tuple containing the balance and a boolean indicating whether the account was "cold" (accessed for the first time in the current transaction). -These control the execution of the interpreter, allowing step-by-step execution and inspection. +- `code` -## `env` + This method retrieves the bytecode of a given address. It returns a tuple containing the bytecode and a boolean indicating whether the account was "cold". -This method returns a mutable reference to the environment information that the EVM uses for its execution. The `Env` struct contains details about the current block, such as the timestamp, block number, difficulty, and gas limit. +- `code_hash` -## `block_hash` + This method retrieves the code_hash at a given address. It returns a tuple containing the hash and a boolean indicating whether the account was "cold". -This method retrieves the hash of a block given its number. It's typically used within smart contracts for actions like random number generation. +- `sload` & `sstore` -## `load_account` + These methods interact with the contract storage. The `sload` method retrieves a value from contract storage, while `sstore` sets a value in contract storage. -This method loads the account associated with a given address and returns information about the account's existence and if it's a contract. +- `tload` & `tstore` -## `balance` + As defined in [EIP1153](https://eips.ethereum.org/EIPS/eip-1153), for transiant storage reads and writes. -This method retrieves the balance of an Ethereum account given its address. It returns a tuple containing the balance and a boolean indicating whether the account was "cold" (accessed for the first time in the current transaction). +- `log` -## `code` + This method is used to create log entries, which are a way for contracts to produce output that external observers (like dapps or the frontend of a blockchain explorer) can listen for and react to. -This method retrieves the bytecode of a contract given its address. It returns a tuple containing the bytecode and a boolean indicating whether the account was "cold". +- `selfdestruct` -## `sload` & `sstore` + The selfdestruct method attempts to terminate the specified address, transferring its remaining balance to a given target address. If the INSPECT constant is true, the self-destruction event is observed or logged via an inspector. The method returns an Option, encapsulating the outcome of the operation: Some(SelfDestructResult) on success and None if an error occurs, with the error being stored internally for later reference. -These methods interact with the contract storage. The `sload` method retrieves a value from contract storage, while `sstore` sets a value in contract storage. +- `create` -## `log` + The create method initiates the creation of a contract with the provided CreateInputs. If the INSPECT constant is true, the creation process is observed or logged using an inspector, both at the start and end of the creation. The method returns a tuple consisting of the operation's result (InstructionResult), the optional address (Option) of the newly created contract, the amount of gas consumed (Gas), and the output data (Bytes). If the inspector intervenes and determines the instruction shouldn't continue, an early return occurs with the observed outcomes. -This method is used to create log entries, which are a way for contracts to produce output that external observers (like dapps or the frontend of a blockchain explorer) can listen for and react to. +- `call` -## `selfdestruct` + The call method manages a contract invocation using the provided CallInputs. If the INSPECT constant is active, the call event is observed or logged via an inspector before execution. The method yields a tuple representing the outcome of the call: the result status (InstructionResult), the consumed gas (Gas), and the output data (Bytes). If the inspector suggests early termination, the method returns immediately with the observed results. Otherwise, the main call execution is processed, and the outcomes, either raw or observed, are returned accordingly. \ No newline at end of file diff --git a/documentation/src/crates/revm/inspector.md b/documentation/src/crates/revm/inspector.md index c220761d7a..753acb08e4 100644 --- a/documentation/src/crates/revm/inspector.md +++ b/documentation/src/crates/revm/inspector.md @@ -15,62 +15,6 @@ There are several built-in inspectors in this module: The `Inspector` trait defines a set of methods that are called during various stages of EVM execution. You can implement this trait to create your own custom inspectors. -```rust -pub trait Inspector { - fn initialize_interp( - &mut self, - _interp: &mut Interpreter, - _data: &mut EVMData<'_, DB>, - ) -> InstructionResult; - fn step( - &mut self, - _interp: &mut Interpreter, - _data: &mut EVMData<'_, DB>, - ) -> InstructionResult; - fn log( - &mut self, - _evm_data: &mut EVMData<'_, DB>, - _address: &B160, - _topics: &[B256], - _data: &Bytes, - ); - fn step_end( - &mut self, - _interp: &mut Interpreter, - _data: &mut EVMData<'_, DB>, - _eval: InstructionResult, - ) -> InstructionResult; - fn call( - &mut self, - _data: &mut EVMData<'_, DB>, - _inputs: &mut CallInputs, - ) -> (InstructionResult, Gas, Bytes); - fn call_end( - &mut self, - _data: &mut EVMData<'_, DB>, - _inputs: &CallInputs, - remaining_gas: Gas, - ret: InstructionResult, - out: Bytes, - ) -> (InstructionResult, Gas, Bytes); - fn create( - &mut self, - _data: &mut EVMData<'_, DB>, - _inputs: &mut CreateInputs, - ) -> (InstructionResult, Option, Gas, Bytes); - fn create_end( - &mut self, - _data: &mut EVMData<'_, DB>, - _inputs: &CreateInputs, - ret: InstructionResult, - address: Option, - remaining_gas: Gas, - out: Bytes, - ) -> (InstructionResult, Option, Gas, Bytes); - fn selfdestruct(&mut self, _contract: B160, _target: B160); -} -``` - Each of these methods is called at different stages of the execution of a transaction, and they can be used to monitor, debug, or modify the execution of the EVM. For example, the `step` method is called on each step of the interpreter, and the `log` method is called when a log is emitted. @@ -92,10 +36,4 @@ To use an inspector, you need to implement the `Inspector` trait. For each metho For example, if you wanted to log all `SELFDESTRUCT` operations, you could implement the selfdestruct method to write a log entry every time a contract initiates a `selfdestruct` operation. -```rust -fn selfdestruct(&mut self, contract: B160, target: B160) { - println!("Contract {} self destructed, funds sent to {}", contract, target); -} -``` - Remember, the methods in the `Inspector` trait are optional to implement; if you do not need specific functionality, you can use the provided default implementations. diff --git a/documentation/src/crates/revm/journaled_state.md b/documentation/src/crates/revm/journaled_state.md index 3065507ddb..aa36a59f77 100644 --- a/documentation/src/crates/revm/journaled_state.md +++ b/documentation/src/crates/revm/journaled_state.md @@ -1,14 +1,14 @@ # Journaled State The `journaled_state` module of the `revm` crate provides a state management -implementation for Ethereum-style accounts in a blockchain. It includes support for +implementation for Ethereum-style accounts. It includes support for various actions such as self-destruction of accounts, initial account loading, account state modification, and logging. It also contains several important utility functions such as `is_precompile`. This module is built around the `JournaledState` structure, which encapsulates the entire state of the blockchain. `JournaledState` uses an internal state representation (a HashMap) that tracks all accounts. Each account is represented by the `Account` structure, which includes -fields like balance, nonce, and code hash, among others. +fields like balance, nonce, and code hash. For state-changing operations, the module keeps track of all the changes within a "journal" for easy reversion and commitment to the database. This feature is particularly useful for handling reversion of state changes in case of transaction failures or other exceptions. @@ -16,165 +16,76 @@ The module interacts with a database through the `Database` trait, which abstrac operations for fetching and storing data. This design allows for a pluggable backend where different implementations of the `Database` trait can be used to persist the state in various ways (for instance, in-memory or disk-based databases). -A notable feature of this module is its handling of "cold" and "hot" accesses to accounts and -storage, mimicking how Ethereum clients implement these concepts for state accesses. -## Structures +## Data Structures -### `JournaledState` +- `JournaledState` -This structure represents the entire state of the blockchain, including accounts, their -associated balances, nonces, and code hashes. It maintains a journal of all state changes -that allows for easy reversion and commitment of changes to the database. + This structure represents the entire state of the blockchain, including accounts, their + associated balances, nonces, and code hashes. It maintains a journal of all state changes + that allows for easy reversion and commitment of changes to the database. -### `Account` +- `Account` -This structure represents an individual account on the blockchain. It includes the account's -balance, nonce, and code hash. It also includes a flag indicating if the account is -self-destructed, and a map representing the account's storage. + This structure represents an individual account on the blockchain. It includes the account's + balance, nonce, and code hash. It also includes a flag indicating if the account is + self-destructed, and a map representing the account's storage. -### `JournalEntry` +- `JournalEntry` -This structure represents an entry in the `JournaledState`'s journal. Each entry describes -an operation that changes the state, such as an account loading, an account destruction, or a -storage change. + This structure represents an entry in the `JournaledState`'s journal. Each entry describes + an operation that changes the state, such as an account loading, an account destruction, or a + storage change. ## Methods -### `selfdestruct` +- `selfdestruct` -This method marks an account as self-destructed and transfers its balance to a target account. -If the target account does not exist, it's created. If the self-destructed account and the -target are the same, the balance will be lost. + This method marks an account as self-destructed and transfers its balance to a target account. + If the target account does not exist, it's created. If the self-destructed account and the + target are the same, the balance will be lost. -Example: +- `initial_account_and_code_load` -```rust -// Mark an account for self-destruction -journaled_state.selfdestruct(&account_address, &target_address); -``` + This method initializes an account and loads its associated code from the database. If the + code does not exist, an empty code is associated with the account. -### `initial_account_and_code_load` +- `initial_account_load` -This method initializes an account and loads its associated code from the database. If the -code does not exist, an empty code is associated with the account. + This method loads an account's basic information from the database without loading the code. + It also loads specified storage slots into memory. -Example: +- `load_account` -```rust -// Load an account and its code -journaled_state.initial_account_and_code_load(&account_address); -let account = journaled_state.get_account(&account_address); -let code = journaled_state.get_code(&account_address); -println!("Account: {:?}", account); -println!("Code: {:?}", code); -``` + This method loads an account's information into memory and returns whether the account was + cold or hot accessed. -### `initial_account_load` +- `load_account_exist` -This method loads an account's basic information from the database without loading the code. -It also loads specified storage slots into memory. + This method checks whether an account exists or not. It returns whether the account was + cold or hot accessed and whether it exists. -Example: +- `load_code` -```rust -// Load account without loading the code -journaled_state.initial_account_load(&account_address, &vec![slot1, slot2]); -let account = journaled_state.get_account(&account_address); -println!("Account: {:?}", account); -``` + This method loads an account's code into memory from the database. -### `load_account` +- `sload` -This method loads an account's information into memory and returns whether the account was -cold or hot accessed. + This method loads a specified storage value of an account. It returns the value and whether + the storage was cold loaded. -Example: +- `sstore` -```rust -// Load an account -let (account, was_cold) = journaled_state.load_account(&account_address); -println!("Account: {:?}", account); -println!("Was cold: {:?}", was_cold); -``` + This method changes the value of a specified storage slot in an account and returns the + original value, the present value, the new value, and whether the storage was cold loaded. -### `load_account_exist` +- `log` -This method checks whether an account exists or not. It returns whether the account was -cold or hot accessed and whether it exists. + This method adds a log entry to the journal. -Example: +- `is_precompile` -```rust -// Load an account's data and check its existence -let mut journaled_state = JournaledState::new(db); -let cold_accessed = journaled_state.load_account_exist(&account_address); -println!("Account exists: {:?}", cold_accessed.1); -``` - -### `load_code` - -This method loads an account's code into memory from the database. - -Example: - -```rust -// Load the code of an account -let (account, was_cold) = journaled_state.load_code(&account_address); -println!("Account: {:?}", account); -println!("Code: {:?}", account.info.code.unwrap()); -println!("Was cold: {:?}", was_cold); -``` - -### `sload` - -This method loads a specified storage value of an account. It returns the value and whether -the storage was cold loaded. - -Example: - -```rust -// Load a storage value -let (value, was_cold) = journaled_state.sload(&account_address, &slot); -println!("Storage value: {:?}, Was cold: {:?}", value, was_cold); -``` - -### `sstore` - -This method changes the value of a specified storage slot in an account and returns the -original value, the present value, the new value, and whether the storage was cold loaded. - -Example: - -```rust -// Change a storage value and commit the change -journaled_state.sstore(&account_address, slot, new_value); -journaled_state.commit(); -``` - -### `log` - -This method adds a log entry to the journal. - -Example: - -```rust -// Create a log entry -let topics = vec![H256::random(), H256::random()]; -journaled_state.log(&account_address, &topics, &data); -``` - -### `is_precompile` - -This method checks whether an address is a precompiled contract or not. - -Example: - -```rust -// Check whether an address is a precompiled contract -let is_precompile = journaled_state.is_precompile(&account_address); -println!("Is precompiled contract: {:?}", is_precompile); -``` + This method checks whether an address is a precompiled contract or not. ## Relevant EIPs diff --git a/documentation/src/examples.md b/documentation/src/examples.md deleted file mode 100644 index 0784c91051..0000000000 --- a/documentation/src/examples.md +++ /dev/null @@ -1,130 +0,0 @@ -# Examples - -Currently there is an example `examples/fork_ref_transact.rs` that takes a fork of a UniswapV2 pair contract for the ETH/USDT pair from the Ethereum mainnet via an Infura endpoint (an HTTP Provider). -It loads a specific storage slot of the contract. In this case, the slot corresponds to calling the contract's `getReserves()` function which returns a tuple of the quantity of reserves of token 0 and token 1 as well as the latest block timestamp. - -The fork of the mainnet state is initialized as an `EthersDB` via the call to `EthersDB::basic` which returns `AccountInfo` containing the account's nonce, balance, and code. -Then, we also specify the storage slot (8) it wants to interact with, which holds the reserves and block timestamp. - -The code generates and encodes the Application Binary Interface (ABI) for a specific function, getReserves(), within the contract. -Setting up Database for EVM: A database for the EVM is created using EthersDB and populated with the basic account info and storage slot value of the contract to be interacted with. -An EVM is initialized and the environment is set up for making a reference transaction, specifying details like the caller address, the contract to transact with, the call data (the `getReserves()` function), and the transaction value. -The reference transaction is executed, but it doesn't write the result to the database, but it captures the output of the call. -`transact_commit` can be used instead to update the local database. - -The resulting data is extracted and decoded. -In the context of the Uniswap contract, this means getting the reserves for the two tokens and the last block timestamp. -Finally, the code prints out the result of the `getReserves()` call from that point of the ETH/USDT pool history. -This code is a demonstration of how one can interact with a smart contract's storage, generate call data, initialize an EVM, and execute a transaction to a contract function using Rust and `revm`. - -```rust -use anyhow::{Ok, Result}; -use bytes::Bytes; -use ethers_contract::BaseContract; -use ethers_core::abi::parse_abi; -use ethers_providers::{Http, Provider}; -use revm::{ - db::{CacheDB, EmptyDB, EthersDB}, - primitives::{ExecutionResult, Output, TransactTo, B160, U256 as rU256}, - Database, EVM, -}; -use std::{str::FromStr, sync::Arc}; - -#[tokio::main] -async fn main() -> Result<()> { - // create ethers client and wrap it in Arc - let client = Provider::::try_from( - "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27", - )?; - let client = Arc::new(client); - - // ----------------------------------------------------------- // - // Storage slots of UniV2Pair contract // - // =========================================================== // - // storage[5] = factory: address // - // storage[6] = token0: address // - // storage[7] = token1: address // - // storage[8] = (res0, res1, ts): (uint112, uint112, uint32) // - // storage[9] = price0CumulativeLast: uint256 // - // storage[10] = price1CumulativeLast: uint256 // - // storage[11] = kLast: uint256 // - // =========================================================== // - - // choose slot of storage that you would like to transact with - let slot = rU256::from(8); - - // ETH/USDT pair on Uniswap V2 - let pool_address = B160::from_str("0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852")?; - - // generate abi for the calldata from the human readable interface - let abi = BaseContract::from( - parse_abi(&[ - "function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)", - ])? - ); - - // encode abi into Bytes - let encoded = abi.encode("getReserves", ())?; - - // initialize new EthersDB - let mut ethersdb = EthersDB::new(Arc::clone(&client), None).unwrap(); - - // query basic properties of an account incl bytecode - let acc_info = ethersdb.basic(pool_address).unwrap().unwrap(); - - // query value of storage slot at account address - let value = ethersdb.storage(pool_address, slot).unwrap(); - - // initialise empty in-memory-db - let mut cache_db = CacheDB::new(EmptyDB::default()); - - // insert basic account info which was generated via Web3DB with the corresponding address - cache_db.insert_account_info(pool_address, acc_info); - - // insert our pre-loaded storage slot to the corresponding contract key (address) in the DB - cache_db - .insert_account_storage(pool_address, slot, value) - .unwrap(); - - // initialise an empty (default) EVM - let mut evm = EVM::new(); - - // insert pre-built database from above - evm.database(cache_db); - - // fill in missing bits of env struc - // change that to whatever caller you want to be - evm.env.tx.caller = B160::from_str("0x0000000000000000000000000000000000000000")?; - // account you want to transact with - evm.env.tx.transact_to = TransactTo::Call(pool_address); - // calldata formed via abigen - evm.env.tx.data = Bytes::from(hex::decode(hex::encode(&encoded))?); - // transaction value in wei - evm.env.tx.value = rU256::try_from(0)?; - - // execute transaction without writing to the DB - let ref_tx = evm.transact_ref().unwrap(); - // select ExecutionResult struct - let result = ref_tx.result; - - // unpack output call enum into raw bytes - let value = match result { - ExecutionResult::Success { output, .. } => match output { - Output::Call(value) => Some(value), - _ => None, - }, - _ => None, - }; - - // decode bytes to reserves + ts via ethers-rs's abi decode - let (reserve0, reserve1, ts): (u128, u128, u32) = - abi.decode_output("getReserves", value.unwrap())?; - - // Print emulated getReserves() call output - println!("Reserve0: {:#?}", reserve0); - println!("Reserve1: {:#?}", reserve1); - println!("Timestamp: {:#?}", ts); - - Ok(()) -} -``` diff --git a/documentation/src/introduction.md b/documentation/src/introduction.md index f46bc9c615..0bb7074dce 100644 --- a/documentation/src/introduction.md +++ b/documentation/src/introduction.md @@ -11,8 +11,20 @@ The project hase 4 main crates that are used to build the revm. The crates are: - `interpreter`: Execution loop with instructions. - `precompile`: EVM precompiles. -## Binaries +## Testing with the binaries -- `revme`: A CLI binary, used for running state test json. Currently it is used to run ethereum tests: -* statetest: takes path to folder where ethereum statetest json can be found. It recursively searches for all json files and execute them. This is how I run all https://github.com/ethereum/tests to check if revm is compliant. Example `revme statests test/GenericEvmTest/` -- `revm-test`: test binaries with contracts; used mostly to check performance. +There are two binaries both of which are used for testing. To install them run `cargo install --path bins/`. The binaries are: + +- `revme`: A CLI binary, used for running state test json. Currently it is used to run [ethereum tests](https://github.com/ethereum/tests) to check if revm is compliant. For example if you have the eth tests cloned into a directory called eth tests and the EIP tests in the following directories you can run +```bash +cargo run --profile ethtests -p revme -- \ + statetest \ + ../ethtests/GeneralStateTests/ \ + ../ethtests/LegacyTests/Constantinople/GeneralStateTests/ \ + bins/revme/tests/EIPTests/StateTests/stEIP5656-MCOPY/ \ + bins/revme/tests/EIPTests/StateTests/stEIP1153-transientStorage/ +``` + +- `revm-test`: test binaries with contracts; used mostly to check performance + +If you are interested in contributing, be sure to run the statetests. It is recommeded to read about the [ethereum tests](https://ethereum-tests.readthedocs.io/en/latest/). diff --git a/examples/fork_ref_transact.rs b/examples/fork_ref_transact.rs index 0fba487d2b..933c55a651 100644 --- a/examples/fork_ref_transact.rs +++ b/examples/fork_ref_transact.rs @@ -92,6 +92,7 @@ async fn main() -> Result<()> { ExecutionResult::Success { output, .. } => match output { Output::Call(value) => Some(value), _ => None, + Output::Create(_, _) => todo!(), }, _ => None, }; From 012fe247815199a5dd8f53181c4337499b2d803c Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Fri, 18 Aug 2023 12:31:18 -0700 Subject: [PATCH 6/7] fmt + CI --- crates/revm/src/evm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/revm/src/evm.rs b/crates/revm/src/evm.rs index 76f223bfa4..eba13198bb 100644 --- a/crates/revm/src/evm.rs +++ b/crates/revm/src/evm.rs @@ -25,7 +25,7 @@ use revm_precompile::Precompiles; /// want to update anything on it. It enabled `transact_ref` and `inspect_ref` functions /// * Database+DatabaseCommit allow directly committing changes of transaction. it enabled `transact_commit` /// and `inspect_commit` -/// +/// /// /// # Example /// /// ``` @@ -36,7 +36,7 @@ use revm_precompile::Precompiles; /// let evm: EVM = EVM::new(); /// assert!(evm.db.is_none()); /// ``` -/// +/// #[derive(Clone)] pub struct EVM { pub env: Env, From d6dd4afe59aed9aac72299eb78bfd561576c4efd Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Fri, 18 Aug 2023 12:36:08 -0700 Subject: [PATCH 7/7] clippy + book --- .github/workflows/book.yml | 1 + crates/primitives/src/bits.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml index 746ab3d543..088b01b5f0 100644 --- a/.github/workflows/book.yml +++ b/.github/workflows/book.yml @@ -80,6 +80,7 @@ jobs: - name: Move docs to book folder run: | + mkdir -p target/book/docs mv target/doc target/book/docs - name: Archive artifact diff --git a/crates/primitives/src/bits.rs b/crates/primitives/src/bits.rs index 31b7d69ba7..45ac577d8c 100644 --- a/crates/primitives/src/bits.rs +++ b/crates/primitives/src/bits.rs @@ -1,3 +1,5 @@ +#![allow(clippy::incorrect_clone_impl_on_copy_type)] + use derive_more::{AsRef, Deref}; use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions};