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(levm): fix validation errors (part 2) and some extra things #1345

Merged
merged 66 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
49a1967
add errors
JereSalo Nov 27, 2024
8c0088a
add is_internal function to vmerror
JereSalo Nov 27, 2024
cfeee50
remove previous validate_transaction
JereSalo Nov 27, 2024
3167f2c
change execute, mainly for propagating internal errors
JereSalo Nov 27, 2024
74e4923
add validate_transaction (not working yet) and gas_price_or_max_fee_p…
JereSalo Nov 27, 2024
1e0449d
change return type of has_code in Account
JereSalo Nov 27, 2024
c62cfad
add intrinsic gas function
JereSalo Nov 27, 2024
f4566c9
add necessary constants
JereSalo Nov 27, 2024
d24ec11
add some fields to environment and think of gas_price as effective ga…
JereSalo Nov 27, 2024
6ac5c20
add unwraps to execute
JereSalo Nov 28, 2024
b01ec97
change blob hashes type and add other paremeters in vm.rs
JereSalo Nov 28, 2024
e5196ec
make small changes in type 3 validations
JereSalo Nov 28, 2024
99a1e21
fix behavior for op_blobhash
JereSalo Nov 28, 2024
88c50c3
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
JereSalo Nov 28, 2024
40b6b8a
fix ef_tests environment for levm
JereSalo Nov 28, 2024
8d62d29
stop using effective gas price in levm
JereSalo Nov 28, 2024
85b7dd6
comment some stuff in validate transaction
JereSalo Nov 28, 2024
d94a98a
delete add_intrinsic_gas (out of scope), and change some things in va…
JereSalo Nov 28, 2024
2f71d26
last commit was wrong, this one is the real one :)
JereSalo Nov 28, 2024
d13cf3b
remove import gas price
JereSalo Nov 28, 2024
0f2f7a1
Merge branch 'main' into levm/ef-tests-error-handling
JereSalo Nov 28, 2024
68a3191
add unwrap() to execute in edge cases tests
JereSalo Nov 28, 2024
79b14d6
merge main into branch
JereSalo Nov 28, 2024
8e882bc
return error when not finding transaction levm_runner
JereSalo Nov 28, 2024
8981d83
remove storage constants that were not used
JereSalo Nov 28, 2024
c9b747f
remove comment from revert create
JereSalo Nov 28, 2024
fc1c17d
Merge branch 'main' into levm/ef-tests-error-handling
JereSalo Nov 28, 2024
ba57edf
fix clippy lint in execute
JereSalo Nov 28, 2024
793d6ad
Merge branch 'main' into levm/ef-tests-error-handling
JereSalo Nov 28, 2024
f80c900
merge
JereSalo Nov 28, 2024
7455a1d
change rust version levm workflow
JereSalo Nov 28, 2024
d9cd1dd
add docs for validations
JereSalo Nov 28, 2024
707303d
comment revm re_run for developing
JereSalo Nov 28, 2024
292d7fe
start cleaning transact
JereSalo Nov 28, 2024
651b13a
start making changes to gas consumption
JereSalo Nov 28, 2024
485ea4c
modify add_gas_with_max for report
JereSalo Nov 28, 2024
54f058a
create function for post execution changes in creatae
JereSalo Nov 28, 2024
37b2a67
make use of create_post_execution function
JereSalo Nov 28, 2024
bc082e4
delete revert_create function
JereSalo Nov 28, 2024
e3c3c88
merge main
JereSalo Nov 28, 2024
35d4116
change error type in blob gas exception
JereSalo Nov 28, 2024
e9fef60
change if in max fee per blob gas validation
JereSalo Nov 29, 2024
05dbab0
change things in validation, up-front-cost and add support for gas co…
JereSalo Nov 29, 2024
ea3bb1a
change link source of eip
JereSalo Nov 29, 2024
390c45a
merge main into branch (still didn't test if everything works fine)
JereSalo Dec 2, 2024
1d9ce34
make some comments on blob gas cost
JereSalo Dec 2, 2024
c4936fe
fix initcode size error
JereSalo Dec 2, 2024
f1ff08b
remove comment
JereSalo Dec 2, 2024
2ce90f7
implement get_base_fee_per_blob_gas()
JereSalo Dec 2, 2024
d344254
fix clippy lints
JereSalo Dec 2, 2024
d743fd3
fix add_gas_with_max for report
JereSalo Dec 2, 2024
bd801b7
fix clippy lint
JereSalo Dec 2, 2024
3af7fb0
move effective_gas_price to utils
JereSalo Dec 2, 2024
a91e419
uncomment revm re-run
JereSalo Dec 2, 2024
fb1b0b7
Merge branch 'main' into levm/transact-refactor
JereSalo Dec 2, 2024
2ef311a
Merge branch 'main' into levm/transact-refactor
JereSalo Dec 2, 2024
f12fd22
Merge branch 'main' into levm/transact-refactor
ilitteri Dec 2, 2024
e8007c6
Merge branch 'main' into levm/transact-refactor
JereSalo Dec 3, 2024
f5dd02e
handle errors if fees are not present in transaction when necessary
JereSalo Dec 3, 2024
92e4848
nits
JereSalo Dec 3, 2024
36b8c15
make change in create_post_execution()
JereSalo Dec 3, 2024
d66679b
add constants
JereSalo Dec 3, 2024
74162a5
rename calldata and code
JereSalo Dec 3, 2024
79fc4e0
set calldata to empty and change init_code_max_size validation
JereSalo Dec 3, 2024
801dad7
remove comment
JereSalo Dec 3, 2024
9bf003c
Merge branch 'main' into levm/transact-refactor
ilitteri Dec 3, 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
4 changes: 2 additions & 2 deletions cmd/ef_tests/levm/runner/levm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
report::{EFTestReport, TestVector},
runner::{EFTestRunnerError, InternalError},
types::EFTest,
utils,
utils::{self, effective_gas_price},
};
use ethrex_core::{
types::{code_hash, AccountInfo},
Expand Down Expand Up @@ -94,7 +94,7 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result<VM, EFTes
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: tx.gas_price.unwrap_or_default(),
gas_price: effective_gas_price(test, &tx)?,
block_excess_blob_gas: test.env.current_excess_blob_gas,
block_blob_gas_used: None,
tx_blob_hashes: tx.blob_versioned_hashes.clone(),
Expand Down
21 changes: 4 additions & 17 deletions cmd/ef_tests/levm/runner/revm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use crate::{
levm_runner::{self, post_state_root},
EFTestRunnerError, InternalError,
},
types::{EFTest, EFTestTransaction},
utils::load_initial_state,
types::EFTest,
utils::{effective_gas_price, load_initial_state},
};
use bytes::Bytes;
use ethrex_core::{types::TxKind, Address, H256, U256};
use ethrex_core::{types::TxKind, Address, H256};
use ethrex_levm::{
errors::{TransactionReport, TxResult},
Account, StorageSlot,
Expand Down Expand Up @@ -90,19 +90,6 @@ pub fn re_run_failed_ef_test_tx(
Ok(())
}

// If gas price is not provided, calculate it with current base fee and priority fee
pub fn effective_gas_price(test: &EFTest, tx: &&EFTestTransaction) -> U256 {
match tx.gas_price {
None => {
let current_base_fee = test.env.current_base_fee.unwrap();
let priority_fee = tx.max_priority_fee_per_gas.unwrap();
let max_fee_per_gas = tx.max_fee_per_gas.unwrap();
std::cmp::min(max_fee_per_gas, current_base_fee + priority_fee)
}
Some(price) => price,
}
}

pub fn prepare_revm_for_tx<'state>(
initial_state: &'state mut EvmState,
vector: &TestVector,
Expand Down Expand Up @@ -148,7 +135,7 @@ pub fn prepare_revm_for_tx<'state>(
let tx_env = RevmTxEnv {
caller: tx.sender.0.into(),
gas_limit: tx.gas_limit.as_u64(),
gas_price: RevmU256::from_limbs(effective_gas_price(test, tx).0),
gas_price: RevmU256::from_limbs(effective_gas_price(test, tx)?.0),
transact_to: match tx.to {
TxKind::Call(to) => RevmTxKind::Call(to.0.into()),
TxKind::Create => RevmTxKind::Create,
Expand Down
40 changes: 38 additions & 2 deletions cmd/ef_tests/levm/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::types::EFTest;
use ethrex_core::{types::Genesis, H256};
use crate::{
runner::{EFTestRunnerError, InternalError},
types::{EFTest, EFTestTransaction},
};
use ethrex_core::{types::Genesis, H256, U256};
use ethrex_storage::{EngineType, Store};
use ethrex_vm::{evm_state, EvmState};

Expand All @@ -17,3 +20,36 @@ pub fn load_initial_state(test: &EFTest) -> (EvmState, H256) {
genesis.get_block().header.compute_block_hash(),
)
}

// If gas price is not provided, calculate it with current base fee and priority fee
pub fn effective_gas_price(
test: &EFTest,
tx: &&EFTestTransaction,
) -> Result<U256, EFTestRunnerError> {
match tx.gas_price {
None => {
let current_base_fee = test
.env
.current_base_fee
.ok_or(EFTestRunnerError::Internal(
InternalError::FirstRunInternal("current_base_fee not found".to_string()),
))?;
let priority_fee = tx
.max_priority_fee_per_gas
.ok_or(EFTestRunnerError::Internal(
InternalError::FirstRunInternal(
"max_priority_fee_per_gas not found".to_string(),
),
))?;
let max_fee_per_gas = tx.max_fee_per_gas.ok_or(EFTestRunnerError::Internal(
InternalError::FirstRunInternal("max_fee_per_gas not found".to_string()),
))?;

Ok(std::cmp::min(
max_fee_per_gas,
current_base_fee + priority_fee,
))
}
Some(price) => Ok(price),
}
}
17 changes: 17 additions & 0 deletions crates/vm/levm/docs/validations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Transaction Validation

1. **GASLIMIT_PRICE_PRODUCT_OVERFLOW**: The product of gas limit and gas price is too high.
2. **INSUFFICIENT_ACCOUNT_FUNDS**: Sender does not have enough funds to pay for the gas.
3. **INSUFFICIENT_MAX_FEE_PER_GAS**: The max fee per gas is lower than the base fee per gas.
4. **INITCODE_SIZE_EXCEEDED**: The size of the initcode is too big.
5. **INTRINSIC_GAS_TOO_LOW**: The gas limit is lower than the intrinsic gas.
6. **NONCE_IS_MAX**: The nonce of the sender is at its maximum value.
7. **PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS**: The priority fee is greater than the max fee per gas.
8. **SENDER_NOT_EOA**: The sender is not an EOA (it has code).
9. **GAS_ALLOWANCE_EXCEEDED**: The gas limit is higher than the block gas limit.
10. **INSUFFICIENT_MAX_FEE_PER_BLOB_GAS**: The max fee per blob gas is lower than the base fee per gas.
11. **TYPE_3_TX_ZERO_BLOBS**: The transaction has zero blobs.
12. **TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH**: The blob versioned hash is invalid.
13. **TYPE_3_TX_PRE_FORK**: The transaction is a pre-cancun transaction.
14. **TYPE_3_TX_BLOB_COUNT_EXCEEDED**: The blob count is higher than the max allowed.
15. **TYPE_3_TX_CONTRACT_CREATION**: The type 3 transaction is a contract creation.
4 changes: 2 additions & 2 deletions crates/vm/levm/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ pub const MAX_BLOB_NUMBER_PER_BLOCK: usize = 6;

// Blob constants
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 MIN_BASE_FEE_PER_BLOB_GAS: u64 = 1;
pub const BLOB_BASE_FEE_UPDATE_FRACTION: u64 = 3338477;
pub const MAX_BLOB_COUNT: usize = 6;
pub const VALID_BLOB_PREFIXES: [u8; 2] = [0x01, 0x02];

Expand Down
14 changes: 12 additions & 2 deletions crates/vm/levm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,18 @@ pub struct TransactionReport {

impl TransactionReport {
/// Function to add gas to report without exceeding the maximum gas limit
pub fn add_gas_with_max(&mut self, gas: u64, max: u64) {
self.gas_used = self.gas_used.saturating_add(gas).min(max);
pub fn add_gas_with_max(&mut self, gas: u64, max: u64) -> Result<(), VMError> {
let new_gas_used = self
.gas_used
.checked_add(gas)
.ok_or(OutOfGasError::MaxGasLimitExceeded)?;

if new_gas_used > max {
return Err(VMError::OutOfGas(OutOfGasError::MaxGasLimitExceeded));
}

self.gas_used = new_gas_used;
Ok(())
}

pub fn is_success(&self) -> bool {
Expand Down
55 changes: 51 additions & 4 deletions crates/vm/levm/src/gas_cost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ pub const INIT_CODE_WORD_COST: U256 = U256([2, 0, 0, 0]);
pub const CODE_DEPOSIT_COST: U256 = U256([200, 0, 0, 0]);
pub const CREATE_BASE_COST: U256 = U256([32000, 0, 0, 0]);

// Calldata costs
pub const CALLDATA_COST_ZERO_BYTE: U256 = U256([4, 0, 0, 0]);
pub const CALLDATA_COST_NON_ZERO_BYTE: U256 = U256([16, 0, 0, 0]);

// Blob gas costs
pub const BLOB_GAS_PER_BLOB: U256 = U256([131072, 0, 0, 0]);

pub fn exp(exponent_bits: u64) -> Result<U256, OutOfGasError> {
let exponent_byte_size = (exponent_bits
.checked_add(7)
Expand Down Expand Up @@ -462,18 +469,18 @@ pub fn selfdestruct(address_was_cold: bool, account_is_empty: bool) -> Result<U2
Ok(gas_cost)
}

pub fn tx_calldata(calldata: &Bytes) -> Result<u64, OutOfGasError> {
pub fn tx_calldata(calldata: &Bytes) -> Result<U256, OutOfGasError> {
// This cost applies both for call and create
// 4 gas for each zero byte in the transaction data 16 gas for each non-zero byte in the transaction.
let mut calldata_cost: u64 = 0;
let mut calldata_cost: U256 = U256::zero();
for byte in calldata {
if *byte != 0 {
calldata_cost = calldata_cost
.checked_add(16)
.checked_add(CALLDATA_COST_NON_ZERO_BYTE)
.ok_or(OutOfGasError::GasUsedOverflow)?;
} else {
calldata_cost = calldata_cost
.checked_add(4)
.checked_add(CALLDATA_COST_ZERO_BYTE)
.ok_or(OutOfGasError::GasUsedOverflow)?;
}
}
Expand Down Expand Up @@ -720,3 +727,43 @@ pub fn staticcall(
.checked_add(dynamic_gas)
.ok_or(OutOfGasError::GasCostOverflow)?)
}

pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> Result<U256, VMError> {
let mut i = 1;
let mut output: u64 = 0;

// Initial multiplication: factor * denominator
let mut numerator_accum = factor
.checked_mul(denominator)
.ok_or(InternalError::ArithmeticOperationOverflow)?;

while numerator_accum > 0 {
// Safe addition to output
output = output
.checked_add(numerator_accum)
.ok_or(InternalError::ArithmeticOperationOverflow)?;

// Safe multiplication and division within loop
numerator_accum = numerator_accum
.checked_mul(numerator)
.ok_or(InternalError::ArithmeticOperationOverflow)?
.checked_div(
denominator
.checked_mul(i)
.ok_or(InternalError::ArithmeticOperationOverflow)?,
)
.ok_or(VMError::Internal(
InternalError::ArithmeticOperationOverflow,
))?;

i = i
.checked_add(1)
.ok_or(InternalError::ArithmeticOperationOverflow)?;
}

Ok(U256::from(
output
.checked_div(denominator)
.ok_or(InternalError::ArithmeticOperationOverflow)?,
))
}
Loading
Loading