diff --git a/crates/contracts/src/account_contract.cairo b/crates/contracts/src/account_contract.cairo index 7149adb67..0bb162056 100644 --- a/crates/contracts/src/account_contract.cairo +++ b/crates/contracts/src/account_contract.cairo @@ -66,10 +66,8 @@ pub mod AccountContract { use core::starknet::{ EthAddress, ClassHash, get_caller_address, get_tx_info, get_block_timestamp }; - use core::traits::TryInto; use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; use super::OutsideExecution; - use utils::constants::{POW_2_32}; use utils::eth_transaction::transaction::TransactionUnsignedTrait; use utils::serialization::{deserialize_signature, deserialize_bytes, serialize_bytes}; use utils::traits::DefaultSignature; @@ -241,7 +239,9 @@ pub mod AccountContract { // EOA Validation assert(self.Account_bytecode_len.read().is_zero(), 'EOA: cannot have code'); - let chain_id: u64 = tx_info.chain_id.try_into().unwrap() % POW_2_32.try_into().unwrap(); + let kakarot = IEthRPCDispatcher { contract_address: self.ownable.owner() }; + + let chain_id: u64 = kakarot.eth_chain_id(); assert(signature.len() == 5, 'EOA: Invalid signature length'); let signature = deserialize_signature(signature, chain_id) .expect('EOA: invalid signature'); @@ -257,7 +257,6 @@ pub mod AccountContract { let address = self.Account_evm_address.read(); verify_eth_signature(unsigned_transaction.hash, signature, address); - let kakarot = IEthRPCDispatcher { contract_address: self.ownable.owner() }; //TODO: refactor this to call eth_send_raw_unsigned_tx. Only the transactions bytes are //passed. let (success, return_data, gas_used) = kakarot diff --git a/crates/contracts/src/kakarot_core/eth_rpc.cairo b/crates/contracts/src/kakarot_core/eth_rpc.cairo index 59794ae05..9e7786353 100644 --- a/crates/contracts/src/kakarot_core/eth_rpc.cairo +++ b/crates/contracts/src/kakarot_core/eth_rpc.cairo @@ -8,6 +8,7 @@ use evm::backend::starknet_backend; use evm::backend::validation::validate_eth_tx; use evm::model::{TransactionResult, Address}; use evm::{EVMTrait}; +use utils::constants::POW_2_53; use utils::eth_transaction::transaction::{TransactionTrait, Transaction}; #[starknet::interface] @@ -130,7 +131,9 @@ pub impl EthRPC< } fn eth_chain_id(self: @TContractState) -> u64 { - panic!("unimplemented") + let tx_info = get_tx_info().unbox(); + let tx_chain_id: u64 = tx_info.chain_id.try_into().unwrap(); + tx_chain_id % POW_2_53.try_into().unwrap() } fn eth_call( @@ -210,3 +213,55 @@ fn is_view(self: @KakarotCore::ContractState) -> bool { } true } + +#[cfg(test)] +mod tests { + use contracts::kakarot_core::KakarotCore; + use contracts::kakarot_core::eth_rpc::IEthRPC; + use snforge_std::{start_cheat_chain_id_global, stop_cheat_chain_id_global}; + use utils::constants::POW_2_53; + + fn set_up() -> KakarotCore::ContractState { + // Define the kakarot state to access contract functions + let kakarot_state = KakarotCore::unsafe_new_contract_state(); + + kakarot_state + } + + fn tear_down() { + stop_cheat_chain_id_global(); + } + + + #[test] + fn test_eth_chain_id_returns_input_when_less_than_pow_2_53() { + let kakarot_state = KakarotCore::unsafe_new_contract_state(); + // Convert POW_2_53 - 1 to u64 since POW_2_53 is defined as u128 + let chain_id: u64 = (POW_2_53 - 1).try_into().unwrap(); + start_cheat_chain_id_global(chain_id.into()); + assert_eq!( + kakarot_state.eth_chain_id(), + chain_id, + "Should return original chain ID when below 2^53" + ); + tear_down(); + } + + #[test] + fn test_eth_chain_id_returns_modulo_when_greater_than_or_equal_to_pow_2_53() { + // Test with a value equal to 2^53 + let kakarot_state = set_up(); + let chain_id: u64 = POW_2_53.try_into().unwrap(); + start_cheat_chain_id_global(chain_id.into()); + assert_eq!(kakarot_state.eth_chain_id(), 0, "Should return 0 when chain ID is 2^53"); + + // Test with a value greater than 2^53 + let chain_id: u64 = (POW_2_53 + 53).try_into().unwrap(); + start_cheat_chain_id_global(chain_id.into()); + assert_eq!( + kakarot_state.eth_chain_id(), 53, "Should return correct value after modulo operation" + ); + tear_down(); + } +} + diff --git a/crates/evm/src/backend/starknet_backend.cairo b/crates/evm/src/backend/starknet_backend.cairo index ea764db9d..5298e5c36 100644 --- a/crates/evm/src/backend/starknet_backend.cairo +++ b/crates/evm/src/backend/starknet_backend.cairo @@ -1,11 +1,12 @@ use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; +use contracts::kakarot_core::eth_rpc::IEthRPC; use contracts::kakarot_core::{KakarotCore, KakarotCore::KakarotCoreImpl}; use core::num::traits::zero::Zero; use core::ops::SnapshotDeref; use core::starknet::storage::StoragePointerReadAccess; use core::starknet::syscalls::{deploy_syscall}; use core::starknet::syscalls::{emit_event_syscall}; -use core::starknet::{EthAddress, get_tx_info, get_block_info, SyscallResultTrait}; +use core::starknet::{EthAddress, get_block_info, SyscallResultTrait}; use evm::errors::{ensure, EVMError, EOA_EXISTS}; use evm::model::{Address, AddressTrait, Environment, Account, AccountTrait}; use evm::model::{Transfer}; @@ -71,7 +72,8 @@ pub fn get_bytecode(evm_address: EthAddress) -> Span { /// Populate an Environment with Starknet syscalls. pub fn get_env(origin: EthAddress, gas_price: u128) -> Environment { - let kakarot_state = KakarotCore::unsafe_new_contract_state().snapshot_deref(); + let kakarot_state = KakarotCore::unsafe_new_contract_state(); + let kakarot_storage = kakarot_state.snapshot_deref(); let block_info = get_block_info().unbox(); // tx.gas_price and env.gas_price have the same values here @@ -79,13 +81,13 @@ pub fn get_env(origin: EthAddress, gas_price: u128) -> Environment { Environment { origin: origin, gas_price, - chain_id: get_tx_info().unbox().chain_id.try_into().unwrap(), - prevrandao: kakarot_state.Kakarot_prev_randao.read(), + chain_id: kakarot_state.eth_chain_id(), + prevrandao: kakarot_storage.Kakarot_prev_randao.read(), block_number: block_info.block_number, block_gas_limit: constants::BLOCK_GAS_LIMIT, block_timestamp: block_info.block_timestamp, - coinbase: kakarot_state.Kakarot_coinbase.read(), - base_fee: kakarot_state.Kakarot_base_fee.read(), + coinbase: kakarot_storage.Kakarot_coinbase.read(), + base_fee: kakarot_storage.Kakarot_base_fee.read(), state: Default::default(), } } diff --git a/crates/evm/src/backend/validation.cairo b/crates/evm/src/backend/validation.cairo index 90fcbd79e..d16dfb546 100644 --- a/crates/evm/src/backend/validation.cairo +++ b/crates/evm/src/backend/validation.cairo @@ -1,8 +1,9 @@ use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; use contracts::kakarot_core::KakarotCore; +use contracts::kakarot_core::eth_rpc::IEthRPC; use core::ops::SnapshotDeref; use core::starknet::storage::{StoragePointerReadAccess}; -use core::starknet::{get_caller_address, get_tx_info}; +use core::starknet::{get_caller_address}; use evm::gas; use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; use starknet::storage::StorageTrait; @@ -24,12 +25,7 @@ pub fn validate_eth_tx(kakarot_state: @KakarotCore::ContractState, tx: Transacti // Validate chain_id for post eip155 let tx_chain_id = tx.chain_id(); - let kakarot_chain_id: u64 = get_tx_info() - .chain_id - .try_into() - .unwrap() % POW_2_32 - .try_into() - .unwrap(); + let kakarot_chain_id: u64 = kakarot_state.eth_chain_id(); if (tx_chain_id.is_some()) { assert(tx_chain_id.unwrap() == kakarot_chain_id, 'Invalid chain id'); } diff --git a/crates/utils/src/constants.cairo b/crates/utils/src/constants.cairo index bb97faa82..899b13828 100644 --- a/crates/utils/src/constants.cairo +++ b/crates/utils/src/constants.cairo @@ -216,6 +216,7 @@ pub const POW_2_24: u128 = 0x1000000; pub const POW_2_32: u128 = 0x100000000; pub const POW_2_40: u128 = 0x10000000000; pub const POW_2_48: u128 = 0x1000000000000; +pub const POW_2_53: u128 = 0x20000000000000; pub const POW_2_56: u128 = 0x100000000000000; pub const POW_2_64: u128 = 0x10000000000000000; pub const POW_2_72: u128 = 0x1000000000000000000;