Skip to content

Commit

Permalink
feat(levm): error handling ef_tests (Part 1) (#1319)
Browse files Browse the repository at this point in the history
**Motivation**

<!-- Why does this pull request exist? What are its goals? -->

**Description**

<!-- A clear and concise general description of the changes this PR
introduces -->
- Add some other fields to levm's environment: Max priority fee per gas,
max fee per gas, block gas limit, max fee per blob gas.
- Refactors `tx_blob_hashes` and `op_blobhash`. I realized this opcode
wasn't pushing 0 to the stack if no blobhash was found.
- Make `execute()` propagate interal errors
- Partially implements validation errors. Partially because for them to
be fully implemented I have to make changes like gas consumption logic
and that would be too much for this PR.


- The amount of tests that passed is pretty similar to the ones that are
passing in `main`, only a few more are passing. This PR only doesn't fix
all execution errors, for this to be fixed I have to make a lot more
changes and it would transform itself into a very big PR.

<!-- Link to issues: Resolves #111, Resolves #222 -->

Closes #issue_number
  • Loading branch information
JereSalo authored Nov 28, 2024
1 parent c3d1236 commit 17ddca5
Show file tree
Hide file tree
Showing 10 changed files with 462 additions and 325 deletions.
31 changes: 19 additions & 12 deletions cmd/ef_tests/levm/runner/levm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,31 +73,38 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result<VM, EFTes
store: initial_state.database().unwrap().clone(),
block_hash,
});

let tx = test
.transactions
.get(vector)
.ok_or(EFTestRunnerError::Internal(
InternalError::FirstRunInternal("Failed to get transaction".to_owned()),
))?;

VM::new(
test.transactions.get(vector).unwrap().to.clone(),
tx.to.clone(),
Environment {
origin: test.transactions.get(vector).unwrap().sender,
origin: tx.sender,
consumed_gas: U256::default(),
refunded_gas: U256::default(),
gas_limit: test.env.current_gas_limit, //this should be tx gas limit
gas_limit: tx.gas_limit,
block_number: test.env.current_number,
coinbase: test.env.current_coinbase,
timestamp: test.env.current_timestamp,
prev_randao: test.env.current_random,
chain_id: U256::from(1729),
base_fee_per_gas: test.env.current_base_fee.unwrap_or_default(),
gas_price: test
.transactions
.get(vector)
.unwrap()
.gas_price
.unwrap_or_default(), // or max_fee_per_gas?
gas_price: tx.gas_price.unwrap_or_default(),
block_excess_blob_gas: test.env.current_excess_blob_gas,
block_blob_gas_used: None,
tx_blob_hashes: None,
tx_blob_hashes: tx.blob_versioned_hashes.clone(),
tx_max_priority_fee_per_gas: tx.max_priority_fee_per_gas,
tx_max_fee_per_gas: tx.max_fee_per_gas,
tx_max_fee_per_blob_gas: tx.max_fee_per_blob_gas,
block_gas_limit: test.env.current_gas_limit,
},
test.transactions.get(vector).unwrap().value,
test.transactions.get(vector).unwrap().data.clone(),
tx.value,
tx.data.clone(),
db,
CacheDB::default(),
)
Expand Down
4 changes: 2 additions & 2 deletions crates/vm/levm/bench/revm_comparison/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ pub fn run_with_levm(program: &str, runs: usize, number_of_iterations: u32) {
let mut vm = new_vm_with_bytecode(Bytes::new()).unwrap();
*vm.current_call_frame_mut().unwrap() = call_frame.clone();
let mut current_call_frame = vm.call_frames.pop().unwrap();
let tx_report = black_box(vm.execute(&mut current_call_frame));
let tx_report = black_box(vm.execute(&mut current_call_frame).unwrap());
assert!(tx_report.result == TxResult::Success);
}
let mut vm = new_vm_with_bytecode(Bytes::new()).unwrap();
*vm.current_call_frame_mut().unwrap() = call_frame.clone();
let mut current_call_frame = vm.call_frames.pop().unwrap();
let tx_report = black_box(vm.execute(&mut current_call_frame));
let tx_report = black_box(vm.execute(&mut current_call_frame).unwrap());
assert!(tx_report.result == TxResult::Success);

