Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: integrate revm + impl address recovery #73

Merged
merged 49 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
af59cf4
Draft
fmoletta Jun 26, 2024
9830005
Create BlockEnv from BlockHeader
fmoletta Jun 27, 2024
f568b4c
Add state cache
fmoletta Jun 27, 2024
19b47e1
Merge branch 'main' of https://github.com/lambdaclass/ethrex into add…
fmoletta Jun 27, 2024
4d82b04
Fill more tx env fields
fmoletta Jun 27, 2024
9c8f150
Move `Transaction` to its own module
fmoletta Jun 27, 2024
d48b3f6
Update crate name + add access list
fmoletta Jun 27, 2024
ff36e10
Merge branch 'main' of https://github.com/lambdaclass/ethrex into add…
fmoletta Jun 27, 2024
0423796
Add nonce and external handler
fmoletta Jun 27, 2024
0e7739e
Fill some todos
fmoletta Jun 27, 2024
e854ae5
Convert eftests header to ethrex block header
fmoletta Jun 27, 2024
639b74e
Convert eftests tx to ethrex tx
fmoletta Jun 27, 2024
ff7297f
Convert eftests account to ethrex account
fmoletta Jun 27, 2024
5e1d06b
Replace evm code in eftests with ethrex-evm import
fmoletta Jun 27, 2024
c1f7f53
WIP: add address recovery
fmoletta Jun 27, 2024
f29a030
Make ef tests run: Set chain id to mainnet + use current block instea…
fmoletta Jun 28, 2024
98b9edd
Update address calculation
fmoletta Jun 28, 2024
2d27e43
Use y parity
fmoletta Jun 28, 2024
f25208f
Fix parity calc
fmoletta Jun 28, 2024
890cff8
Fix parity calc
fmoletta Jun 28, 2024
937e1a9
Add another ef test example
fmoletta Jul 1, 2024
7c663df
Comment quick fix
fmoletta Jul 1, 2024
6ca3811
Differentiate between legacy and eip tx when converting from eftests …
fmoletta Jul 1, 2024
9748e86
Filter by tx_type
fmoletta Jul 1, 2024
f0b02a0
execute_tx return ExecutionResult
fmoletta Jul 1, 2024
fe64b2c
Handle y_parity in protected legacy txs
fmoletta Jul 1, 2024
3875895
Use rlp encoded tx fields instead of tx data to calc pub key
fmoletta Jul 1, 2024
5e52b86
Move quick fix for empty data
fmoletta Jul 1, 2024
184d56b
Add todo comment
fmoletta Jul 1, 2024
e8bd271
Fix tx data desrialization for eftests
fmoletta Jul 1, 2024
9e4b141
Remove comment
fmoletta Jul 1, 2024
1f2a194
Fix code deser
fmoletta Jul 1, 2024
9549014
Use correct data for EIP1555 addr calc too
fmoletta Jul 1, 2024
1dbc191
Remove unused dep
fmoletta Jul 1, 2024
4da9018
clippy
fmoletta Jul 1, 2024
69caf65
Remove uneeded feature
fmoletta Jul 1, 2024
625fc21
Remove dbg print
fmoletta Jul 1, 2024
08de5e2
Move evm crate inside core
fmoletta Jul 1, 2024
0908a4a
Fix desr
fmoletta Jul 1, 2024
87dab3d
map error
fmoletta Jul 1, 2024
6636cfc
Merge branch 'main' of https://github.com/lambdaclass/ethrex into add…
fmoletta Jul 2, 2024
54ffef5
Remove dbg print
fmoletta Jul 2, 2024
480a2fc
Merge branch 'main' of https://github.com/lambdaclass/ethrex into add…
fmoletta Jul 2, 2024
1aff2a4
Fix EOF
fmoletta Jul 2, 2024
d3fb8fc
Merge branch 'main' of https://github.com/lambdaclass/ethrex into add…
fmoletta Jul 2, 2024
d3f52b2
Add ExecutionResult type
fmoletta Jul 2, 2024
f4ced4a
Push fn
fmoletta Jul 2, 2024
4368db0
Move ExecutionResult to its own module
fmoletta Jul 2, 2024
769550f
Merge branch 'main' of https://github.com/lambdaclass/ethrex into add…
fmoletta Jul 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ members = [
"ethrex",
"crates/consensus",
"crates/core",
"crates/evm",
"crates/net",
"crates/rpc",
"crates/storage",
Expand All @@ -18,7 +17,6 @@ edition = "2021"
[workspace.dependencies]
ethrex-consensus = { path = "./crates/consensus" }
ethrex-core = { path = "./crates/core" }
ethrex-evm = { path = "./crates/evm" }
ethrex-net = { path = "./crates/net" }
ethrex-rpc = { path = "./crates/rpc" }
ethrex-storage = { path = "./crates/storage" }
Expand All @@ -29,5 +27,6 @@ tracing-subscriber = "0.3.0"
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.117"
libmdbx = { version = "0.5.0", features = ["orm"] }
bytes = "1.6.0"
tokio = { version = "1.38.0", features = ["full"] }
thiserror = "1.0.61"
8 changes: 7 additions & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bytes = { version = "1.6.0", features = ["serde"] }
bytes.workspace = true
tinyvec = "1.6.0"
ethereum-types = "0.14.1"
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
keccak-hash = "0.10.0"
sha3 = "0.10.8"
secp256k1 = { version = "0.29", default-features = false, features = [
"global-context",
"recovery",
] }
revm = { version = "10.0.0", features = ["serde", "std", "serde-json"] }

[dev-dependencies]
hex-literal = "0.4.1"
101 changes: 101 additions & 0 deletions crates/core/src/evm/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use super::{
types::{Account, BlockHeader, Transaction},
Address,
};
use revm::{
inspector_handle_register,
inspectors::TracerEip3155,
primitives::{BlockEnv, Bytecode, TxEnv, TxKind, U256},
CacheState, Evm,
};
use std::collections::HashMap;
// Rename imported types for clarity
use revm::primitives::AccountInfo as RevmAccountInfo;
use revm::primitives::Address as RevmAddress;
// Export needed types
pub use revm::primitives::ExecutionResult;
pub use revm::primitives::SpecId;

pub fn execute_tx(
tx: &Transaction,
header: &BlockHeader,
pre: &HashMap<Address, Account>, // TODO: Modify this type when we have a defined State structure
spec_id: SpecId,
) -> ExecutionResult {
let block_env = block_env(header);
let tx_env = tx_env(tx);
let cache_state = cache_state(pre);
let mut state = revm::db::State::builder()
.with_cached_prestate(cache_state)
.with_bundle_update()
.build();
let mut evm = Evm::builder()
.with_db(&mut state)
.with_block_env(block_env)
.with_tx_env(tx_env)
.with_spec_id(spec_id)
.reset_handler()
.with_external_context(TracerEip3155::new(Box::new(std::io::stderr())).without_summary())
.append_handler_register(inspector_handle_register)
.build();
let tx_result = evm.transact().unwrap();
tx_result.result
juanbono marked this conversation as resolved.
Show resolved Hide resolved
}

fn cache_state(pre: &HashMap<Address, Account>) -> CacheState {
let mut cache_state = revm::CacheState::new(false);
for (address, account) in pre {
let acc_info = RevmAccountInfo {
balance: U256::from_limbs(account.info.balance.0),
code_hash: account.info.code_hash.0.into(),
code: Some(Bytecode::new_raw(account.code.clone().into())),
nonce: account.info.nonce,
};

let mut storage = HashMap::new();
for (k, v) in &account.storage {
storage.insert(U256::from_be_bytes(k.0), U256::from_be_bytes(v.0));
}

cache_state.insert_account_with_storage(address.to_fixed_bytes().into(), acc_info, storage);
}
cache_state
}

fn block_env(header: &BlockHeader) -> BlockEnv {
BlockEnv {
number: U256::from(header.number),
coinbase: RevmAddress(header.coinbase.0.into()),
timestamp: U256::from(header.timestamp),
gas_limit: U256::from(header.gas_limit),
basefee: U256::from(header.base_fee_per_gas),
difficulty: U256::from_limbs(header.difficulty.0),
prevrandao: Some(header.prev_randao.as_fixed_bytes().into()),
..Default::default()
}
}

fn tx_env(tx: &Transaction) -> TxEnv {
TxEnv {
caller: RevmAddress(tx.sender().0.into()),
gas_limit: tx.gas_limit(),
gas_price: U256::from(tx.gas_price()),
transact_to: TxKind::Call(RevmAddress(tx.to().0.into())), // Todo: handle case where this is Create
value: U256::from_limbs(tx.value().0),
data: tx.data().clone().into(),
nonce: Some(tx.nonce()),
chain_id: tx.chain_id(),
access_list: tx
.access_list()
.into_iter()
.map(|(addr, list)| {
(
RevmAddress(addr.0.into()),
list.into_iter().map(|a| U256::from_be_bytes(a.0)).collect(),
)
})
.collect(),
gas_priority_fee: tx.max_priority_fee().map(U256::from),
..Default::default()
}
}
1 change: 1 addition & 0 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod rlp;
pub use ethereum_types::*;
pub mod evm;
pub mod serde_utils;
pub mod types;
55 changes: 55 additions & 0 deletions crates/core/src/rlp/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,61 @@ impl<T: RLPEncode, S: RLPEncode> RLPEncode for (T, S) {
}
}

