Skip to content

Commit

Permalink
Merge branch 'main' into l2/forbid-expects
Browse files Browse the repository at this point in the history
  • Loading branch information
fborello-lambda authored Nov 27, 2024
2 parents a77da2c + 9881520 commit 42839de
Show file tree
Hide file tree
Showing 14 changed files with 257 additions and 63 deletions.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion .github/workflows/asertoor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Setup kurtosis testnet and run assertoor tests
uses: ethpandaops/kurtosis-assertoor-github-action@v1
with:
kurtosis_version: "1.3.1"
kurtosis_version: "1.4.2"
ethereum_package_url: "github.com/lambdaclass/ethereum-package"
ethereum_package_branch: "ethrex-integration"
ethereum_package_args: "./test_data/network_params.yaml"
6 changes: 3 additions & 3 deletions .github/workflows/docker_publish.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
name: Publish docker image to Github Packages
name: Publish Docker

on:
push:
branches: ["main"]
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push-image:
name: Build and push Docker image
runs-on: ubuntu-latest

# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
Expand Down Expand Up @@ -45,8 +47,6 @@ jobs:
context: .
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/hive_coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ jobs:
- name: Post results to levm slack channel
env:
url: ${{ secrets.LEVM_SLACK_WEBHOOK }}
run: sh publish.sh
run: sh .github/scripts/publish.sh
6 changes: 3 additions & 3 deletions .github/workflows/loc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ jobs:
- name: Post results to ethrex L1 slack channel
env:
url: ${{ secrets.ETHREX_L1_SLACK_WEBHOOK }}
run: sh publish_loc.sh
run: sh .github/scripts/publish_loc.sh

- name: Post results to ethrex L2 slack channel
env:
url: ${{ secrets.ETHREX_L2_SLACK_WEBHOOK }}
run: sh publish_loc.sh
run: sh .github/scripts/publish_loc.sh

- name: Post results to levm slack channel
env:
url: ${{ secrets.LEVM_SLACK_WEBHOOK }}
run: sh publish_loc.sh
run: sh .github/scripts/publish_loc.sh
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ At a high level, the following new parts are added to the node:
| 6 | Support multiple L2s sharing the same bridge contract on L1 for seamless interoperability. ||
| 7 | The L2 can also be deployed using a custom native token, meaning that a certain ERC20 can be the common currency that's used for paying network fees. ||
| 8 | The L2 has added security mechanisms in place, running on Trusted Execution Environments and Multi Prover setup where multiple guarantees (Execution on TEEs, zkVMs/proving systems) are required for settlement on the L1. This better protects against possible security bugs on implementations. ||
| 9 | The network can be run as a Based Rollup, meaning sequencing is done by the Ethereum Validator set; transactions are sent to a private mempool and L1 Validators that opt into the L2 sequencing propose blocks for the L2 on every L1 block. ||
| 10 | The L2 can be initialized in Validium Mode, meaning the Data Availability layer is no longer the L1, but rather a DA layer of the user's choice. ||
| 9 | The L2 can be initialized in Validium Mode, meaning the Data Availability layer is no longer the L1, but rather a DA layer of the user's choice. ||
| 10 | The network can be run as a Based Rollup, meaning sequencing is done by the Ethereum Validator set; transactions are sent to a private mempool and L1 Validators that opt into the L2 sequencing propose blocks for the L2 on every L1 block. ||

### Milestone 0

Expand Down Expand Up @@ -416,7 +416,11 @@ The L2 has added security mechanisms in place, running on Trusted Execution Envi
| Support verifying multiple different zkVM executions on the `onChainProposer` L1 contract. ||
| Support running the operator on a TEE environment ||

### Milestone 9: Based Contestable Rollup
### Milestone 9: Validium

The L2 can be initialized in Validium Mode, meaning the Data Availability layer is no longer the L1, but rather a DA layer of the user's choice.

### Milestone 10: Based Contestable Rollup

The network can be run as a Based Rollup, meaning sequencing is done by the Ethereum Validator set; transactions are sent to a private mempool and L1 Validators that opt into the L2 sequencing propose blocks for the L2 on every L1 block.

Expand All @@ -428,10 +432,6 @@ The network can be run as a Based Rollup, meaning sequencing is done by the Ethe

TODO: Expand on this.

### Milestone 10: Validium

The L2 can be initialized in Validium Mode, meaning the Data Availability layer is no longer the L1, but rather a DA layer of the user's choice.

#### Status

