Skip to content
This repository has been archived by the owner on Jan 8, 2025. It is now read-only.

Commit

Permalink
dev: cleaning (#781)
Browse files Browse the repository at this point in the history
  • Loading branch information
enitrat authored Apr 19, 2024
1 parent 5d1dca8 commit 7cfe1b2
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 139 deletions.
105 changes: 76 additions & 29 deletions crates/evm/src/backend/starknet_backend.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,32 @@ use contracts::kakarot_core::{
};
use core::num::traits::zero::Zero;
use evm::errors::{ensure, EVMError, EOA_EXISTS};
use evm::model::{Address, AddressTrait, Environment};
use evm::model::{Address, AddressTrait, Environment, Account, AccountTrait};
use evm::state::{State, StateTrait};
use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait};
use starknet::{
EthAddress, get_contract_address, deploy_syscall, get_tx_info, get_block_info,
SyscallResultTrait
};
use utils::constants;


/// Commits the state changes to Starknet.
///
/// # Arguments
///
/// * `state` - The state to commit.
///
/// # Returns
///
/// `Ok(())` if the commit was successful, otherwise an `EVMError`.
fn commit(ref state: State) -> Result<(), EVMError> {
internals::commit_accounts(ref state)?;
internals::transfer_native_token(ref state)?;
internals::emit_events(ref state)?;
internals::commit_storage(ref state)
}


/// Deploys a new EOA contract.
///
/// # Arguments
Expand Down Expand Up @@ -59,6 +68,7 @@ fn get_bytecode(evm_address: EthAddress) -> Span<u8> {
}
}

/// Populate an Environment with Starknet syscalls.
fn get_env(origin: EthAddress, gas_price: u128) -> Environment {
let kakarot_state = KakarotCore::unsafe_new_contract_state();
let block_info = get_block_info().unbox();
Expand All @@ -79,6 +89,41 @@ fn get_env(origin: EthAddress, gas_price: u128) -> Environment {
}
}

/// Fetches the value stored at the given key for the corresponding contract accounts.
/// If the account is not deployed (in case of a create/deploy transaction), returns 0.
/// # Arguments
///
/// * `account` The account to read from.
/// * `key` The key to read.
///
/// # Returns
///
/// A `Result` containing the value stored at the given key or an `EVMError` if there was an error.
fn fetch_original_storage(account: @Account, key: u256) -> u256 {
let is_deployed = account.evm_address().is_deployed();
if is_deployed {
return IAccountDispatcher { contract_address: account.starknet_address() }.storage(key);
}
0
}

/// Fetches the balance of the given address.
///
/// # Arguments
///
/// * `self` - The address to fetch the balance of.
///
/// # Returns
///
/// The balance of the given address.
fn fetch_balance(self: @Address) -> u256 {
let kakarot_state = KakarotCore::unsafe_new_contract_state();
let native_token_address = kakarot_state.get_native_token();
let native_token = IERC20CamelDispatcher { contract_address: native_token_address };
native_token.balanceOf(*self.starknet)
}


mod internals {
use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait};
use contracts::kakarot_core::{KakarotCore, KakarotCore::KakarotCoreImpl};
Expand All @@ -88,11 +133,20 @@ mod internals {
use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait};
use starknet::SyscallResultTrait;
use starknet::syscalls::{emit_event_syscall};
use super::{State, StateTrait};
use super::{State, StateTrait, deploy};
use utils::constants::BURN_ADDRESS;
use utils::set::{Set, SetTrait};