match tx_report.result {
Expand Down
3 changes: 3 additions & 0 deletions crates/vm/levm/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub const MEMORY_EXPANSION_QUOTIENT: usize = 512;
pub const TX_BASE_COST: U256 = U256([21000, 0, 0, 0]);

pub const MAX_CODE_SIZE: usize = 0x6000;
pub const INIT_CODE_MAX_SIZE: usize = 49152;
pub const MAX_CREATE_CODE_SIZE: usize = 2 * MAX_CODE_SIZE;

pub const INVALID_CONTRACT_PREFIX: u8 = 0xef;
Expand All @@ -44,6 +45,8 @@ pub const MAX_BLOB_NUMBER_PER_BLOCK: usize = 6;
pub const TARGET_BLOB_GAS_PER_BLOCK: U256 = U256([393216, 0, 0, 0]); // TARGET_BLOB_NUMBER_PER_BLOCK * GAS_PER_BLOB
pub const MIN_BASE_FEE_PER_BLOB_GAS: U256 = U256([1, 0, 0, 0]);
pub const BLOB_BASE_FEE_UPDATE_FRACTION: U256 = U256([3338477, 0, 0, 0]);
pub const MAX_BLOB_COUNT: usize = 6;
pub const VALID_BLOB_PREFIXES: [u8; 2] = [0x01, 0x02];

// Block constants
pub const LAST_AVAILABLE_BLOCK_LIMIT: U256 = U256([256, 0, 0, 0]);
Expand Down
12 changes: 10 additions & 2 deletions crates/vm/levm/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ pub struct Environment {
pub prev_randao: Option<H256>,
pub chain_id: U256,
pub base_fee_per_gas: U256,
pub gas_price: U256,
pub gas_price: U256, // Effective gas price
pub block_excess_blob_gas: Option<U256>,
pub block_blob_gas_used: Option<U256>,
pub tx_blob_hashes: Option<Vec<H256>>,
pub tx_blob_hashes: Vec<H256>,
pub tx_max_priority_fee_per_gas: Option<U256>,
pub tx_max_fee_per_gas: Option<U256>,
pub tx_max_fee_per_blob_gas: Option<U256>,
pub block_gas_limit: U256,
}

impl Environment {
Expand All @@ -38,6 +42,10 @@ impl Environment {
block_excess_blob_gas: Default::default(),
block_blob_gas_used: Default::default(),
tx_blob_hashes: Default::default(),
tx_max_priority_fee_per_gas: Default::default(),
tx_max_fee_per_gas: Default::default(),
tx_max_fee_per_blob_gas: Default::default(),
block_gas_limit: Default::default(),
}
}
}
42 changes: 42 additions & 0 deletions crates/vm/levm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,48 @@ pub enum VMError {
// Internal
#[error("Internal error: {0}")]
Internal(#[from] InternalError),
#[error("Transaction validation error: {0}")]
TxValidation(#[from] TxValidationError),
}

impl VMError {
pub fn is_internal(&self) -> bool {
matches!(self, VMError::Internal(_))
}
}

#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
pub enum TxValidationError {
#[error("Sender account should not have bytecode")]
SenderNotEOA,
#[error("Insufficient account founds")]
InsufficientAccountFunds,
#[error("Nonce is max (overflow)")]
NonceIsMax,
#[error("Initcode size exceeded")]
InitcodeSizeExceeded,
#[error("Priority fee greater than max fee per gas")]
PriorityGreaterThanMaxFeePerGas,
#[error("Intrinsic gas too low")]
IntrinsicGasTooLow,
#[error("Gas allowance exceeded")]
GasAllowanceExceeded,
#[error("Insufficient max fee per gas")]
InsufficientMaxFeePerGas,
#[error("Insufficient max fee per blob gas")]
InsufficientMaxFeePerBlobGas,
#[error("Type3TxZeroBlobs")]
Type3TxZeroBlobs,
#[error("Type3TxInvalidBlobVersionedHash")]
Type3TxInvalidBlobVersionedHash,
#[error("Type3TxBlobCountExceeded")]
Type3TxBlobCountExceeded,
#[error("Type3TxContractCreation")]
Type3TxContractCreation,
#[error("Undefined state")]
UndefinedState(i32), // This error is temporarily for things that cause an undefined state.
#[error("Gas limit price product overflow")]
GasLimitPriceProductOverflow,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, thiserror::Error, Serialize, Deserialize)]
Expand Down
28 changes: 11 additions & 17 deletions crates/vm/levm/src/opcode_handlers/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
};
use ethrex_core::{
types::{BLOB_BASE_FEE_UPDATE_FRACTION, MIN_BASE_FEE_PER_BLOB_GAS},
H256, U256,
U256,
};

// Block Information (11)
Expand Down Expand Up @@ -170,22 +170,16 @@ impl VM {
.try_into()
.map_err(|_err| VMError::VeryLargeNumber)?;

let blob_hash: H256 = match &self.env.tx_blob_hashes {
Some(vec) => match vec.get(index) {
Some(el) => *el,
None => {
return Err(VMError::BlobHashIndexOutOfBounds);
}
},
None => {
return Err(VMError::MissingBlobHashes);
}
};

// Could not find a better way to translate from H256 to U256
let u256_blob = U256::from(blob_hash.as_bytes());

current_call_frame.stack.push(u256_blob)?;
let blob_hashes = &self.env.tx_blob_hashes;

blob_hashes
.get(index)
.map(|el| {
current_call_frame
.stack
.push(U256::from_big_endian(el.as_bytes()))
})
.unwrap_or_else(|| current_call_frame.stack.push(U256::zero()))?;

Ok(OpcodeSuccess::Continue)
}
Expand Down
Loading

0 comments on commit 17ddca5

Please sign in to comment.