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 23 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
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,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"] }
k256 = "0.13.3"
7 changes: 6 additions & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ 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, features = ["serde"] }
mpaulucci marked this conversation as resolved.
Show resolved Hide resolved
tinyvec = "1.6.0"
ethereum-types = "0.14.1"
serde.workspace = true
serde_json.workspace = true
keccak-hash = "0.10.0"
sha3 = "0.10.8"
secp256k1 = { version = "0.29", default-features = false, features = [
"global-context",
"recovery",
] }

[dev-dependencies]
hex-literal = "0.4.1"
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
@@ -1,7 +1,9 @@
mod account;
mod block;
mod genesis;
mod transaction;

pub use account::*;
pub use block::*;
pub use genesis::*;
pub use transaction::*;
194 changes: 194 additions & 0 deletions crates/core/src/types/transaction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
use bytes::Bytes;
use ethereum_types::{Address, H256, U256};
use secp256k1::{ecdsa::RecoveryId, Message, SECP256K1};
use sha3::{Digest, Keccak256};

use crate::rlp::encode::RLPEncode;

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

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

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

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),
};
}
}

impl RLPEncode for LegacyTransaction {
juanbono marked this conversation as resolved.
Show resolved Hide resolved
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);
}
}

impl RLPEncode for EIP1559Transaction {
juanbono marked this conversation as resolved.
Show resolved Hide resolved
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);
}
}

impl Transaction {
pub fn sender(&self) -> Address {
match self {
Transaction::LegacyTransaction(tx) => recover_address(
&tx.r,
&tx.s,
tx.v.as_u64().saturating_sub(27) != 0,
&tx.data,
),
Transaction::EIP1559Transaction(tx) => {
dbg!(recover_address(
&tx.signature_r,
&tx.signature_s,
tx.signature_y_parity,
&tx.payload
))
}
}
}

pub fn gas_limit(&self) -> u64 {
match self {
Transaction::LegacyTransaction(tx) => tx.gas,
Transaction::EIP1559Transaction(tx) => tx.gas_limit,
}
}

pub fn gas_price(&self) -> u64 {
match self {
Transaction::LegacyTransaction(tx) => tx.gas_price,
Transaction::EIP1559Transaction(tx) => tx.max_fee_per_gas,
}
}

pub fn to(&self) -> Address {
match self {
Transaction::LegacyTransaction(tx) => tx.to,
Transaction::EIP1559Transaction(tx) => tx.destination,
}
}

pub fn value(&self) -> U256 {
match self {
Transaction::LegacyTransaction(tx) => tx.value,
Transaction::EIP1559Transaction(tx) => tx.amount,
}
}

pub fn max_priority_fee(&self) -> Option<u64> {
match self {
Transaction::LegacyTransaction(_tx) => None,
Transaction::EIP1559Transaction(tx) => Some(tx.max_priority_fee_per_gas),
}
}

pub fn chain_id(&self) -> Option<u64> {
match self {
Transaction::LegacyTransaction(_tx) => None,
Transaction::EIP1559Transaction(tx) => Some(tx.chain_id),
}
}

pub fn access_list(&self) -> Vec<(Address, Vec<H256>)> {
match self {
Transaction::LegacyTransaction(_tx) => Vec::new(),
Transaction::EIP1559Transaction(tx) => tx.access_list.clone(),
}
}

pub fn nonce(&self) -> u64 {
match self {
Transaction::LegacyTransaction(tx) => tx.nonce,
Transaction::EIP1559Transaction(tx) => tx.signer_nonce,
}
}

pub fn data(&self) -> &Bytes {
match self {
Transaction::LegacyTransaction(tx) => &tx.data,
Transaction::EIP1559Transaction(tx) => &tx.payload,
}
}
}

fn recover_address(
signature_r: &U256,
signature_s: &U256,
signature_y_parity: bool,
message: &Bytes,
) -> Address {
// Create signature
let mut signature_bytes = [0; 64];
signature_r.to_big_endian(&mut signature_bytes[0..32]);
signature_s.to_big_endian(&mut signature_bytes[32..]);
let signature = secp256k1::ecdsa::RecoverableSignature::from_compact(
&signature_bytes,
RecoveryId::from_i32(signature_y_parity as i32).unwrap(), // cannot fail
)
.unwrap();
// Hash message
// let message = Bytes::new(); // TODO: Fix parsing so "0x" is empty bytes (Uncomment this when running add11 ef test)
let msg_digest: [u8; 32] = Keccak256::new_with_prefix(message.as_ref())
.finalize()
.into();
// Recover public key
let public = SECP256K1
.recover_ecdsa(&Message::from_digest(msg_digest), &signature)
.unwrap();
// Hash public key to obtain address
let hash = Keccak256::new_with_prefix(&public.serialize_uncompressed()[1..]).finalize();
Address::from_slice(&hash[12..])
}
3 changes: 3 additions & 0 deletions crates/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
revm = { version = "10.0.0", features = ["serde", "std", "serde-json"] }
bytes.workspace = true
ethrex-core.workspace = true
Loading