/// Commits the account changes to Starknet.
///
/// # Arguments
///
/// * `state` - The state containing the accounts to commit.
///
/// # Returns
///
/// `Ok(())` if the commit was successful, otherwise an `EVMError`.
fn commit_accounts(ref state: State) -> Result<(), EVMError> {
let mut account_keys = state.accounts.keyset.to_span();
loop {
Expand All @@ -109,26 +163,21 @@ mod internals {
/// Commits the account to Starknet by updating the account state if it
/// exists, or deploying a new account if it doesn't.
///
/// Only Contract Accounts can be modified.
///
/// # Arguments
/// * `self` - The account to commit
/// * `state` - The state, modified in the case of selfdestruct transfers
///
/// # Returns
///
/// `Ok(())` if the commit was successful, otherwise an `EVMError`.
//TODO: move state out in starknet backend
fn commit(self: @Account, ref state: State) {
let is_deployed = self.evm_address().is_deployed();

if self.is_precompile() {
if self.evm_address().is_precompile() {
return;
}

// Case new account
if !is_deployed {
// If SELFDESTRUCT, deploy empty SN account
self.deploy();
if !self.evm_address().is_deployed() {
deploy(self.evm_address()).expect('account deployment failed');

let has_code_or_nonce = self.has_code_or_nonce();
if !has_code_or_nonce {
Expand All @@ -140,10 +189,10 @@ mod internals {
// burning any leftover balance.
if (self.is_selfdestruct()) {
let kakarot_state = KakarotCore::unsafe_new_contract_state();
let starknet_address = kakarot_state
let burn_starknet_address = kakarot_state
.compute_starknet_address(BURN_ADDRESS.try_into().unwrap());
let burn_address = Address {
starknet: starknet_address, evm: BURN_ADDRESS.try_into().unwrap()
starknet: burn_starknet_address, evm: BURN_ADDRESS.try_into().unwrap()
};
state
.add_transfer(
Expand All @@ -155,37 +204,34 @@ mod internals {
return;
}

let account = IAccountDispatcher {
contract_address: self.get_registered_starknet_address()
};
account.write_bytecode(self.bytecode());
account.set_nonce(*self.nonce);
// Write bytecode and set nonce
let starknet_account = IAccountDispatcher { contract_address: self.starknet_address() };
starknet_account.write_bytecode(self.bytecode());
starknet_account.set_nonce(*self.nonce);

//TODO: storage commits are done in the State commitment
//Storage is handled outside of the account and must be committed after all accounts are committed.
return;
};

// If the account was not scheduled for deployment - then update it if it's deployed.

// @dev: EIP-6780 - If selfdestruct on an account created, dont commit data
let is_created_selfdestructed = self.is_selfdestruct() && self.is_created();
if is_created_selfdestructed {
// If the account was created and selfdestructed in the same transaction, we don't need to commit it.
return;
}

let account = IAccountDispatcher {
contract_address: self.get_registered_starknet_address()
};
let starknet_account = IAccountDispatcher { contract_address: self.starknet_address() };

account.set_nonce(*self.nonce);
//TODO: handle storage commitment
starknet_account.set_nonce(*self.nonce);
//TODO: storage commits are done in the State commitment
//Storage is handled outside of the account and must be committed after all accounts are committed.

// Update bytecode if required (SELFDESTRUCTed contract committed and redeployed)
//TODO: add bytecode_len entrypoint for optimization
let bytecode_len = account.bytecode().len();
let bytecode_len = starknet_account.bytecode().len();
if bytecode_len != self.bytecode().len() {
account.write_bytecode(self.bytecode());
starknet_account.write_bytecode(self.bytecode());
}
}

Expand Down Expand Up @@ -237,7 +283,8 @@ mod internals {
.get(*state_key)
.deref();
let mut account = self.get_account(evm_address);
account.commit_storage(key, value);
IAccountDispatcher { contract_address: account.starknet_address() }
.write_storage(key, value);
},
Option::None => { break Result::Ok(()); }
}
Expand Down
5 changes: 0 additions & 5 deletions crates/evm/src/call_helpers.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,3 @@ impl CallHelpersImpl of CallHelpers {
}
}

/// Check whether an address for a call-family opcode is a precompile.
fn is_precompile(self: EthAddress) -> bool {
let self: felt252 = self.into();
return (self != 0 && (self.into() < 10_u256 || self.into() == 256_u256));
}
4 changes: 3 additions & 1 deletion crates/evm/src/instructions/environmental_information.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use evm::gas;
use evm::memory::MemoryTrait;
use evm::model::account::{AccountTrait};
use evm::model::vm::{VM, VMTrait};
use evm::model::{AddressTrait};
use evm::stack::StackTrait;
use evm::state::StateTrait;
use keccak::cairo_keccak;
Expand Down Expand Up @@ -299,7 +300,8 @@ impl EnvironmentInformationImpl of EnvironmentInformationTrait {
let account = self.env.state.get_account(evm_address);
// Relevant cases:
// https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L392
if account.is_precompile() || (!account.has_code_or_nonce() && account.balance.is_zero()) {
if account.evm_address().is_precompile()
|| (!account.has_code_or_nonce() && account.balance.is_zero()) {
return self.stack.push(0);
}
let bytecode = account.code;
Expand Down
3 changes: 2 additions & 1 deletion crates/evm/src/instructions/memory_operations.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::hash::{HashStateTrait, HashStateExTrait};
use core::poseidon::PoseidonTrait;
use evm::backend::starknet_backend::fetch_original_storage;
//! Stack Memory Storage and Flow Operations.
use evm::errors::{EVMError, ensure, INVALID_DESTINATION, READ_SYSCALL_FAILED};
use evm::gas;
Expand Down Expand Up @@ -99,7 +100,7 @@ impl MemoryOperation of MemoryOperationTrait {
let new_value = self.stack.pop()?;
let evm_address = self.message().target.evm;
let account = self.env.state.get_account(evm_address);
let original_value = account.read_storage(key);
let original_value = fetch_original_storage(@account, key);
let current_value = self.env.state.read_state(evm_address, key);

// GAS
Expand Down
5 changes: 2 additions & 3 deletions crates/evm/src/interpreter.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use evm::call_helpers::is_precompile;
use evm::create_helpers::CreateHelpers;
use evm::errors::{EVMError, ensure, PC_OUT_OF_BOUNDS, EVMErrorTrait, CONTRACT_ACCOUNT_EXISTS};

Expand All @@ -14,7 +13,7 @@ use evm::model::account::{AccountTrait};
use evm::model::vm::{VM, VMTrait};
use evm::model::{
Message, Environment, Address, Transfer, ExecutionSummary, ExecutionSummaryTrait,
ExecutionResult, ExecutionResultTrait
ExecutionResult, ExecutionResultTrait, AddressTrait
};
use evm::precompiles::Precompiles;
use evm::stack::{Stack, StackTrait};
Expand Down Expand Up @@ -140,7 +139,7 @@ impl EVMImpl of EVMTrait {

fn execute_code(ref vm: VM) -> ExecutionResult {
// Handle precompile logic
if is_precompile(vm.message.target.evm) {
if vm.message.target.evm.is_precompile() {
let result = Precompiles::exec_precompile(ref vm);

match result {
Expand Down
10 changes: 4 additions & 6 deletions crates/evm/src/model.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use core::num::traits::Zero;
use evm::errors::{EVMError, CONTRACT_SYSCALL_FAILED};
use evm::model::account::{Account, AccountTrait};
use evm::state::State;
use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait};
use starknet::{EthAddress, get_contract_address, ContractAddress};
use utils::checked_math::CheckedMath;
use utils::fmt::{TSpanSetDebug};
Expand Down Expand Up @@ -137,11 +136,10 @@ impl AddressImpl of AddressTrait {
return address.is_non_zero();
}

fn fetch_balance(self: @Address) -> u256 {
let kakarot_state = KakarotCore::unsafe_new_contract_state();
let native_token_address = kakarot_state.get_native_token();
let native_token = IERC20CamelDispatcher { contract_address: native_token_address };
native_token.balanceOf(*self.starknet)
/// Check whether an address for a call-family opcode is a precompile.
fn is_precompile(self: EthAddress) -> bool {
let self: felt252 = self.into();
return (self != 0 && (self.into() < 10_u256 || self.into() == 256_u256));
}
}

Expand Down
Loading

0 comments on commit 7cfe1b2

Please sign in to comment.