Skip to content

Commit 9f0148f

Browse files
fborello-lambdajrchatructomip01
authored
feat(levm): pectra-devnet6 eftests (#1877)
**Motivation** The latest test for pectra has been released. [Pectra Devnet 6 ](https://github.com/ethereum/execution-spec-tests/releases/tag/pectra-devnet-6%40v1.0.0) **Description** - Download latest tests - Add eip7702 latest changes: ethereum/EIPs#9248 - Add a new CI rule for EF Tests to be 100% from London to Prague forks - Fix tests from `set_code_txs_2` and `refunds` belonging to EIP 7702 and EIP 7623 --------- Co-authored-by: Javier Chatruc <[email protected]> Co-authored-by: Tomás Paradelo <[email protected]>
1 parent 567d32c commit 9f0148f

File tree

5 files changed

+61
-76
lines changed

5 files changed

+61
-76
lines changed

.github/workflows/ci_levm.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ jobs:
113113
name: main-ef-test-data
114114
path: crates/vm/levm/test_result_main_short.txt
115115

116+
# This is for ensuring test from merge to Prague are passing.
117+
# After adding the Legacy Test suite, not all are passing.
118+
# This is a temporary solution until we fix the legacy tests.
119+
- name: Check EF-TESTS from London to Prague is 100%
120+
run: |
121+
cd crates/vm/levm
122+
awk '/Prague:/, /London:/ {print $1, $3}' test_result_main.txt | sed 's/[()]//g' | grep -v '100.00%' && echo "All percentage are not 100%." && exit 1 || echo "All percentage are 100%."
123+
116124
- name: Check EF-TESTS status is 100%
117125
run: |
118126
cd crates/vm/levm

crates/vm/levm/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ ETH_TEST_URL := https://github.com/ethereum/tests.git
2424
ETH_TEST_TAG := v14.1
2525
COMMIT_LEGACY_TESTS_FOR_TAG := b2e6c9e
2626

27-
STATETEST_VERSION := pectra-devnet-5%40v1.1.0
28-
STATETEST_NET := pectra-devnet-5
27+
STATETEST_VERSION := pectra-devnet-6%40v1.0.0
28+
STATETEST_NET := pectra-devnet-6
2929
STATETEST_ARTIFACT := fixtures_$(STATETEST_NET).tar.gz
3030
STATETEST_URL := https://github.com/ethereum/execution-spec-tests/releases/download/$(STATETEST_VERSION)/fixtures_$(STATETEST_NET).tar.gz
3131

crates/vm/levm/src/hooks/default_hook.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,21 +363,30 @@ impl Hook for DefaultHook {
363363

364364
// 2. Return unused gas + gas refunds to the sender.
365365
let max_gas = vm.env.gas_limit;
366-
let consumed_gas = report.gas_used;
366+
let mut consumed_gas = report.gas_used;
367367
// [EIP-3529](https://eips.ethereum.org/EIPS/eip-3529)
368368
let quotient = if vm.env.config.fork < Fork::London {
369369
MAX_REFUND_QUOTIENT_PRE_LONDON
370370
} else {
371371
MAX_REFUND_QUOTIENT
372372
};
373-
let refunded_gas = report.gas_refunded.min(
373+
let mut refunded_gas = report.gas_refunded.min(
374374
consumed_gas
375375
.checked_div(quotient)
376376
.ok_or(VMError::Internal(InternalError::UndefinedState(-1)))?,
377377
);
378378
// "The max refundable proportion of gas was reduced from one half to one fifth by EIP-3529 by Buterin and Swende [2021] in the London release"
379379
report.gas_refunded = refunded_gas;
380380

381+
if vm.env.config.fork >= Fork::Prague {
382+
let floor_gas_price = vm.get_floor_gas_price(initial_call_frame)?;
383+
let execution_gas_used = consumed_gas.saturating_sub(refunded_gas);
384+
if floor_gas_price > execution_gas_used {
385+
consumed_gas = floor_gas_price;
386+
refunded_gas = 0;
387+
}
388+
}
389+
381390
let gas_to_return = max_gas
382391
.checked_sub(consumed_gas)
383392
.and_then(|gas| gas.checked_add(refunded_gas))

crates/vm/levm/src/opcode_handlers/environment.rs

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use crate::{
22
call_frame::CallFrame,
3-
constants::SET_CODE_DELEGATION_BYTES,
43
errors::{InternalError, OpcodeResult, VMError},
54
gas_cost::{self},
65
memory::{self, calculate_memory_size},
7-
utils::{access_account, has_delegation, word_to_address},
6+
utils::{access_account, word_to_address},
87
vm::VM,
98
};
109
use ethrex_common::{types::Fork, U256};
@@ -294,19 +293,14 @@ impl VM {
294293
address,
295294
);
296295

297-
// https://eips.ethereum.org/EIPS/eip-7702#delegation-designation
298-
let is_delegation = has_delegation(&account_info)?;
299-
300296
current_call_frame.increase_consumed_gas(gas_cost::extcodesize(
301297
address_was_cold,
302298
self.env.config.fork,
303299
)?)?;
304300

305-
current_call_frame.stack.push(if is_delegation {
306-
SET_CODE_DELEGATION_BYTES[..2].len().into()
307-
} else {
308-
account_info.bytecode.len().into()
309-
})?;
301+
current_call_frame
302+
.stack
303+
.push(account_info.bytecode.len().into())?;
310304

311305
Ok(OpcodeResult::Continue { pc_increment: 1 })
312306
}
@@ -334,9 +328,6 @@ impl VM {
334328

335329
let new_memory_size = calculate_memory_size(dest_offset, size)?;
336330

337-
// https://eips.ethereum.org/EIPS/eip-7702#delegation-designation
338-
let is_delegation = has_delegation(&account_info)?;
339-
340331
current_call_frame.increase_consumed_gas(gas_cost::extcodecopy(
341332
size,
342333
new_memory_size,
@@ -349,11 +340,9 @@ impl VM {
349340
return Ok(OpcodeResult::Continue { pc_increment: 1 });
350341
}
351342

352-
let bytecode = if is_delegation {
353-
SET_CODE_DELEGATION_BYTES[..2].into()
354-
} else {
355-
account_info.bytecode
356-
};
343+
// If the bytecode is a delegation designation, it will copy the marker (0xef0100) || address.
344+
// https://eips.ethereum.org/EIPS/eip-7702#delegation-designation
345+
let bytecode = account_info.bytecode;
357346

358347
let mut data = vec![0u8; size];
359348
if offset < bytecode.len().into() {
@@ -467,29 +456,20 @@ impl VM {
467456
address,
468457
);
469458

470-
// https://eips.ethereum.org/EIPS/eip-7702#delegation-designation
471-
let is_delegation = has_delegation(&account_info)?;
472-
473459
current_call_frame.increase_consumed_gas(gas_cost::extcodehash(
474460
address_was_cold,
475461
self.env.config.fork,
476462
)?)?;
477463

478-
if is_delegation {
479-
let hash =
480-
U256::from_big_endian(keccak(&SET_CODE_DELEGATION_BYTES[..2]).as_fixed_bytes());
481-
current_call_frame.stack.push(hash)?;
482-
} else {
483-
// An account is considered empty when it has no code and zero nonce and zero balance. [EIP-161]
484-
if account_info.is_empty() {
485-
current_call_frame.stack.push(U256::zero())?;
486-
return Ok(OpcodeResult::Continue { pc_increment: 1 });
487-
}
488-
489-
let hash = U256::from_big_endian(keccak(account_info.bytecode).as_fixed_bytes());
490-
current_call_frame.stack.push(hash)?;
464+
// An account is considered empty when it has no code and zero nonce and zero balance. [EIP-161]
465+
if account_info.is_empty() {
466+
current_call_frame.stack.push(U256::zero())?;
467+
return Ok(OpcodeResult::Continue { pc_increment: 1 });
491468
}
492469

470+
let hash = U256::from_big_endian(keccak(account_info.bytecode).as_fixed_bytes());
471+
current_call_frame.stack.push(hash)?;
472+
493473
Ok(OpcodeResult::Continue { pc_increment: 1 })
494474
}
495475
}

crates/vm/levm/src/vm.rs

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use ethrex_common::{
2626
Address, H256, U256,
2727
};
2828
use std::{
29-
cmp::max,
3029
collections::{HashMap, HashSet},
3130
fmt::Debug,
3231
sync::Arc,
@@ -360,42 +359,33 @@ impl VM {
360359
matches!(self.tx_kind, TxKind::Create)
361360
}
362361

363-
fn gas_used(
364-
&self,
365-
initial_call_frame: &CallFrame,
366-
report: &ExecutionReport,
367-
) -> Result<u64, VMError> {
368-
if self.env.config.fork >= Fork::Prague {
369-
// If the transaction is a CREATE transaction, the calldata is emptied and the bytecode is assigned.
370-
let calldata = if self.is_create() {
371-
&initial_call_frame.bytecode
372-
} else {
373-
&initial_call_frame.calldata
374-
};
375-
376-
// tokens_in_calldata = nonzero_bytes_in_calldata * 4 + zero_bytes_in_calldata
377-
// tx_calldata = nonzero_bytes_in_calldata * 16 + zero_bytes_in_calldata * 4
378-
// this is actually tokens_in_calldata * STANDARD_TOKEN_COST
379-
// see it in https://eips.ethereum.org/EIPS/eip-7623
380-
let tokens_in_calldata: u64 = gas_cost::tx_calldata(calldata, self.env.config.fork)
381-
.map_err(VMError::OutOfGas)?
382-
.checked_div(STANDARD_TOKEN_COST)
383-
.ok_or(VMError::Internal(InternalError::DivisionError))?;
384-
385-
// floor_gas_price = TX_BASE_COST + TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata
386-
let mut floor_gas_price: u64 = tokens_in_calldata
387-
.checked_mul(TOTAL_COST_FLOOR_PER_TOKEN)
388-
.ok_or(VMError::Internal(InternalError::GasOverflow))?;
389-
390-
floor_gas_price = floor_gas_price
391-
.checked_add(TX_BASE_COST)
392-
.ok_or(VMError::Internal(InternalError::GasOverflow))?;
393-
394-
let gas_used = max(floor_gas_price, report.gas_used);
395-
Ok(gas_used)
362+
pub fn get_floor_gas_price(&self, initial_call_frame: &CallFrame) -> Result<u64, VMError> {
363+
// If the transaction is a CREATE transaction, the calldata is emptied and the bytecode is assigned.
364+
let calldata = if self.is_create() {
365+
&initial_call_frame.bytecode
396366
} else {
397-
Ok(report.gas_used)
398-
}
367+
&initial_call_frame.calldata
368+
};
369+
370+
// tokens_in_calldata = nonzero_bytes_in_calldata * 4 + zero_bytes_in_calldata
371+
// tx_calldata = nonzero_bytes_in_calldata * 16 + zero_bytes_in_calldata * 4
372+
// this is actually tokens_in_calldata * STANDARD_TOKEN_COST
373+
// see it in https://eips.ethereum.org/EIPS/eip-7623
374+
let tokens_in_calldata: u64 = gas_cost::tx_calldata(calldata, self.env.config.fork)
375+
.map_err(VMError::OutOfGas)?
376+
.checked_div(STANDARD_TOKEN_COST)
377+
.ok_or(VMError::Internal(InternalError::DivisionError))?;
378+
379+
// floor_gas_price = TX_BASE_COST + TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata
380+
let mut floor_gas_price: u64 = tokens_in_calldata
381+
.checked_mul(TOTAL_COST_FLOOR_PER_TOKEN)
382+
.ok_or(VMError::Internal(InternalError::GasOverflow))?;
383+
384+
floor_gas_price = floor_gas_price
385+
.checked_add(TX_BASE_COST)
386+
.ok_or(VMError::Internal(InternalError::GasOverflow))?;
387+
388+
Ok(floor_gas_price)
399389
}
400390

401391
pub fn execute(&mut self) -> Result<ExecutionReport, VMError> {
@@ -434,8 +424,6 @@ impl VM {
434424

435425
let mut report = self.run_execution(&mut initial_call_frame)?;
436426

437-
report.gas_used = self.gas_used(&initial_call_frame, &report)?;
438-
439427
self.finalize_execution(&initial_call_frame, &mut report)?;
440428

441429
report.new_state.clone_from(&self.cache);

0 commit comments

Comments
 (0)