impl<A: RLPEncode, B: RLPEncode, C: RLPEncode, D: RLPEncode, E: RLPEncode, F: RLPEncode> RLPEncode
for (A, B, C, D, E, F)
{
fn encode(&self, buf: &mut dyn BufMut) {
let total_len = self.0.length()
+ self.1.length()
+ self.2.length()
+ self.3.length()
+ self.4.length()
+ self.5.length();
encode_length(total_len, buf);
self.0.encode(buf);
self.1.encode(buf);
self.2.encode(buf);
self.3.encode(buf);
self.4.encode(buf);
self.5.encode(buf);
}
}

impl<
A: RLPEncode,
B: RLPEncode,
C: RLPEncode,
D: RLPEncode,
E: RLPEncode,
F: RLPEncode,
G: RLPEncode,
H: RLPEncode,
I: RLPEncode,
> RLPEncode for (A, B, C, D, E, F, G, H, I)
{
juanbono marked this conversation as resolved.
Show resolved Hide resolved
fn encode(&self, buf: &mut dyn BufMut) {
let total_len = self.0.length()
+ self.1.length()
+ self.2.length()
+ self.3.length()
+ self.4.length()
+ self.5.length()
+ self.6.length()
+ self.7.length()
+ self.8.length();
encode_length(total_len, buf);
self.0.encode(buf);
self.1.encode(buf);
self.2.encode(buf);
self.3.encode(buf);
self.4.encode(buf);
self.5.encode(buf);
self.6.encode(buf);
self.7.encode(buf);
self.8.encode(buf);
}
}