| Task Description | Status |
Expand Down
89 changes: 88 additions & 1 deletion cmd/ef_tests/levm/report.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::runner::{EFTestRunnerError, InternalError};
use colored::Colorize;
use ethrex_core::{Address, H256};
use ethrex_levm::errors::{TransactionReport, TxResult, VMError};
use ethrex_levm::{
errors::{TransactionReport, TxResult, VMError},
Account, StorageSlot,
};
use ethrex_storage::{error::StoreError, AccountUpdate};
use ethrex_vm::SpecId;
use revm::primitives::{EVMError, ExecutionResult as RevmExecutionResult};
Expand Down Expand Up @@ -340,6 +343,7 @@ impl EFTestReport {

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct AccountUpdatesReport {
pub initial_accounts: HashMap<Address, Account>,
pub levm_account_updates: Vec<AccountUpdate>,
pub revm_account_updates: Vec<AccountUpdate>,
pub levm_updated_accounts_only: HashSet<Address>,
Expand All @@ -353,6 +357,89 @@ impl fmt::Display for AccountUpdatesReport {
for levm_updated_account_only in self.levm_updated_accounts_only.iter() {
writeln!(f, " {levm_updated_account_only:#x}:")?;
writeln!(f, "{}", " Was updated in LEVM but not in REVM".red())?;
let initial_account = self
.initial_accounts
.get(levm_updated_account_only)
.cloned()
.unwrap_or_default();
let updated_account_update = self
.levm_account_updates
.iter()
.find(|account_update| &account_update.address == levm_updated_account_only)
.unwrap();
let updated_account_storage = updated_account_update
.added_storage
.iter()
.map(|(key, value)| {
let storage_slot = StorageSlot {
original_value: *value,
current_value: *value,
};
(*key, storage_slot)
})
.collect();
let updated_account_info = updated_account_update.info.clone().unwrap();
let updated_account = Account::new(
updated_account_info.balance,
updated_account_update.code.clone().unwrap_or_default(),
updated_account_info.nonce,
updated_account_storage,
);
let mut updates = 0;
if initial_account.info.balance != updated_account.info.balance {
writeln!(
f,
"{}",
format!(
" Balance updated: {initial_balance} -> {updated_balance}",
initial_balance = initial_account.info.balance,
updated_balance = updated_account.info.balance
)
.red()
)?;
updates += 1;
}
if initial_account.info.nonce != updated_account.info.nonce {
writeln!(
f,
"{}",
format!(
" Nonce updated: {initial_nonce} -> {updated_nonce}",
initial_nonce = initial_account.info.nonce,
updated_nonce = updated_account.info.nonce
)
.red()
)?;
updates += 1;
}
if initial_account.info.bytecode != updated_account.info.bytecode {
writeln!(
f,
"{}",
format!(
" Code updated: {initial_code}, {updated_code}",
initial_code = hex::encode(&initial_account.info.bytecode),
updated_code = hex::encode(&updated_account.info.bytecode)
)
.red()
)?;
updates += 1;
}
for (added_storage_address, added_storage_slot) in updated_account.storage.iter() {
writeln!(
f,
"{}",
format!(
" Storage slot added: {added_storage_address}: {} -> {}",
added_storage_slot.original_value, added_storage_slot.current_value
)
.red()
)?;
updates += 1;
}
if updates == 0 {
writeln!(f, "{}", " No changes".green())?;
}
}
for revm_updated_account_only in self.revm_updated_accounts_only.iter() {
writeln!(f, " {revm_updated_account_only:#x}:")?;
Expand Down
48 changes: 43 additions & 5 deletions cmd/ef_tests/levm/runner/revm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ use crate::{
types::EFTest,
utils::load_initial_state,
};
use ethrex_core::{types::TxKind, Address};
use ethrex_levm::errors::{TransactionReport, TxResult};
use ethrex_core::{types::TxKind, Address, H256};
use ethrex_levm::{
errors::{TransactionReport, TxResult},
Account, StorageSlot,
};
use ethrex_storage::{error::StoreError, AccountUpdate};
use ethrex_vm::{db::StoreWrapper, EvmState, RevmAddress, RevmU256, SpecId};
use revm::{
Expand All @@ -17,7 +20,7 @@ use revm::{
},
Evm as Revm,
};
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};

pub fn re_run_failed_ef_test(
test: &EFTest,
Expand Down Expand Up @@ -245,8 +248,11 @@ pub fn ensure_post_state(
None => {
let levm_account_updates = levm_runner::get_state_transitions(levm_execution_report);
let revm_account_updates = ethrex_vm::get_state_transitions(revm_state);
let account_updates_report =
compare_levm_revm_account_updates(&levm_account_updates, &revm_account_updates);
let account_updates_report = compare_levm_revm_account_updates(
test,
&levm_account_updates,
&revm_account_updates,
);
re_run_report.register_account_updates_report(*vector, account_updates_report);
}
}
Expand All @@ -255,9 +261,40 @@ pub fn ensure_post_state(
}

pub fn compare_levm_revm_account_updates(
test: &EFTest,
levm_account_updates: &[AccountUpdate],
revm_account_updates: &[AccountUpdate],
) -> AccountUpdatesReport {
let mut initial_accounts: HashMap<Address, Account> = test
.pre
.0
.iter()
.map(|(account_address, pre_state_value)| {
let account_storage = pre_state_value
.storage
.iter()
.map(|(key, value)| {
let mut temp = [0u8; 32];
key.to_big_endian(&mut temp);
let storage_slot = StorageSlot {
original_value: *value,
current_value: *value,
};
(H256::from_slice(&temp), storage_slot)
})
.collect();
let account = Account::new(
pre_state_value.balance,
pre_state_value.code.clone(),
pre_state_value.nonce.as_u64(),
account_storage,
);
(*account_address, account)
})
.collect();
initial_accounts
.entry(test.env.current_coinbase)
.or_default();
let levm_updated_accounts = levm_account_updates
.iter()
.map(|account_update| account_update.address)
Expand All @@ -268,6 +305,7 @@ pub fn compare_levm_revm_account_updates(
.collect::<HashSet<Address>>();

AccountUpdatesReport {
initial_accounts,
levm_account_updates: levm_account_updates.to_vec(),
revm_account_updates: revm_account_updates.to_vec(),
levm_updated_accounts_only: levm_updated_accounts
Expand Down
75 changes: 37 additions & 38 deletions crates/vm/levm/src/opcode_handlers/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,28 +134,32 @@ impl VM {
) -> Result<OpcodeSuccess, VMError> {
self.increase_consumed_gas(current_call_frame, gas_cost::SMOD)?;

let dividend = current_call_frame.stack.pop()?;
let divisor = current_call_frame.stack.pop()?;
if divisor.is_zero() {
let unchecked_dividend = current_call_frame.stack.pop()?;
let unchecked_divisor = current_call_frame.stack.pop()?;

if unchecked_divisor.is_zero() {
current_call_frame.stack.push(U256::zero())?;
} else {
let normalized_dividend = abs(dividend);
let normalized_divisor = abs(divisor);

let mut remainder =
normalized_dividend
.checked_rem(normalized_divisor)
.ok_or(VMError::Internal(
InternalError::ArithmeticOperationDividedByZero,
))?; // Cannot be zero bc if above;

// The remainder should have the same sign as the dividend
if is_negative(dividend) {
remainder = negate(remainder);
return Ok(OpcodeSuccess::Continue);
}

let divisor = abs(unchecked_divisor);
let dividend = abs(unchecked_dividend);

let unchecked_remainder = match dividend.checked_rem(divisor) {
Some(remainder) => remainder,
None => {
current_call_frame.stack.push(U256::zero())?;
return Ok(OpcodeSuccess::Continue);
}
};

current_call_frame.stack.push(remainder)?;
}
let remainder = if is_negative(unchecked_dividend) {
negate(unchecked_remainder)
} else {
unchecked_remainder
};

current_call_frame.stack.push(remainder)?;

Ok(OpcodeSuccess::Continue)
}
Expand All @@ -169,20 +173,16 @@ impl VM {

let augend = current_call_frame.stack.pop()?;
let addend = current_call_frame.stack.pop()?;
let divisor = current_call_frame.stack.pop()?;
if divisor.is_zero() {
current_call_frame.stack.push(U256::zero())?;
return Ok(OpcodeSuccess::Continue);
}
let (sum, overflow) = augend.overflowing_add(addend);
let mut remainder = sum.checked_rem(divisor).ok_or(VMError::Internal(
InternalError::ArithmeticOperationDividedByZero,
))?; // Cannot be zero bc if above;
if overflow || remainder > divisor {
remainder = remainder.overflowing_sub(divisor).0;
}
let modulus = current_call_frame.stack.pop()?;

current_call_frame.stack.push(remainder)?;
let new_augend = augend.checked_rem(modulus).unwrap_or_default();
let new_addend = addend.checked_rem(modulus).unwrap_or_default();

let (sum, _overflowed) = new_augend.overflowing_add(new_addend);

let sum_mod = sum.checked_rem(modulus).unwrap_or_default();

current_call_frame.stack.push(sum_mod)?;

Ok(OpcodeSuccess::Continue)
}
Expand Down Expand Up @@ -298,16 +298,15 @@ fn is_negative(value: U256) -> bool {
}

/// Negates a number in two's complement
fn negate(value: U256) -> U256 {
let (dividend, _overflowed) = (!value).overflowing_add(U256::one());
dividend
}

fn abs(value: U256) -> U256 {
if is_negative(value) {
negate(value)
} else {
value
}
}

/// Negates a number in two's complement
fn negate(value: U256) -> U256 {
let inverted = !value;
inverted.saturating_add(U256::one())
}
Loading

0 comments on commit 42839de

Please sign in to comment.