impl RLPEncode for Ipv4Addr {
fn encode(&self, buf: &mut dyn BufMut) {
self.octets().encode(buf)
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/types/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl From<GenesisAccount> for Account {
}
}

fn code_hash(code: &Bytes) -> H256 {
pub fn code_hash(code: &Bytes) -> H256 {
keccak_hash::keccak(code.as_ref())
}

Expand Down
117 changes: 22 additions & 95 deletions crates/core/src/types/block.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
use crate::{rlp::encode::RLPEncode, Address, H256, U256};
use bytes::Bytes;

use super::Transaction;

pub type BlockNumber = u64;
pub type Bloom = [u8; 256];

/// Header part of a block on the chain.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BlockHeader {
parent_hash: H256,
ommers_hash: H256,
coinbase: Address,
state_root: H256,
transactions_root: H256,
receipt_root: H256,
logs_bloom: Bloom,
difficulty: U256,
number: BlockNumber,
gas_limit: u64,
gas_used: u64,
timestamp: u64,
extra_data: Bytes,
prev_randao: H256,
nonce: u64,
base_fee_per_gas: u64,
withdrawals_root: H256,
blob_gas_used: u64,
excess_blob_gas: u64,
parent_beacon_block_root: H256,
pub parent_hash: H256,
pub ommers_hash: H256, // ommer = uncle
pub coinbase: Address,
pub state_root: H256,
pub transactions_root: H256,
pub receipt_root: H256,
pub logs_bloom: Bloom,
pub difficulty: U256,
pub number: BlockNumber,
pub gas_limit: u64,
pub gas_used: u64,
pub timestamp: u64,
pub extra_data: Bytes,
pub prev_randao: H256,
pub nonce: u64,
pub base_fee_per_gas: u64,
pub withdrawals_root: H256,
pub blob_gas_used: u64,
pub excess_blob_gas: u64,
pub parent_beacon_block_root: H256,
}

impl RLPEncode for BlockHeader {
Expand Down Expand Up @@ -86,78 +88,3 @@ impl RLPEncode for Withdrawal {
self.amount.encode(buf);
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Transaction {
LegacyTransaction(LegacyTransaction),
EIP1559Transaction(EIP1559Transaction),
}

impl RLPEncode for Transaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
match self {
Transaction::LegacyTransaction(t) => t.encode(buf),
Transaction::EIP1559Transaction(t) => t.encode(buf),
};
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LegacyTransaction {
nonce: U256,
gas_price: u64,
gas: u64,
to: Address,
value: U256,
data: Bytes,
v: U256,
r: U256,
s: U256,
}

impl RLPEncode for LegacyTransaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
self.nonce.encode(buf);
self.gas_price.encode(buf);
self.gas.encode(buf);
self.to.encode(buf);
self.value.encode(buf);
self.data.encode(buf);
self.v.encode(buf);
self.r.encode(buf);
self.s.encode(buf);
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EIP1559Transaction {
chain_id: u64,
signer_nonce: U256,
max_priority_fee_per_gas: u64,
max_fee_per_gas: u64,
gas_limit: u64,
destination: Address,
amount: u64,
payload: Bytes,
access_list: Vec<(Address, Vec<H256>)>,
signature_y_parity: bool,
signature_r: U256,
signature_s: U256,
}

impl RLPEncode for EIP1559Transaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
self.chain_id.encode(buf);
self.signer_nonce.encode(buf);
self.max_priority_fee_per_gas.encode(buf);
self.max_fee_per_gas.encode(buf);
self.gas_limit.encode(buf);
self.destination.encode(buf);
self.amount.encode(buf);
self.payload.encode(buf);
self.access_list.encode(buf);
self.signature_y_parity.encode(buf);
self.signature_r.encode(buf);
self.signature_s.encode(buf);
}
}
2 changes: 2 additions & 0 deletions crates/core/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ mod account;
mod block;
mod genesis;
mod receipt;
mod transaction;

pub use account::*;
pub use block::*;
pub use genesis::*;
pub use receipt::*;
pub use transaction::*;
Loading
Loading