diff --git a/crates/alexandria_data_structures/src/lib.cairo b/crates/alexandria_data_structures/src/lib.cairo index e06c662e6..63e55caa6 100644 --- a/crates/alexandria_data_structures/src/lib.cairo +++ b/crates/alexandria_data_structures/src/lib.cairo @@ -1 +1 @@ -mod vec; +pub mod vec; diff --git a/crates/alexandria_data_structures/src/vec.cairo b/crates/alexandria_data_structures/src/vec.cairo index 797bd595e..237adaff2 100644 --- a/crates/alexandria_data_structures/src/vec.cairo +++ b/crates/alexandria_data_structures/src/vec.cairo @@ -70,8 +70,8 @@ impl VecIndex> of Index { } pub struct Felt252Vec { - items: Felt252Dict, - len: usize, + pub items: Felt252Dict, + pub len: usize, } impl DefaultFeltVec, +Copy, +Felt252DictValue> of Default> { diff --git a/crates/contracts/Scarb.toml b/crates/contracts/Scarb.toml index 3c60f88bf..728572e10 100644 --- a/crates/contracts/Scarb.toml +++ b/crates/contracts/Scarb.toml @@ -1,7 +1,7 @@ [package] name = "contracts" version = "0.1.0" -edition = "2023_10" +edition = "2024_07" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html diff --git a/crates/contracts/src/account_contract.cairo b/crates/contracts/src/account_contract.cairo index 8faa2ea60..05640cc1f 100644 --- a/crates/contracts/src/account_contract.cairo +++ b/crates/contracts/src/account_contract.cairo @@ -1,10 +1,10 @@ -use core::starknet::account::{Call}; //! The generic account that is deployed by Kakarot Core before being "specialized" into an //! Externally Owned Account or a Contract Account This aims at having only one class hash for all //! the contracts deployed by Kakarot, thus enforcing a unique and consistent address mapping Eth //! Address <=> Starknet Address -use core::starknet::{ContractAddress, EthAddress, ClassHash}; +use core::starknet::account::{Call}; +use core::starknet::{EthAddress, ClassHash, ContractAddress}; #[derive(Copy, Drop, Serde, Debug)] pub struct OutsideExecution { @@ -49,28 +49,22 @@ pub mod AccountContract { use contracts::components::ownable::IOwnable; use contracts::components::ownable::ownable_component::InternalTrait; use contracts::components::ownable::ownable_component; - use contracts::errors::{ - BYTECODE_READ_ERROR, BYTECODE_WRITE_ERROR, STORAGE_READ_ERROR, STORAGE_WRITE_ERROR, - NONCE_READ_ERROR, NONCE_WRITE_ERROR, KAKAROT_VALIDATION_FAILED, KAKAROT_REENTRANCY - }; + use contracts::errors::{KAKAROT_VALIDATION_FAILED, KAKAROT_REENTRANCY}; use contracts::kakarot_core::interface::{IKakarotCoreDispatcher, IKakarotCoreDispatcherTrait}; use contracts::storage::StorageBytecode; - use core::integer; use core::num::traits::Bounded; use core::num::traits::zero::Zero; use core::panic_with_felt252; use core::starknet::SyscallResultTrait; use core::starknet::account::{Call}; - use core::starknet::secp256_trait::Signature; use core::starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, StoragePointerWriteAccess }; - use core::starknet::storage_access::{storage_base_address_from_felt252, StorageBaseAddress}; use core::starknet::syscalls::{call_contract_syscall, replace_class_syscall}; use core::starknet::{ - ContractAddress, EthAddress, ClassHash, VALIDATED, get_caller_address, get_contract_address, - get_tx_info, Store, get_block_timestamp + EthAddress, ClassHash, VALIDATED, get_caller_address, get_contract_address, get_tx_info, + get_block_timestamp }; use core::traits::TryInto; use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; @@ -78,9 +72,6 @@ pub mod AccountContract { use utils::constants::{POW_2_32}; use utils::eth_transaction::EthereumTransactionTrait; use utils::eth_transaction::{EthTransactionTrait, TransactionMetadata}; - use utils::helpers::SpanExtTrait; - use utils::helpers::{ByteArrayExTrait, ResultExTrait}; - use utils::math::OverflowingMul; use utils::serialization::{deserialize_signature, deserialize_bytes, serialize_bytes}; // Add ownable component @@ -95,30 +86,30 @@ pub mod AccountContract { #[storage] pub(crate) struct Storage { - Account_bytecode: StorageBytecode, + pub(crate) Account_bytecode: StorageBytecode, pub(crate) Account_bytecode_len: u32, - Account_storage: Map, - Account_is_initialized: bool, - Account_nonce: u64, - Account_implementation: ClassHash, - Account_evm_address: EthAddress, - Account_code_hash: u256, + pub(crate) Account_storage: Map, + pub(crate) Account_is_initialized: bool, + pub(crate) Account_nonce: u64, + pub(crate) Account_implementation: ClassHash, + pub(crate) Account_evm_address: EthAddress, + pub(crate) Account_code_hash: u256, #[substorage(v0)] ownable: ownable_component::Storage } #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { transaction_executed: TransactionExecuted, OwnableEvent: ownable_component::Event } #[derive(Drop, starknet::Event, Debug)] - struct TransactionExecuted { - response: Span, - success: bool, - gas_used: u128 + pub struct TransactionExecuted { + pub response: Span, + pub success: bool, + pub gas_used: u128 } #[constructor] diff --git a/crates/contracts/src/cairo1_helpers.cairo b/crates/contracts/src/cairo1_helpers.cairo index 11b29fa38..08241e7b8 100644 --- a/crates/contracts/src/cairo1_helpers.cairo +++ b/crates/contracts/src/cairo1_helpers.cairo @@ -106,26 +106,27 @@ pub trait IHelpers { } -mod embeddable_impls { +pub mod embeddable_impls { use core::keccak::{cairo_keccak, keccak_u256s_be_inputs}; use core::num::traits::Zero; use core::starknet::EthAddress; - use core::starknet::eth_signature::{ - Signature, verify_eth_signature, public_key_point_to_eth_address + use core::starknet::eth_signature::{verify_eth_signature}; + use core::starknet::secp256_trait::{ + Signature, recover_public_key, Secp256PointTrait, is_valid_signature }; - use core::starknet::secp256_trait::{recover_public_key, Secp256PointTrait, is_valid_signature}; + use core::starknet::secp256_trait::{Secp256Trait}; use core::starknet::secp256k1::Secp256k1Point; - use core::starknet::secp256r1::{secp256r1_new_syscall, Secp256r1Point}; + use core::starknet::secp256r1::{Secp256r1Point}; use core::traits::Into; use core::{starknet, starknet::SyscallResultTrait}; use evm::errors::EVMError; - use evm::precompiles::blake2f::Blake2f; - use evm::precompiles::ec_add::EcAdd; - use evm::precompiles::ec_mul::EcMul; - use evm::precompiles::ec_recover::EcRecover; - use evm::precompiles::identity::Identity; - use evm::precompiles::modexp::ModExp; - use evm::precompiles::sha256::Sha256; + use evm::precompiles::Blake2f; + use evm::precompiles::EcAdd; + use evm::precompiles::EcMul; + use evm::precompiles::EcRecover; + use evm::precompiles::Identity; + use evm::precompiles::ModExp; + use evm::precompiles::Sha256; use utils::helpers::U256Trait; @@ -209,7 +210,9 @@ mod embeddable_impls { fn verify_signature_secp256r1( self: @TContractState, msg_hash: u256, r: u256, s: u256, x: u256, y: u256 ) -> bool { - let maybe_public_key: Option = secp256r1_new_syscall(x, y) + let maybe_public_key: Option = Secp256Trait::secp256_ec_new_syscall( + x, y + ) .unwrap_syscall(); let public_key = match maybe_public_key { Option::Some(public_key) => public_key, @@ -227,8 +230,8 @@ pub mod Cairo1Helpers { struct Storage {} #[abi(embed_v0)] - impl Precompiles = super::embeddable_impls::Precompiles; + pub impl Precompiles = super::embeddable_impls::Precompiles; #[abi(embed_v0)] - impl Helpers = super::embeddable_impls::Helpers; + pub impl Helpers = super::embeddable_impls::Helpers; } diff --git a/crates/contracts/src/components/ownable.cairo b/crates/contracts/src/components/ownable.cairo index 19f827077..fc8f88db7 100644 --- a/crates/contracts/src/components/ownable.cairo +++ b/crates/contracts/src/components/ownable.cairo @@ -18,13 +18,13 @@ pub trait IOwnable { #[starknet::component] pub mod ownable_component { use core::num::traits::Zero; - use core::starknet::ContractAddress; - use core::starknet::get_caller_address; + use core::starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use core::starknet::{get_caller_address, ContractAddress}; use super::Errors; #[storage] - struct Storage { - Ownable_owner: ContractAddress + pub struct Storage { + pub Ownable_owner: ContractAddress } #[event] @@ -34,14 +34,14 @@ pub mod ownable_component { } #[derive(Drop, starknet::Event)] - struct OwnershipTransferred { - previous_owner: ContractAddress, - new_owner: ContractAddress, + pub struct OwnershipTransferred { + pub previous_owner: ContractAddress, + pub new_owner: ContractAddress, } #[embeddable_as(Ownable)] - impl OwnableImpl< + pub impl OwnableImpl< TContractState, +HasComponent > of super::IOwnable> { fn owner(self: @ComponentState) -> ContractAddress { diff --git a/crates/contracts/src/components/upgradeable.cairo b/crates/contracts/src/components/upgradeable.cairo index 8b5d28076..67c441ef5 100644 --- a/crates/contracts/src/components/upgradeable.cairo +++ b/crates/contracts/src/components/upgradeable.cairo @@ -8,12 +8,12 @@ pub trait IUpgradeable { #[starknet::component] pub mod upgradeable_component { + use core::starknet::ClassHash; use core::starknet::syscalls::{replace_class_syscall}; - use core::starknet::{get_caller_address, ClassHash}; #[storage] - struct Storage {} + pub struct Storage {} #[event] #[derive(Drop, starknet::Event)] @@ -27,7 +27,7 @@ pub mod upgradeable_component { } #[embeddable_as(Upgradeable)] - impl UpgradeableImpl< + pub impl UpgradeableImpl< TContractState, +HasComponent > of super::IUpgradeable> { fn upgrade_contract( diff --git a/crates/contracts/src/kakarot_core.cairo b/crates/contracts/src/kakarot_core.cairo index 7ce16bbd8..83b34337c 100644 --- a/crates/contracts/src/kakarot_core.cairo +++ b/crates/contracts/src/kakarot_core.cairo @@ -1,5 +1,7 @@ pub mod interface; mod kakarot; -use interface::IKakarotCore; - -use kakarot::KakarotCore; +pub use interface::{ + IKakarotCore, IKakarotCoreDispatcher, IKakarotCoreDispatcherTrait, + IExtendedKakarotCoreDispatcher, IExtendedKakarotCoreDispatcherTrait +}; +pub use kakarot::KakarotCore; diff --git a/crates/contracts/src/kakarot_core/kakarot.cairo b/crates/contracts/src/kakarot_core/kakarot.cairo index 17ecef250..93f6c5493 100644 --- a/crates/contracts/src/kakarot_core/kakarot.cairo +++ b/crates/contracts/src/kakarot_core/kakarot.cairo @@ -1,5 +1,3 @@ -use core::starknet::{ContractAddress, EthAddress, ClassHash}; - const INVOKE_ETH_CALL_FORBIDDEN: felt252 = 'KKT: Cannot invoke eth_call'; @@ -9,14 +7,12 @@ pub mod KakarotCore { use contracts::components::ownable::{ownable_component}; use contracts::components::upgradeable::{IUpgradeable, upgradeable_component}; use contracts::kakarot_core::interface::IKakarotCore; - use core::num::traits::{Zero, CheckedAdd, CheckedSub, CheckedMul}; - use core::starknet::SyscallResultTrait; + use core::num::traits::{Zero, CheckedSub}; use core::starknet::event::EventEmitter; use core::starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, StoragePointerWriteAccess }; - use core::starknet::syscalls::deploy_syscall; use core::starknet::{ EthAddress, ContractAddress, ClassHash, get_tx_info, get_contract_address, get_caller_address @@ -24,21 +20,17 @@ pub mod KakarotCore { use evm::backend::starknet_backend; use evm::errors::{EVMError, ensure, EVMErrorTrait,}; use evm::gas; - use evm::interpreter::{EVMTrait}; - use evm::model::account::{Account, AccountTrait}; + use evm::model::account::AccountTrait; use evm::model::{ - Transfer, Message, Environment, TransactionResult, TransactionResultTrait, ExecutionSummary, - ExecutionSummaryTrait, Address, AddressTrait + Message, TransactionResult, TransactionResultTrait, ExecutionSummaryTrait, Address }; use evm::precompiles::eth_precompile_addresses; - use evm::state::{State, StateTrait}; - use super::{INVOKE_ETH_CALL_FORBIDDEN}; + use evm::state::StateTrait; + use evm::{EVMTrait}; use utils::address::compute_contract_address; - use utils::constants; use utils::eth_transaction::AccessListItemTrait; use utils::eth_transaction::{EthereumTransaction, EthereumTransactionTrait, AccessListItem}; - use utils::helpers::{compute_starknet_address, EthAddressExTrait}; - use utils::rlp::RLPTrait; + use utils::helpers::compute_starknet_address; use utils::set::{Set, SetTrait}; component!(path: ownable_component, storage: ownable, event: OwnableEvent); @@ -54,14 +46,14 @@ pub mod KakarotCore { #[storage] pub struct Storage { - Kakarot_evm_to_starknet_address: Map::, - Kakarot_uninitialized_account_class_hash: ClassHash, - Kakarot_account_contract_class_hash: ClassHash, - Kakarot_native_token_address: ContractAddress, - Kakarot_coinbase: EthAddress, - Kakarot_base_fee: u128, - Kakarot_prev_randao: u256, - Kakarot_block_gas_limit: u128, + pub Kakarot_evm_to_starknet_address: Map::, + pub Kakarot_uninitialized_account_class_hash: ClassHash, + pub Kakarot_account_contract_class_hash: ClassHash, + pub Kakarot_native_token_address: ContractAddress, + pub Kakarot_coinbase: EthAddress, + pub Kakarot_base_fee: u128, + pub Kakarot_prev_randao: u256, + pub Kakarot_block_gas_limit: u128, // Components #[substorage(v0)] ownable: ownable_component::Storage, @@ -71,7 +63,7 @@ pub mod KakarotCore { #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { OwnableEvent: ownable_component::Event, UpgradeableEvent: upgradeable_component::Event, AccountDeployed: AccountDeployed, @@ -80,24 +72,24 @@ pub mod KakarotCore { } #[derive(Copy, Drop, starknet::Event)] - struct AccountDeployed { + pub struct AccountDeployed { #[key] - evm_address: EthAddress, + pub evm_address: EthAddress, #[key] - starknet_address: ContractAddress, + pub starknet_address: ContractAddress, } #[derive(Copy, Drop, starknet::Event)] - struct AccountClassHashChange { - old_class_hash: ClassHash, - new_class_hash: ClassHash, + pub struct AccountClassHashChange { + pub old_class_hash: ClassHash, + pub new_class_hash: ClassHash, } #[derive(Copy, Drop, starknet::Event)] - struct EOAClassHashChange { - old_class_hash: ClassHash, - new_class_hash: ClassHash, + pub struct EOAClassHashChange { + pub old_class_hash: ClassHash, + pub new_class_hash: ClassHash, } @@ -126,7 +118,7 @@ pub mod KakarotCore { } #[abi(embed_v0)] - impl KakarotCoreImpl of IKakarotCore { + pub impl KakarotCoreImpl of IKakarotCore { fn set_native_token(ref self: ContractState, native_token: ContractAddress) { self.ownable.assert_only_owner(); self.Kakarot_native_token_address.write(native_token); @@ -250,7 +242,7 @@ pub mod KakarotCore { } #[generate_trait] - impl KakarotCoreInternalImpl of KakarotCoreInternal { + pub impl KakarotCoreInternalImpl of KakarotCoreInternal { fn is_view(self: @ContractState) -> bool { let tx_info = get_tx_info().unbox(); diff --git a/crates/contracts/src/lib.cairo b/crates/contracts/src/lib.cairo index 07d60a231..995015b10 100644 --- a/crates/contracts/src/lib.cairo +++ b/crates/contracts/src/lib.cairo @@ -1,28 +1,37 @@ -mod account_contract; -mod cairo1_helpers; -mod components; +pub mod account_contract; +pub mod cairo1_helpers; +pub mod components; -mod errors; +pub mod errors; // Kakarot smart contract -mod kakarot_core; - -mod storage; +pub mod kakarot_core; +pub mod storage; #[cfg(target: 'test')] -mod test_data; +pub mod test_data; #[cfg(target: 'test')] -mod test_utils; +pub mod test_utils; // Account transparent proxy mod uninitialized_account; +pub use account_contract::{AccountContract, IAccount, IAccountDispatcher, IAccountDispatcherTrait}; +pub use cairo1_helpers::{ + Cairo1Helpers, IPrecompiles, IHelpers, IPrecompilesDispatcher, IHelpersDispatcher, + IPrecompilesDispatcherTrait, IHelpersDispatcherTrait +}; +pub use kakarot_core::{ + KakarotCore, IKakarotCore, IKakarotCoreDispatcher, IKakarotCoreDispatcherTrait, + IExtendedKakarotCoreDispatcher, IExtendedKakarotCoreDispatcherTrait +}; +pub use uninitialized_account::{UninitializedAccount}; //TODO: hide this behind a feature flag -mod test_contracts { - mod test_upgradeable; +pub mod test_contracts { + pub mod test_upgradeable; } -mod mocks { - mod cairo1_helpers_fixture; +pub mod mocks { + pub mod cairo1_helpers_fixture; } diff --git a/crates/contracts/src/mocks/cairo1_helpers_fixture.cairo b/crates/contracts/src/mocks/cairo1_helpers_fixture.cairo index 766bc7d55..bd5ef60a4 100644 --- a/crates/contracts/src/mocks/cairo1_helpers_fixture.cairo +++ b/crates/contracts/src/mocks/cairo1_helpers_fixture.cairo @@ -1,6 +1,6 @@ #[starknet::contract] pub mod Cairo1HelpersFixture { - use contracts::cairo1_helpers::{IPrecompiles, IHelpers, embeddable_impls}; + use contracts::cairo1_helpers::embeddable_impls; const VERSION: felt252 = 2; diff --git a/crates/contracts/src/storage.cairo b/crates/contracts/src/storage.cairo index 62529e47a..4ff139dfe 100644 --- a/crates/contracts/src/storage.cairo +++ b/crates/contracts/src/storage.cairo @@ -1,20 +1,19 @@ use contracts::account_contract::AccountContract::unsafe_new_contract_state as account_contract_state; use core::ops::DerefMut; use core::ops::SnapshotDeref; -use core::starknet::{ - SyscallResult, storage_read_syscall, Store, StorageBaseAddress, StorageAddress, - storage_write_syscall +use core::starknet::storage::{ + StoragePointerReadAccess, StoragePointerWriteAccess, StorageTrait, StorageTraitMut }; -use starknet::storage::StorageTrait; -use starknet::storage::StorageTraitMut; -use super::account_contract::IAccount; +use core::starknet::storage_access::StorageBaseAddress; +use core::starknet::syscalls::{storage_read_syscall, storage_write_syscall}; +use core::starknet::{SyscallResult, Store, StorageAddress}; use utils::utils::{pack_bytes, load_packed_bytes}; /// A wrapper type for the bytecode storage. Packing / unpacking is done transparently inside the /// `read` and `write` methods of `Store`. #[derive(Copy, Drop)] -struct StorageBytecode { - bytecode: Span +pub struct StorageBytecode { + pub bytecode: Span } const BYTES_PER_FELT: NonZero = 31; @@ -88,10 +87,8 @@ impl StoreBytecode of Store { #[cfg(test)] mod tests { - use contracts::account_contract::AccountContract::{ - unsafe_new_contract_state as account_contract_state, ContractState as AccountContractState - }; - use starknet::contract_address::ContractAddress; + use contracts::account_contract::AccountContract::unsafe_new_contract_state as account_contract_state; + use core::starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; use starknet::storage_access::Store; use starknet::storage_access::{ StorageBaseAddress, StorageAddress, storage_base_address_from_felt252 @@ -102,7 +99,7 @@ mod tests { use super::StorageBytecode; use super::StorageTrait; use super::StorageTraitMut; - use utils::utils::{pack_bytes, load_packed_bytes}; + use utils::utils::pack_bytes; #[test] fn test_store_bytecode_empty() { diff --git a/crates/contracts/src/test_contracts/test_upgradeable.cairo b/crates/contracts/src/test_contracts/test_upgradeable.cairo index a51c61cf4..6ff3ce473 100644 --- a/crates/contracts/src/test_contracts/test_upgradeable.cairo +++ b/crates/contracts/src/test_contracts/test_upgradeable.cairo @@ -1,18 +1,14 @@ -use MockContractUpgradeableV0::HasComponentImpl_upgradeable_component; -use contracts::components::upgradeable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait}; use contracts::components::upgradeable::{upgradeable_component}; -use core::serde::Serde; -use core::starknet::{deploy_syscall, ClassHash, ContractAddress, testing}; use upgradeable_component::{UpgradeableImpl}; #[starknet::interface] -trait IMockContractUpgradeable { +pub trait IMockContractUpgradeable { fn version(self: @TContractState) -> felt252; } #[starknet::contract] -mod MockContractUpgradeableV0 { +pub mod MockContractUpgradeableV0 { use contracts::components::upgradeable::{upgradeable_component}; use super::IMockContractUpgradeable; component!(path: upgradeable_component, storage: upgradeable, event: UpgradeableEvent); @@ -28,7 +24,7 @@ mod MockContractUpgradeableV0 { #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { UpgradeableEvent: upgradeable_component::Event } @@ -41,7 +37,7 @@ mod MockContractUpgradeableV0 { } #[starknet::contract] -mod MockContractUpgradeableV1 { +pub mod MockContractUpgradeableV1 { use contracts::components::upgradeable::{upgradeable_component}; use super::IMockContractUpgradeable; component!(path: upgradeable_component, storage: upgradeable, event: upgradeableEvent); @@ -54,7 +50,7 @@ mod MockContractUpgradeableV1 { #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { upgradeableEvent: upgradeable_component::Event } @@ -68,12 +64,11 @@ mod MockContractUpgradeableV1 { #[cfg(test)] mod tests { + use contracts::components::upgradeable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait}; + use core::starknet::syscalls::{deploy_syscall}; use snforge_std::{declare, DeclareResultTrait}; - use starknet::{deploy_syscall, ClassHash}; - use super::{ - IMockContractUpgradeableDispatcher, IUpgradeableDispatcher, IUpgradeableDispatcherTrait, - IMockContractUpgradeableDispatcherTrait - }; + use starknet::{ClassHash}; + use super::{IMockContractUpgradeableDispatcher, IMockContractUpgradeableDispatcherTrait}; #[test] fn test_upgradeable_update_contract() { diff --git a/crates/contracts/src/test_data.cairo b/crates/contracts/src/test_data.cairo index 5658d24b4..913ee4d91 100644 --- a/crates/contracts/src/test_data.cairo +++ b/crates/contracts/src/test_data.cairo @@ -24,7 +24,7 @@ // } // } -pub(crate) fn deploy_counter_calldata() -> Span { +pub fn deploy_counter_calldata() -> Span { [ 0x60, 0x80, @@ -531,7 +531,7 @@ pub(crate) fn deploy_counter_calldata() -> Span { ].span() } -pub(crate) fn counter_evm_bytecode() -> Span { +pub fn counter_evm_bytecode() -> Span { [ 0x60, 0x80, @@ -1040,7 +1040,7 @@ pub(crate) fn counter_evm_bytecode() -> Span { // } // } // Remix compiler: 0.8.20+commit.a1b79de6 -pub(crate) fn storage_evm_initcode() -> Span { +pub fn storage_evm_initcode() -> Span { [ 0x60, 0x80, @@ -1397,7 +1397,7 @@ pub(crate) fn storage_evm_initcode() -> Span { ].span() } -pub(crate) fn storage_evm_bytecode() -> Span { +pub fn storage_evm_bytecode() -> Span { [ 0x60, 0x80, @@ -1730,7 +1730,7 @@ pub(crate) fn storage_evm_bytecode() -> Span { // format: 0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList]) // rlp decoding: [ '0x01', '0x', '0x3b9aca00', '0x1e8480', // '0x0000006f746865725f65766d5f61646472657373', '0x', '0x371303c0', [] ] -pub(crate) fn eip_2930_rlp_encoded_counter_inc_tx() -> Span { +pub fn eip_2930_rlp_encoded_counter_inc_tx() -> Span { [ 1, 231, diff --git a/crates/contracts/src/test_utils.cairo b/crates/contracts/src/test_utils.cairo index 67e9182ac..2846d0145 100644 --- a/crates/contracts/src/test_utils.cairo +++ b/crates/contracts/src/test_utils.cairo @@ -1,56 +1,46 @@ -use contracts::account_contract::{AccountContract}; use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; use contracts::kakarot_core::{ - interface::IExtendedKakarotCoreDispatcher, interface::IExtendedKakarotCoreDispatcherTrait, - KakarotCore + interface::IExtendedKakarotCoreDispatcher, interface::IExtendedKakarotCoreDispatcherTrait }; -use contracts::uninitialized_account::{UninitializedAccount}; -use core::fmt::Debug; use core::result::ResultTrait; -use core::starknet::ClassHash; -use core::starknet::{ - testing, contract_address_const, EthAddress, ContractAddress, deploy_syscall, - get_contract_address -}; -use evm::backend::starknet_backend; +use core::starknet::syscalls::deploy_syscall; +use core::starknet::{EthAddress, ContractAddress}; use evm::model::{Address}; -use evm::test_utils::{ca_address, other_starknet_address, chain_id, sequencer_evm_address}; -use openzeppelin::token::erc20::ERC20; +use evm::test_utils::{other_starknet_address, sequencer_evm_address}; use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; use snforge_std::{ - declare, DeclareResult, DeclareResultTrait, ContractClassTrait, start_cheat_caller_address, - start_cheat_sequencer_address_global, stop_cheat_caller_address, CheatSpan, - start_cheat_caller_address_global + declare, DeclareResultTrait, start_cheat_caller_address, start_cheat_sequencer_address_global, + stop_cheat_caller_address, start_cheat_caller_address_global }; use utils::constants::BLOCK_GAS_LIMIT; use utils::eth_transaction::LegacyTransaction; -mod constants { - use core::starknet::{EthAddress, testing, contract_address_const, ContractAddress}; - fn ZERO() -> ContractAddress { +pub mod constants { + use core::starknet::{EthAddress, contract_address_const, ContractAddress}; + pub fn ZERO() -> ContractAddress { contract_address_const::<0>() } - fn OWNER() -> ContractAddress { + pub fn OWNER() -> ContractAddress { contract_address_const::<0xabde1>() } - fn OTHER() -> ContractAddress { + pub fn OTHER() -> ContractAddress { contract_address_const::<0xe1145>() } - pub(crate) fn EVM_ADDRESS() -> EthAddress { + pub fn EVM_ADDRESS() -> EthAddress { 0xc0ffee.try_into().unwrap() } - pub(crate) fn ETH_BANK() -> ContractAddress { + pub fn ETH_BANK() -> ContractAddress { contract_address_const::<0x777>() } } -fn deploy_native_token() -> IERC20CamelDispatcher { +pub fn deploy_native_token() -> IERC20CamelDispatcher { let calldata: Array = array![ 'STARKNET_ETH', 'ETH', 0x00, 0xfffffffffffffffffffffffffff, constants::ETH_BANK().into() ]; @@ -62,7 +52,7 @@ fn deploy_native_token() -> IERC20CamelDispatcher { } } -fn deploy_kakarot_core( +pub fn deploy_kakarot_core( native_token: ContractAddress, mut eoas: Span ) -> IExtendedKakarotCoreDispatcher { let account_contract_class_hash = declare("AccountContract") @@ -97,7 +87,7 @@ fn deploy_kakarot_core( } } -pub(crate) fn deploy_contract_account( +pub fn deploy_contract_account( kakarot_core: IExtendedKakarotCoreDispatcher, evm_address: EthAddress, bytecode: Span ) -> Address { let eoa = deploy_eoa(kakarot_core, evm_address); @@ -109,14 +99,14 @@ pub(crate) fn deploy_contract_account( Address { evm: evm_address, starknet: starknet_address } } -fn deploy_eoa( +pub fn deploy_eoa( kakarot_core: IExtendedKakarotCoreDispatcher, evm_address: EthAddress ) -> IAccountDispatcher { let starknet_address = kakarot_core.deploy_externally_owned_account(evm_address); IAccountDispatcher { contract_address: starknet_address } } -fn call_transaction( +pub fn call_transaction( chain_id: u128, destination: Option, calldata: Span ) -> LegacyTransaction { LegacyTransaction { @@ -124,7 +114,7 @@ fn call_transaction( } } -fn fund_account_with_native_token( +pub fn fund_account_with_native_token( contract_address: ContractAddress, native_token: IERC20CamelDispatcher, amount: u256, ) { start_cheat_caller_address(native_token.contract_address, constants::ETH_BANK()); @@ -132,9 +122,7 @@ fn fund_account_with_native_token( stop_cheat_caller_address(native_token.contract_address); } -pub(crate) fn setup_contracts_for_testing() -> ( - IERC20CamelDispatcher, IExtendedKakarotCoreDispatcher -) { +pub fn setup_contracts_for_testing() -> (IERC20CamelDispatcher, IExtendedKakarotCoreDispatcher) { let native_token = deploy_native_token(); let kakarot_core = deploy_kakarot_core( native_token.contract_address, [sequencer_evm_address()].span() diff --git a/crates/contracts/src/uninitialized_account.cairo b/crates/contracts/src/uninitialized_account.cairo index 2e44295f2..d3516461e 100644 --- a/crates/contracts/src/uninitialized_account.cairo +++ b/crates/contracts/src/uninitialized_account.cairo @@ -19,14 +19,12 @@ trait IAccount { #[starknet::contract] pub mod UninitializedAccount { - use contracts::components::ownable::IOwnable; use contracts::components::ownable::ownable_component::InternalTrait; use contracts::components::ownable::ownable_component; use contracts::kakarot_core::interface::{IKakarotCoreDispatcher, IKakarotCoreDispatcherTrait}; use core::starknet::SyscallResultTrait; use core::starknet::syscalls::{library_call_syscall, replace_class_syscall}; - use core::starknet::{ContractAddress, EthAddress, ClassHash, get_caller_address}; - use super::{IAccountLibraryDispatcher, IAccountDispatcherTrait}; + use core::starknet::{ContractAddress, get_caller_address}; // Add ownable component component!(path: ownable_component, storage: ownable, event: OwnableEvent); diff --git a/crates/contracts/tests/test_contract_account.cairo b/crates/contracts/tests/test_contract_account.cairo index ab95aac48..7ac0c8f5f 100644 --- a/crates/contracts/tests/test_contract_account.cairo +++ b/crates/contracts/tests/test_contract_account.cairo @@ -1,9 +1,9 @@ -use contracts::account_contract::{AccountContract, IAccountDispatcher, IAccountDispatcherTrait}; use contracts::errors::KAKAROT_REENTRANCY; use contracts::test_data::counter_evm_bytecode; use contracts::test_utils::{ setup_contracts_for_testing, deploy_contract_account, fund_account_with_native_token }; +use contracts::{IAccountDispatcher, IAccountDispatcherTrait}; use core::starknet::ContractAddress; use core::starknet::account::{Call}; use core::starknet::testing; @@ -105,9 +105,9 @@ fn test_ca_external_starknet_call_kakarot_get_starknet_address() { let contract_account = IAccountDispatcher { contract_address: ca_address.starknet }; let call = Call { - to: kakarot_core.contract_address, - selector: selector!("get_starknet_address"), - calldata: array![ca_address.evm.address].span(), + to: kakarot_core.contract_address, selector: selector!("get_starknet_address"), calldata: [ + ca_address.evm.into() + ].span(), }; start_cheat_caller_address(ca_address.starknet, kakarot_core.contract_address); let (success, data) = contract_account.execute_starknet_call(call); @@ -127,7 +127,7 @@ fn test_ca_external_starknet_call_cannot_call_kakarot_other_selector() { let call = Call { to: kakarot_core.contract_address, selector: selector!("get_native_token"), - calldata: array![].span(), + calldata: [].span(), }; start_cheat_caller_address(ca_address.starknet, kakarot_core.contract_address); let (success, data) = contract_account.execute_starknet_call(call); diff --git a/crates/contracts/tests/test_eoa.cairo b/crates/contracts/tests/test_eoa.cairo index 1eb363464..7beb6835d 100644 --- a/crates/contracts/tests/test_eoa.cairo +++ b/crates/contracts/tests/test_eoa.cairo @@ -16,10 +16,11 @@ use contracts::test_utils::{ use core::array::SpanTrait; use core::box::BoxTrait; use core::starknet::account::{Call}; -use core::starknet::class_hash::Felt252TryIntoClassHash; +use core::starknet::secp256_trait::Signature; +use core::starknet::syscalls::deploy_syscall; use core::starknet::{ - deploy_syscall, ContractAddress, ClassHash, VALIDATED, get_contract_address, - contract_address_const, EthAddress, eth_signature::{Signature}, get_tx_info, Event + ContractAddress, ClassHash, VALIDATED, get_contract_address, contract_address_const, EthAddress, + get_tx_info, Event }; use evm::model::{Address, AddressTrait}; diff --git a/crates/contracts/tests/test_kakarot_core.cairo b/crates/contracts/tests/test_kakarot_core.cairo index e3ebdf3e4..f02ab1f3e 100644 --- a/crates/contracts/tests/test_kakarot_core.cairo +++ b/crates/contracts/tests/test_kakarot_core.cairo @@ -1,16 +1,14 @@ +use contracts::UninitializedAccount; use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; use contracts::kakarot_core::interface::{ IExtendedKakarotCoreDispatcher, IExtendedKakarotCoreDispatcherTrait }; -use contracts::kakarot_core::{ - interface::IExtendedKakarotCoreDispatcherImpl, KakarotCore, KakarotCore::{KakarotCoreInternal}, -}; +use contracts::kakarot_core::{KakarotCore, KakarotCore::KakarotCoreInternal}; use contracts::test_contracts::test_upgradeable::{ MockContractUpgradeableV1, IMockContractUpgradeableDispatcher, IMockContractUpgradeableDispatcherTrait }; use contracts::test_data::{deploy_counter_calldata, counter_evm_bytecode}; -use contracts::uninitialized_account::UninitializedAccount; use contracts::{test_utils as contract_utils,}; use core::fmt::{Debug, Formatter, Error}; use core::num::traits::Zero; @@ -69,7 +67,7 @@ fn test_kakarot_core_renounce_ownership() { fn test_kakarot_core_chain_id() { contract_utils::setup_contracts_for_testing(); - assert(chain_id() == contract_utils::chain_id(), 'wrong chain id'); + assert(chain_id() == test_utils::chain_id(), 'wrong chain id'); } #[test] diff --git a/crates/contracts/tests/test_ownable.cairo b/crates/contracts/tests/test_ownable.cairo index 093b62ba9..df9ba9a36 100644 --- a/crates/contracts/tests/test_ownable.cairo +++ b/crates/contracts/tests/test_ownable.cairo @@ -14,7 +14,7 @@ use snforge_utils::snforge_utils::{EventsFilterBuilderTrait, ContractEvents, Con #[starknet::contract] -mod MockContract { +pub mod MockContract { use contracts::components::ownable::{ownable_component}; component!(path: ownable_component, storage: ownable, event: OwnableEvent); @@ -33,7 +33,7 @@ mod MockContract { #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { OwnableEvent: ownable_component::Event } } diff --git a/crates/contracts/tests/test_utils.cairo b/crates/contracts/tests/test_utils.cairo index 67e9182ac..f87838080 100644 --- a/crates/contracts/tests/test_utils.cairo +++ b/crates/contracts/tests/test_utils.cairo @@ -4,13 +4,13 @@ use contracts::kakarot_core::{ interface::IExtendedKakarotCoreDispatcher, interface::IExtendedKakarotCoreDispatcherTrait, KakarotCore }; -use contracts::uninitialized_account::{UninitializedAccount}; +use contracts::{UninitializedAccount}; use core::fmt::Debug; use core::result::ResultTrait; use core::starknet::ClassHash; +use core::starknet::syscalls::deploy_syscall; use core::starknet::{ - testing, contract_address_const, EthAddress, ContractAddress, deploy_syscall, - get_contract_address + testing, contract_address_const, EthAddress, ContractAddress, get_contract_address }; use evm::backend::starknet_backend; use evm::model::{Address}; diff --git a/crates/evm/Scarb.toml b/crates/evm/Scarb.toml index 17265e8b4..7155f6e36 100644 --- a/crates/evm/Scarb.toml +++ b/crates/evm/Scarb.toml @@ -1,7 +1,7 @@ [package] name = "evm" version = "0.1.0" -edition = "2023_10" +edition = "2024_07" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html diff --git a/crates/evm/src/backend.cairo b/crates/evm/src/backend.cairo index 209fdaf37..f9215a84b 100644 --- a/crates/evm/src/backend.cairo +++ b/crates/evm/src/backend.cairo @@ -1 +1 @@ -mod starknet_backend; +pub mod starknet_backend; diff --git a/crates/evm/src/backend/starknet_backend.cairo b/crates/evm/src/backend/starknet_backend.cairo index 274389f1c..724407ddf 100644 --- a/crates/evm/src/backend/starknet_backend.cairo +++ b/crates/evm/src/backend/starknet_backend.cairo @@ -1,18 +1,19 @@ use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; use contracts::kakarot_core::{KakarotCore, KakarotCore::KakarotCoreImpl}; use core::num::traits::zero::Zero; -use core::ops::deref::SnapshotDeref; +use core::ops::SnapshotDeref; use core::starknet::storage::StoragePointerReadAccess; -use core::starknet::storage::StoragePointerWriteAccess; -use core::starknet::{ - EthAddress, get_contract_address, deploy_syscall, get_tx_info, get_block_info, - SyscallResultTrait -}; +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 evm::errors::{ensure, EVMError, EOA_EXISTS}; use evm::model::{Address, AddressTrait, Environment, Account, AccountTrait}; +use evm::model::{Transfer}; use evm::state::{State, StateTrait}; use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; +use utils::constants::BURN_ADDRESS; use utils::constants; +use utils::set::SetTrait; /// Commits the state changes to Starknet. @@ -24,11 +25,11 @@ use utils::constants; /// # 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) +pub fn commit(ref state: State) -> Result<(), EVMError> { + commit_accounts(ref state)?; + transfer_native_token(ref state)?; + emit_events(ref state)?; + commit_storage(ref state) } /// Deploys a new EOA contract. @@ -36,7 +37,7 @@ fn commit(ref state: State) -> Result<(), EVMError> { /// # Arguments /// /// * `evm_address` - The EVM address of the EOA to deploy. -fn deploy(evm_address: EthAddress) -> Result { +pub fn deploy(evm_address: EthAddress) -> Result { // Unlike CAs, there is not check for the existence of an EOA prealably to calling // `EOATrait::deploy` - therefore, we need to check that there is no collision. let mut is_deployed = evm_address.is_deployed(); @@ -57,7 +58,7 @@ fn deploy(evm_address: EthAddress) -> Result { Result::Ok(Address { evm: evm_address, starknet: starknet_address }) } -fn get_bytecode(evm_address: EthAddress) -> Span { +pub fn get_bytecode(evm_address: EthAddress) -> Span { let kakarot_state = KakarotCore::unsafe_new_contract_state(); let starknet_address = kakarot_state.address_registry(evm_address); if starknet_address.is_non_zero() { @@ -69,7 +70,7 @@ fn get_bytecode(evm_address: EthAddress) -> Span { } /// Populate an Environment with Starknet syscalls. -fn get_env(origin: EthAddress, gas_price: u128) -> Environment { +pub fn get_env(origin: EthAddress, gas_price: u128) -> Environment { let kakarot_state = KakarotCore::unsafe_new_contract_state().snapshot_deref(); let block_info = get_block_info().unbox(); @@ -99,7 +100,7 @@ fn get_env(origin: EthAddress, gas_price: u128) -> Environment { /// # 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 { +pub 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); @@ -116,7 +117,7 @@ fn fetch_original_storage(account: @Account, key: u256) -> u256 { /// # Returns /// /// The balance of the given address. -fn fetch_balance(self: @Address) -> u256 { +pub 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 }; @@ -124,162 +125,136 @@ fn fetch_balance(self: @Address) -> u256 { } -mod internals { - use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; - use contracts::kakarot_core::{KakarotCore, KakarotCore::KakarotCoreImpl}; - use core::starknet::SyscallResultTrait; - use core::starknet::syscalls::{emit_event_syscall}; - use evm::errors::EVMError; - use evm::model::account::{Account, AccountTrait}; - use evm::model::{Address, AddressTrait, Transfer}; - use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; - 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(); - while let Option::Some(evm_address) = account_keys.pop_front() { - let account = state.accounts.changes.get(*evm_address).deref(); - commit(@account, ref state); - }; - return Result::Ok(()); - } - - /// Commits the account to Starknet by updating the account state if it - /// exists, or deploying a new account if it doesn't. - /// - /// # 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`. - fn commit(self: @Account, ref state: State) { - if self.evm_address().is_precompile() { - return; - } - - // Case new account - if !self.evm_address().is_deployed() { - deploy(self.evm_address()).expect('account deployment failed'); - } - - // @dev: EIP-6780 - If selfdestruct on an account created, dont commit data - // and burn any leftover balance. - if (self.is_selfdestruct() && self.is_created()) { - let kakarot_state = KakarotCore::unsafe_new_contract_state(); - let burn_starknet_address = kakarot_state - .compute_starknet_address(BURN_ADDRESS.try_into().unwrap()); - let burn_address = Address { - starknet: burn_starknet_address, evm: BURN_ADDRESS.try_into().unwrap() - }; - state - .add_transfer( - Transfer { - sender: self.address(), recipient: burn_address, amount: self.balance() - } - ) - .expect('Failed to burn on selfdestruct'); - return; - } - - if !self.has_code_or_nonce() { - // Nothing to commit - return; - } +/// 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(); + while let Option::Some(evm_address) = account_keys.pop_front() { + let account = state.accounts.changes.get(*evm_address).deref(); + commit_account(@account, ref state); + }; + return Result::Ok(()); +} - // Write updated nonce and storage - //TODO: storage commits are done in the State commitment as they're not part of the account - //model in SSJ - let starknet_account = IAccountDispatcher { contract_address: self.starknet_address() }; - starknet_account.set_nonce(*self.nonce); - - //Storage is handled outside of the account and must be committed after all accounts are - //committed. - if self.is_created() { - starknet_account.write_bytecode(self.bytecode()); - //TODO: save valid jumpdests https://github.com/kkrt-labs/kakarot-ssj/issues/839 - //TODO: set code hash https://github.com/kkrt-labs/kakarot-ssj/issues/840 - } +/// Commits the account to Starknet by updating the account state if it +/// exists, or deploying a new account if it doesn't. +/// +/// # 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`. +fn commit_account(self: @Account, ref state: State) { + if self.evm_address().is_precompile() { return; } - /// Iterates through the list of pending transfer and triggers them - fn transfer_native_token(ref self: State) -> Result<(), EVMError> { + // Case new account + if !self.evm_address().is_deployed() { + deploy(self.evm_address()).expect('account deployment failed'); + } + + // @dev: EIP-6780 - If selfdestruct on an account created, dont commit data + // and burn any leftover balance. + if (self.is_selfdestruct() && self.is_created()) { let kakarot_state = KakarotCore::unsafe_new_contract_state(); - let native_token = kakarot_state.get_native_token(); - while let Option::Some(transfer) = self.transfers.pop_front() { - IERC20CamelDispatcher { contract_address: native_token } - .transferFrom( - transfer.sender.starknet, transfer.recipient.starknet, transfer.amount - ); + let burn_starknet_address = kakarot_state + .compute_starknet_address(BURN_ADDRESS.try_into().unwrap()); + let burn_address = Address { + starknet: burn_starknet_address, evm: BURN_ADDRESS.try_into().unwrap() }; - Result::Ok(()) + state + .add_transfer( + Transfer { sender: self.address(), recipient: burn_address, amount: self.balance() } + ) + .expect('Failed to burn on selfdestruct'); + return; } - /// Iterates through the list of events and emits them. - fn emit_events(ref self: State) -> Result<(), EVMError> { - while let Option::Some(event) = self.events.pop_front() { - let mut keys = Default::default(); - let mut data = Default::default(); - Serde::>::serialize(@event.keys, ref keys); - Serde::>::serialize(@event.data, ref data); - emit_event_syscall(keys.span(), data.span()).unwrap_syscall(); - }; - return Result::Ok(()); + if !self.has_code_or_nonce() { + // Nothing to commit + return; } - /// Commits storage changes to the KakarotCore contract by writing pending - /// state changes to Starknet Storage. - /// commit_storage MUST be called after commit_accounts. - fn commit_storage(ref self: State) -> Result<(), EVMError> { - let mut storage_keys = self.accounts_storage.keyset.to_span(); - while let Option::Some(state_key) = storage_keys.pop_front() { - let (evm_address, key, value) = self.accounts_storage.changes.get(*state_key).deref(); - let mut account = self.get_account(evm_address); - // @dev: EIP-6780 - If selfdestruct on an account created, dont commit data - if account.is_selfdestruct() { - continue; - } - IAccountDispatcher { contract_address: account.starknet_address() } - .write_storage(key, value); - }; - Result::Ok(()) + // Write updated nonce and storage + //TODO: storage commits are done in the State commitment as they're not part of the account + //model in SSJ + let starknet_account = IAccountDispatcher { contract_address: self.starknet_address() }; + starknet_account.set_nonce(*self.nonce); + + //Storage is handled outside of the account and must be committed after all accounts are + //committed. + if self.is_created() { + starknet_account.write_bytecode(self.bytecode()); + //TODO: save valid jumpdests https://github.com/kkrt-labs/kakarot-ssj/issues/839 + //TODO: set code hash https://github.com/kkrt-labs/kakarot-ssj/issues/840 } + return; +} + +/// Iterates through the list of pending transfer and triggers them +fn transfer_native_token(ref self: State) -> Result<(), EVMError> { + let kakarot_state = KakarotCore::unsafe_new_contract_state(); + let native_token = kakarot_state.get_native_token(); + while let Option::Some(transfer) = self.transfers.pop_front() { + IERC20CamelDispatcher { contract_address: native_token } + .transferFrom(transfer.sender.starknet, transfer.recipient.starknet, transfer.amount); + }; + Result::Ok(()) +} + +/// Iterates through the list of events and emits them. +fn emit_events(ref self: State) -> Result<(), EVMError> { + while let Option::Some(event) = self.events.pop_front() { + let mut keys = Default::default(); + let mut data = Default::default(); + Serde::>::serialize(@event.keys, ref keys); + Serde::>::serialize(@event.data, ref data); + emit_event_syscall(keys.span(), data.span()).unwrap_syscall(); + }; + return Result::Ok(()); +} + +/// Commits storage changes to the KakarotCore contract by writing pending +/// state changes to Starknet Storage. +/// commit_storage MUST be called after commit_accounts. +fn commit_storage(ref self: State) -> Result<(), EVMError> { + let mut storage_keys = self.accounts_storage.keyset.to_span(); + while let Option::Some(state_key) = storage_keys.pop_front() { + let (evm_address, key, value) = self.accounts_storage.changes.get(*state_key).deref(); + let mut account = self.get_account(evm_address); + // @dev: EIP-6780 - If selfdestruct on an account created, dont commit data + if account.is_selfdestruct() { + continue; + } + IAccountDispatcher { contract_address: account.starknet_address() } + .write_storage(key, value); + }; + Result::Ok(()) } #[cfg(test)] mod tests { - use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; - use contracts::kakarot_core::KakarotCore; use core::starknet::ClassHash; use evm::backend::starknet_backend; - use evm::errors::EVMErrorTrait; use evm::model::Address; - use evm::model::account::{Account, AccountTrait}; + use evm::model::account::Account; use evm::state::{State, StateTrait}; + use evm::test_utils::evm_address; use evm::test_utils::{ setup_test_storages, uninitialized_account, account_contract, register_account }; - use evm::test_utils::{chain_id, evm_address, VMBuilderTrait}; - use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait; - use snforge_std::{spy_events, EventSpyTrait, test_address, start_mock_call, get_class_hash}; - use snforge_utils::snforge_utils::{ - ContractEvents, ContractEventsTrait, EventsFilterBuilderTrait, assert_not_called, - assert_called, assert_called_with - }; + use snforge_std::{test_address, start_mock_call, get_class_hash}; + use snforge_utils::snforge_utils::{assert_not_called, assert_called}; use utils::helpers::compute_starknet_address; #[test] diff --git a/crates/evm/src/call_helpers.cairo b/crates/evm/src/call_helpers.cairo index 8868703a4..e9f70e75b 100644 --- a/crates/evm/src/call_helpers.cairo +++ b/crates/evm/src/call_helpers.cairo @@ -2,26 +2,23 @@ use contracts::kakarot_core::KakarotCore; use contracts::kakarot_core::interface::IKakarotCore; //! CALL, CALLCODE, DELEGATECALL, STATICCALL opcode helpers use core::cmp::min; -use core::starknet::{EthAddress, get_contract_address}; +use core::starknet::EthAddress; -use evm::errors::{EVMError, CALL_GAS_GT_GAS_LIMIT, ACTIVE_MACHINE_STATE_IN_CALL_FINALIZATION}; -use evm::gas; +use evm::errors::EVMError; use evm::interpreter::EVMTrait; use evm::memory::MemoryTrait; -use evm::model::account::{AccountTrait}; use evm::model::vm::{VM, VMTrait}; -use evm::model::{Transfer, Address, Message, ExecutionResultTrait, ExecutionResultStatus}; +use evm::model::{Address, Message, ExecutionResultStatus}; use evm::stack::StackTrait; use evm::state::StateTrait; use utils::constants; -use utils::helpers::compute_starknet_address; use utils::set::SetTrait; use utils::traits::{BoolIntoNumeric, U256TryIntoResult}; /// CallArgs is a subset of CallContext /// Created in order to simplify setting up the call opcodes #[derive(Drop, PartialEq)] -struct CallArgs { +pub struct CallArgs { caller: Address, code_address: Address, to: Address, @@ -36,7 +33,7 @@ struct CallArgs { } #[derive(Drop)] -enum CallType { +pub enum CallType { Call, DelegateCall, CallCode, @@ -44,7 +41,7 @@ enum CallType { } #[generate_trait] -impl CallHelpersImpl of CallHelpers { +pub impl CallHelpersImpl of CallHelpers { /// Initializes and enters into a new sub-context /// The Machine will change its `current_ctx` to point to the /// newly created sub-context. diff --git a/crates/evm/src/create_helpers.cairo b/crates/evm/src/create_helpers.cairo index 5e7a7d061..64ff58a16 100644 --- a/crates/evm/src/create_helpers.cairo +++ b/crates/evm/src/create_helpers.cairo @@ -1,29 +1,19 @@ -use contracts::kakarot_core::KakarotCore; -use contracts::kakarot_core::interface::IKakarotCore; -//! CREATE, CREATE2 opcode helpers -use core::cmp::min; -use core::keccak::cairo_keccak; use core::num::traits::Bounded; use core::num::traits::Zero; -use core::starknet::{EthAddress, get_tx_info}; -use evm::errors::{ - ensure, EVMError, CALL_GAS_GT_GAS_LIMIT, ACTIVE_MACHINE_STATE_IN_CALL_FINALIZATION -}; +use core::starknet::EthAddress; +use evm::errors::{ensure, EVMError}; use evm::gas; use evm::interpreter::EVMTrait; use evm::memory::MemoryTrait; +use evm::model::Message; use evm::model::account::{Account, AccountTrait}; use evm::model::vm::{VM, VMTrait}; -use evm::model::{ - ExecutionResult, ExecutionResultTrait, ExecutionResultStatus, ExecutionSummary, Environment -}; -use evm::model::{Message, Address, Transfer}; +use evm::model::{ExecutionResult, ExecutionResultTrait, ExecutionResultStatus}; use evm::stack::StackTrait; use evm::state::StateTrait; use utils::address::{compute_contract_address, compute_create2_contract_address}; use utils::constants; -use utils::helpers::ArrayExtTrait; -use utils::helpers::{ResultExTrait, EthAddressExTrait, U256Trait, U8SpanExTrait, ceil32}; +use utils::helpers::ceil32; use utils::set::SetTrait; use utils::traits::{ BoolIntoNumeric, EthAddressIntoU256, U256TryIntoResult, SpanU8TryIntoResultEthAddress @@ -31,20 +21,20 @@ use utils::traits::{ /// Helper struct to prepare CREATE and CREATE2 opcodes #[derive(Drop)] -struct CreateArgs { +pub struct CreateArgs { to: EthAddress, value: u256, bytecode: Span, } #[derive(Copy, Drop)] -enum CreateType { +pub enum CreateType { Create, Create2, } #[generate_trait] -impl CreateHelpersImpl of CreateHelpers { +pub impl CreateHelpersImpl of CreateHelpers { /// Prepare the initialization of a new child or so-called sub-context /// As part of the CREATE family of opcodes. fn prepare_create(ref self: VM, create_type: CreateType) -> Result { @@ -189,11 +179,7 @@ impl CreateHelpersImpl of CreateHelpers { #[cfg(test)] mod tests { - use contracts::test_data::counter_evm_bytecode; - use core::starknet::EthAddress; - use evm::create_helpers::CreateHelpers; - use evm::test_utils::{VMBuilderTrait}; - use utils::address::{compute_contract_address, compute_create2_contract_address}; //TODO: test create helpers + } diff --git a/crates/evm/src/errors.cairo b/crates/evm/src/errors.cairo index f71025545..097720215 100644 --- a/crates/evm/src/errors.cairo +++ b/crates/evm/src/errors.cairo @@ -1,47 +1,47 @@ use core::fmt::{Debug, Formatter, Error, Display}; -use utils::helpers::{U256Trait, ToBytes}; +use utils::helpers::ToBytes; // STACK // INSTRUCTIONS -const PC_OUT_OF_BOUNDS: felt252 = 'KKT: pc >= bytecode length'; +pub const PC_OUT_OF_BOUNDS: felt252 = 'KKT: pc >= bytecode length'; // TYPE CONVERSION -const TYPE_CONVERSION_ERROR: felt252 = 'KKT: type conversion error'; +pub const TYPE_CONVERSION_ERROR: felt252 = 'KKT: type conversion error'; // NUMERIC OPERATIONS -const BALANCE_OVERFLOW: felt252 = 'KKT: balance overflow'; +pub const BALANCE_OVERFLOW: felt252 = 'KKT: balance overflow'; // JUMP -const INVALID_DESTINATION: felt252 = 'KKT: invalid JUMP destination'; +pub const INVALID_DESTINATION: felt252 = 'KKT: invalid JUMP destination'; // CALL -const VALUE_TRANSFER_IN_STATIC_CALL: felt252 = 'KKT: transfer value in static'; -const ACTIVE_MACHINE_STATE_IN_CALL_FINALIZATION: felt252 = 'KKT: active state in end call'; -const MISSING_PARENT_CONTEXT: felt252 = 'KKT: missing parent context'; -const CALL_GAS_GT_GAS_LIMIT: felt252 = 'KKT: call gas gt gas limit'; +pub const VALUE_TRANSFER_IN_STATIC_CALL: felt252 = 'KKT: transfer value in static'; +pub const ACTIVE_MACHINE_STATE_IN_CALL_FINALIZATION: felt252 = 'KKT: active state in end call'; +pub const MISSING_PARENT_CONTEXT: felt252 = 'KKT: missing parent context'; +pub const CALL_GAS_GT_GAS_LIMIT: felt252 = 'KKT: call gas gt gas limit'; // EVM STATE // STARKNET_SYSCALLS -const READ_SYSCALL_FAILED: felt252 = 'KKT: read syscall failed'; -const BLOCK_HASH_SYSCALL_FAILED: felt252 = 'KKT: block_hash syscall failed'; -const WRITE_SYSCALL_FAILED: felt252 = 'KKT: write syscall failed'; -const CONTRACT_SYSCALL_FAILED: felt252 = 'KKT: contract syscall failed'; -const EXECUTION_INFO_SYSCALL_FAILED: felt252 = 'KKT: exec info syscall failed'; +pub const READ_SYSCALL_FAILED: felt252 = 'KKT: read syscall failed'; +pub const BLOCK_HASH_SYSCALL_FAILED: felt252 = 'KKT: block_hash syscall failed'; +pub const WRITE_SYSCALL_FAILED: felt252 = 'KKT: write syscall failed'; +pub const CONTRACT_SYSCALL_FAILED: felt252 = 'KKT: contract syscall failed'; +pub const EXECUTION_INFO_SYSCALL_FAILED: felt252 = 'KKT: exec info syscall failed'; // CREATE -const CONTRACT_ACCOUNT_EXISTS: felt252 = 'KKT: Contract Account exists'; -const EOA_EXISTS: felt252 = 'KKT: EOA already exists'; -const ACCOUNT_EXISTS: felt252 = 'KKT: Account already exists'; -const DEPLOYMENT_FAILED: felt252 = 'KKT: deployment failed'; +pub const CONTRACT_ACCOUNT_EXISTS: felt252 = 'KKT: Contract Account exists'; +pub const EOA_EXISTS: felt252 = 'KKT: EOA already exists'; +pub const ACCOUNT_EXISTS: felt252 = 'KKT: Account already exists'; +pub const DEPLOYMENT_FAILED: felt252 = 'KKT: deployment failed'; // TRANSACTION ORIGIN -const CALLING_FROM_UNDEPLOYED_ACCOUNT: felt252 = 'EOA: from is undeployed EOA'; -const CALLING_FROM_CA: felt252 = 'EOA: from is a contract account'; +pub const CALLING_FROM_UNDEPLOYED_ACCOUNT: felt252 = 'EOA: from is undeployed EOA'; +pub const CALLING_FROM_CA: felt252 = 'EOA: from is a contract account'; #[derive(Drop, Copy, PartialEq)] -enum EVMError { +pub enum EVMError { StackOverflow, StackUnderflow, TypeConversionError: felt252, @@ -61,7 +61,7 @@ enum EVMError { } #[generate_trait] -impl EVMErrorImpl of EVMErrorTrait { +pub impl EVMErrorImpl of EVMErrorTrait { fn to_string(self: EVMError) -> felt252 { match self { EVMError::StackOverflow => 'stack overflow', @@ -91,7 +91,7 @@ impl EVMErrorImpl of EVMErrorTrait { } } -impl DebugEVMError of Debug { +pub impl DebugEVMError of Debug { fn fmt(self: @EVMError, ref f: Formatter) -> Result<(), Error> { let error_message = (*self).to_string(); Display::fmt(@error_message, ref f) @@ -99,7 +99,7 @@ impl DebugEVMError of Debug { } #[inline(always)] -fn ensure(cond: bool, err: EVMError) -> Result<(), EVMError> { +pub fn ensure(cond: bool, err: EVMError) -> Result<(), EVMError> { if cond { Result::Ok(()) } else { diff --git a/crates/evm/src/gas.cairo b/crates/evm/src/gas.cairo index dd9e90a7b..7d936e532 100644 --- a/crates/evm/src/gas.cairo +++ b/crates/evm/src/gas.cairo @@ -1,5 +1,4 @@ use core::cmp::min; -use core::starknet::EthAddress; use utils::eth_transaction::{AccessListItem, EthereumTransaction, EthereumTransactionTrait}; use utils::helpers; @@ -7,50 +6,50 @@ use utils::helpers; //! Code is based on alloy project //! Source: -const ZERO: u128 = 0; -const BASE: u128 = 2; -const VERYLOW: u128 = 3; -const LOW: u128 = 5; -const MID: u128 = 8; -const HIGH: u128 = 10; -const JUMPDEST: u128 = 1; -const SELFDESTRUCT: u128 = 5000; -const CREATE: u128 = 32000; -const CALLVALUE: u128 = 9000; -const NEWACCOUNT: u128 = 25000; -const EXP: u128 = 10; -const EXP_GAS_PER_BYTE: u128 = 50; -const MEMORY: u128 = 3; -const LOG: u128 = 375; -const LOGDATA: u128 = 8; -const LOGTOPIC: u128 = 375; -const KECCAK256: u128 = 30; -const KECCAK256WORD: u128 = 6; -const COPY: u128 = 3; -const BLOCKHASH: u128 = 20; -const CODEDEPOSIT: u128 = 200; - -const SSTORE_SET: u128 = 20000; -const SSTORE_RESET: u128 = 5000; -const REFUND_SSTORE_CLEARS: u128 = 4800; - -const TRANSACTION_ZERO_DATA: u128 = 4; -const TRANSACTION_NON_ZERO_DATA_INIT: u128 = 16; -const TRANSACTION_NON_ZERO_DATA_FRONTIER: u128 = 68; -const TRANSACTION_BASE_COST: u128 = 21000; -const TRANSACTION_CREATE_COST: u128 = 32000; +pub const ZERO: u128 = 0; +pub const BASE: u128 = 2; +pub const VERYLOW: u128 = 3; +pub const LOW: u128 = 5; +pub const MID: u128 = 8; +pub const HIGH: u128 = 10; +pub const JUMPDEST: u128 = 1; +pub const SELFDESTRUCT: u128 = 5000; +pub const CREATE: u128 = 32000; +pub const CALLVALUE: u128 = 9000; +pub const NEWACCOUNT: u128 = 25000; +pub const EXP: u128 = 10; +pub const EXP_GAS_PER_BYTE: u128 = 50; +pub const MEMORY: u128 = 3; +pub const LOG: u128 = 375; +pub const LOGDATA: u128 = 8; +pub const LOGTOPIC: u128 = 375; +pub const KECCAK256: u128 = 30; +pub const KECCAK256WORD: u128 = 6; +pub const COPY: u128 = 3; +pub const BLOCKHASH: u128 = 20; +pub const CODEDEPOSIT: u128 = 200; + +pub const SSTORE_SET: u128 = 20000; +pub const SSTORE_RESET: u128 = 5000; +pub const REFUND_SSTORE_CLEARS: u128 = 4800; + +pub const TRANSACTION_ZERO_DATA: u128 = 4; +pub const TRANSACTION_NON_ZERO_DATA_INIT: u128 = 16; +pub const TRANSACTION_NON_ZERO_DATA_FRONTIER: u128 = 68; +pub const TRANSACTION_BASE_COST: u128 = 21000; +pub const TRANSACTION_CREATE_COST: u128 = 32000; // Berlin EIP-2929 constants -const ACCESS_LIST_ADDRESS: u128 = 2400; -const ACCESS_LIST_STORAGE_KEY: u128 = 1900; -const COLD_SLOAD_COST: u128 = 2100; -const COLD_ACCOUNT_ACCESS_COST: u128 = 2600; -const WARM_ACCESS_COST: u128 = 100; +pub const ACCESS_LIST_ADDRESS: u128 = 2400; +pub const ACCESS_LIST_STORAGE_KEY: u128 = 1900; +pub const COLD_SLOAD_COST: u128 = 2100; +pub const COLD_ACCOUNT_ACCESS_COST: u128 = 2600; +pub const WARM_ACCESS_COST: u128 = 100; /// EIP-3860 : Limit and meter initcode -const INITCODE_WORD_COST: u128 = 2; +pub const INITCODE_WORD_COST: u128 = 2; -const CALL_STIPEND: u128 = 2300; +pub const CALL_STIPEND: u128 = 2300; // EIP-4844 pub const BLOB_HASH_COST: u128 = 3; @@ -62,9 +61,9 @@ pub const BLOB_HASH_COST: u128 = 3; /// * `cost`: The non-refundable portion of gas reserved for executing the call opcode. /// * `stipend`: The portion of gas available to sub-calls that is refundable if not consumed. #[derive(Drop)] -struct MessageCallGas { - cost: u128, - stipend: u128, +pub struct MessageCallGas { + pub cost: u128, + pub stipend: u128, } /// Defines the new size and the expansion cost after memory expansion. @@ -74,9 +73,9 @@ struct MessageCallGas { /// * `new_size`: The new size of the memory after extension. /// * `expansion_cost`: The cost of the memory extension. #[derive(Drop)] -struct MemoryExpansion { - new_size: u32, - expansion_cost: u128, +pub struct MemoryExpansion { + pub new_size: u32, + pub expansion_cost: u128, } /// Calculates the maximum gas that is allowed for making a message call. @@ -86,7 +85,7 @@ struct MemoryExpansion { /// /// # Returns /// * The maximum gas allowed for the message call. -fn max_message_call_gas(gas: u128) -> u128 { +pub fn max_message_call_gas(gas: u128) -> u128 { gas - (gas / 64) } @@ -106,7 +105,7 @@ fn max_message_call_gas(gas: u128) -> u128 { /// # Returns /// /// * `message_call_gas`: `MessageCallGas` -fn calculate_message_call_gas( +pub fn calculate_message_call_gas( value: u256, gas: u128, gas_left: u128, memory_cost: u128, extra_gas: u128 ) -> MessageCallGas { let call_stipend = if value == 0 { @@ -142,7 +141,7 @@ fn calculate_message_call_gas( /// # Returns /// /// * `total_gas_cost` - The gas cost for storing data in memory. -fn calculate_memory_gas_cost(size_in_bytes: usize) -> u128 { +pub fn calculate_memory_gas_cost(size_in_bytes: usize) -> u128 { let _512: NonZero = 512_u128.try_into().unwrap(); let size_in_words = (size_in_bytes + 31) / 32; let linear_cost = size_in_words.into() * MEMORY; @@ -165,7 +164,7 @@ fn calculate_memory_gas_cost(size_in_bytes: usize) -> u128 { /// # Returns /// /// * `MemoryExpansion`: New size and expansion cost. -fn memory_expansion(current_size: usize, operations: Span<(usize, usize)>) -> MemoryExpansion { +pub fn memory_expansion(current_size: usize, operations: Span<(usize, usize)>) -> MemoryExpansion { let mut max_size = current_size; for ( @@ -202,7 +201,7 @@ fn memory_expansion(current_size: usize, operations: Span<(usize, usize)>) -> Me /// /// * `init_code_gas` - The gas to be charged for the init code. #[inline(always)] -fn init_code_cost(code_size: usize) -> u128 { +pub fn init_code_cost(code_size: usize) -> u128 { let code_size_in_words = helpers::ceil32(code_size) / 32; code_size_in_words.into() * INITCODE_WORD_COST } @@ -220,7 +219,7 @@ fn init_code_cost(code_size: usize) -> u128 { /// /// Reference: /// https://github.com/ethereum/execution-specs/blob/master/src/ethereum/shanghai/fork.py#L689 -fn calculate_intrinsic_gas_cost(tx: @EthereumTransaction) -> u128 { +pub fn calculate_intrinsic_gas_cost(tx: @EthereumTransaction) -> u128 { let mut data_cost: u128 = 0; let target = tx.destination(); @@ -259,7 +258,6 @@ fn calculate_intrinsic_gas_cost(tx: @EthereumTransaction) -> u128 { #[cfg(test)] mod tests { - use core::option::OptionTrait; use core::starknet::EthAddress; use evm::gas::{ @@ -268,10 +266,9 @@ mod tests { }; use evm::test_utils::evm_address; use utils::eth_transaction::{ - EthereumTransaction, LegacyTransaction, AccessListTransaction, EthereumTransactionTrait, - AccessListItem + EthereumTransaction, LegacyTransaction, AccessListTransaction, AccessListItem }; - use utils::helpers::{U256Trait, ToBytes}; + use utils::helpers::ToBytes; #[test] fn test_calculate_intrinsic_gas_cost() { diff --git a/crates/evm/src/instructions.cairo b/crates/evm/src/instructions.cairo index a6b0192f9..e632d1169 100644 --- a/crates/evm/src/instructions.cairo +++ b/crates/evm/src/instructions.cairo @@ -1,25 +1,34 @@ /// Sub modules. mod block_information; + mod comparison_operations; mod duplication_operations; + mod environmental_information; + mod exchange_operations; + mod logging_operations; + mod memory_operations; + mod push_operations; + mod sha3; + mod stop_and_arithmetic_operations; + mod system_operations; -use block_information::BlockInformationTrait; -use comparison_operations::ComparisonAndBitwiseOperationsTrait; -use duplication_operations::DuplicationOperationsTrait; -use environmental_information::EnvironmentInformationTrait; -use exchange_operations::ExchangeOperationsTrait; -use logging_operations::LoggingOperationsTrait; -use memory_operations::MemoryOperationTrait; -use push_operations::PushOperationsTrait; -use sha3::Sha3Trait; -use stop_and_arithmetic_operations::StopAndArithmeticOperationsTrait; -use system_operations::SystemOperationsTrait; +pub use block_information::BlockInformationTrait; +pub use comparison_operations::ComparisonAndBitwiseOperationsTrait; +pub use duplication_operations::DuplicationOperationsTrait; +pub use environmental_information::EnvironmentInformationTrait; +pub use exchange_operations::ExchangeOperationsTrait; +pub use logging_operations::LoggingOperationsTrait; +pub use memory_operations::MemoryOperationTrait; +pub use push_operations::PushOperationsTrait; +pub use sha3::Sha3Trait; +pub use stop_and_arithmetic_operations::StopAndArithmeticOperationsTrait; +pub use system_operations::SystemOperationsTrait; diff --git a/crates/evm/src/instructions/block_information.cairo b/crates/evm/src/instructions/block_information.cairo index c163de3fa..3f46957d9 100644 --- a/crates/evm/src/instructions/block_information.cairo +++ b/crates/evm/src/instructions/block_information.cairo @@ -1,28 +1,18 @@ //! Block Information. -use contracts::kakarot_core::{KakarotCore, IKakarotCore}; use core::starknet::SyscallResultTrait; +use core::starknet::syscalls::get_block_hash_syscall; -// Corelib imports -use core::starknet::info::get_block_number; -use core::starknet::{get_block_hash_syscall, EthAddress}; - -use evm::errors::{ - EVMError, BLOCK_HASH_SYSCALL_FAILED, EXECUTION_INFO_SYSCALL_FAILED, TYPE_CONVERSION_ERROR -}; +use evm::errors::EVMError; use evm::gas; -use evm::model::account::{AccountTrait}; use evm::model::vm::{VM, VMTrait}; -use evm::model::{Account}; use evm::stack::StackTrait; use evm::state::StateTrait; - -use utils::helpers::ResultExTrait; use utils::traits::{EthAddressTryIntoResultContractAddress, EthAddressIntoU256}; #[generate_trait] -impl BlockInformation of BlockInformationTrait { +pub impl BlockInformation of BlockInformationTrait { /// 0x40 - BLOCKHASH /// Get the hash of one of the 256 most recent complete blocks. /// # Specification: https://www.evm.codes/#40?fork=shanghai @@ -150,26 +140,14 @@ impl BlockInformation of BlockInformationTrait { #[cfg(test)] mod tests { - use contracts::kakarot_core::interface::{ - IExtendedKakarotCoreDispatcher, IExtendedKakarotCoreDispatcherTrait - }; - use core::result::ResultTrait; - use core::starknet::testing::{set_contract_address, ContractAddress}; use evm::instructions::BlockInformationTrait; - use evm::model::account::{Account, AccountTrait}; + use evm::model::account::Account; use evm::model::vm::VMTrait; use evm::stack::StackTrait; use evm::state::StateTrait; - use evm::test_utils::{ - evm_address, VMBuilderTrait, tx_gas_limit, gas_price, native_token, setup_test_storages, - register_account - }; - use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait; - use snforge_std::{ - start_cheat_block_number_global, start_cheat_block_timestamp_global, - start_cheat_caller_address, test_address, start_mock_call - }; + use evm::test_utils::{VMBuilderTrait, gas_price, setup_test_storages}; + use snforge_std::{start_cheat_block_number_global, start_cheat_block_timestamp_global}; use utils::constants; use utils::traits::{EthAddressIntoU256}; diff --git a/crates/evm/src/instructions/comparison_operations.cairo b/crates/evm/src/instructions/comparison_operations.cairo index da6270422..594bc0320 100644 --- a/crates/evm/src/instructions/comparison_operations.cairo +++ b/crates/evm/src/instructions/comparison_operations.cairo @@ -6,11 +6,11 @@ use evm::model::vm::{VM, VMTrait}; use evm::stack::StackTrait; use utils::constants::{POW_2_127}; use utils::i256::i256; -use utils::math::{Exponentiation, Bitshift, WrappingBitshift}; +use utils::math::{Bitshift, WrappingBitshift}; use utils::traits::BoolIntoNumeric; #[generate_trait] -impl ComparisonAndBitwiseOperations of ComparisonAndBitwiseOperationsTrait { +pub impl ComparisonAndBitwiseOperations of ComparisonAndBitwiseOperationsTrait { /// 0x10 - LT /// # Specification: https://www.evm.codes/#10?fork=shanghai fn exec_lt(ref self: VM) -> Result<(), EVMError> { diff --git a/crates/evm/src/instructions/duplication_operations.cairo b/crates/evm/src/instructions/duplication_operations.cairo index 4e9697e3a..8aa3024b5 100644 --- a/crates/evm/src/instructions/duplication_operations.cairo +++ b/crates/evm/src/instructions/duplication_operations.cairo @@ -2,125 +2,119 @@ // Internal imports use evm::errors::EVMError; +use evm::gas; use evm::model::vm::{VM, VMTrait}; - -mod internal { - use evm::errors::EVMError; - use evm::gas; - use evm::model::vm::{VM, VMTrait}; - use evm::stack::StackTrait; - - /// Generic DUP operation - #[inline(always)] - fn exec_dup_i(ref self: VM, i: u8) -> Result<(), EVMError> { - self.charge_gas(gas::VERYLOW)?; - let item = self.stack.peek_at((i - 1).into())?; - self.stack.push(item) - } +use evm::stack::StackTrait; + +/// Generic DUP operation +#[inline(always)] +fn exec_dup_i(ref self: VM, i: u8) -> Result<(), EVMError> { + self.charge_gas(gas::VERYLOW)?; + let item = self.stack.peek_at((i - 1).into())?; + self.stack.push(item) } #[generate_trait] -impl DuplicationOperations of DuplicationOperationsTrait { +pub impl DuplicationOperations of DuplicationOperationsTrait { /// 0x80 - DUP1 operation #[inline(always)] fn exec_dup1(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 1) + exec_dup_i(ref self, 1) } /// 0x81 - DUP2 operation #[inline(always)] fn exec_dup2(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 2) + exec_dup_i(ref self, 2) } /// 0x82 - DUP3 operation #[inline(always)] fn exec_dup3(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 3) + exec_dup_i(ref self, 3) } /// 0x83 - DUP2 operation #[inline(always)] fn exec_dup4(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 4) + exec_dup_i(ref self, 4) } /// 0x84 - DUP5 operation #[inline(always)] fn exec_dup5(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 5) + exec_dup_i(ref self, 5) } /// 0x85 - DUP6 operation #[inline(always)] fn exec_dup6(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 6) + exec_dup_i(ref self, 6) } /// 0x86 - DUP7 operation #[inline(always)] fn exec_dup7(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 7) + exec_dup_i(ref self, 7) } /// 0x87 - DUP8 operation #[inline(always)] fn exec_dup8(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 8) + exec_dup_i(ref self, 8) } /// 0x88 - DUP9 operation #[inline(always)] fn exec_dup9(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 9) + exec_dup_i(ref self, 9) } /// 0x89 - DUP10 operation #[inline(always)] fn exec_dup10(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 10) + exec_dup_i(ref self, 10) } /// 0x8A - DUP11 operation #[inline(always)] fn exec_dup11(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 11) + exec_dup_i(ref self, 11) } /// 0x8B - DUP12 operation #[inline(always)] fn exec_dup12(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 12) + exec_dup_i(ref self, 12) } /// 0x8C - DUP13 operation #[inline(always)] fn exec_dup13(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 13) + exec_dup_i(ref self, 13) } /// 0x8D - DUP14 operation #[inline(always)] fn exec_dup14(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 14) + exec_dup_i(ref self, 14) } /// 0x8E - DUP15 operation #[inline(always)] fn exec_dup15(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 15) + exec_dup_i(ref self, 15) } /// 0x8F - DUP16 operation #[inline(always)] fn exec_dup16(ref self: VM) -> Result<(), EVMError> { - internal::exec_dup_i(ref self, 16) + exec_dup_i(ref self, 16) } } #[cfg(test)] mod tests { - use core::num::traits::Bounded; use evm::instructions::DuplicationOperationsTrait; use evm::stack::Stack; use evm::stack::StackTrait; diff --git a/crates/evm/src/instructions/environmental_information.cairo b/crates/evm/src/instructions/environmental_information.cairo index 3cee0f22b..6f086f5c2 100644 --- a/crates/evm/src/instructions/environmental_information.cairo +++ b/crates/evm/src/instructions/environmental_information.cairo @@ -1,14 +1,6 @@ -use contracts::kakarot_core::interface::{IKakarotCore}; -use contracts::kakarot_core::{KakarotCore}; -use core::hash::{HashStateExTrait, HashStateTrait}; -use core::keccak::cairo_keccak; use core::num::traits::OverflowingAdd; use core::num::traits::Zero; -use core::pedersen::{PedersenTrait, HashState}; -use core::starknet::{ - Store, storage_base_address_from_felt252, ContractAddress, get_contract_address -}; -use evm::errors::{ensure, EVMError, READ_SYSCALL_FAILED}; +use evm::errors::{ensure, EVMError}; use evm::gas; use evm::memory::MemoryTrait; use evm::model::account::{AccountTrait}; @@ -16,17 +8,14 @@ use evm::model::vm::{VM, VMTrait}; use evm::model::{AddressTrait}; use evm::stack::StackTrait; use evm::state::StateTrait; -use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; use utils::constants::EMPTY_KECCAK; -use utils::helpers::ResultExTrait; -use utils::helpers::{ceil32, load_word, U256Trait, U8SpanExTrait}; -use utils::math::BitshiftImpl; +use utils::helpers::{ceil32, load_word, U8SpanExTrait}; use utils::set::SetTrait; use utils::traits::{EthAddressIntoU256}; #[generate_trait] -impl EnvironmentInformationImpl of EnvironmentInformationTrait { +pub impl EnvironmentInformationImpl of EnvironmentInformationTrait { /// 0x30 - ADDRESS /// Get address of currently executing account. /// # Specification: https://www.evm.codes/#30?fork=shanghai @@ -319,26 +308,18 @@ fn copy_bytes_to_memory( #[cfg(test)] mod tests { - use contracts::kakarot_core::{interface::IExtendedKakarotCoreDispatcherImpl, KakarotCore}; use contracts::test_data::counter_evm_bytecode; - use core::num::traits::CheckedAdd; use core::starknet::EthAddress; - - use core::starknet::testing::set_contract_address; use evm::errors::{EVMError, TYPE_CONVERSION_ERROR}; use evm::instructions::EnvironmentInformationTrait; use evm::memory::{InternalMemoryTrait, MemoryTrait}; - use evm::model::vm::{VM, VMTrait}; + use evm::model::vm::VMTrait; use evm::model::{Account, Address}; use evm::stack::StackTrait; use evm::state::StateTrait; - use evm::test_utils::{ - VMBuilderTrait, evm_address, origin, callvalue, native_token, other_address, gas_price, - tx_gas_limit, register_account - }; - use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait; - use snforge_std::{test_address, start_mock_call}; + use evm::test_utils::{VMBuilderTrait, origin, callvalue, gas_price}; + use snforge_std::test_address; use utils::helpers::{u256_to_bytes_array, ArrayExtTrait, compute_starknet_address}; use utils::traits::{EthAddressIntoU256}; @@ -346,7 +327,6 @@ mod tests { mod test_internals { use evm::memory::MemoryTrait; - use evm::model::vm::VMTrait; use evm::test_utils::VMBuilderTrait; use super::super::copy_bytes_to_memory; @@ -1061,7 +1041,7 @@ mod tests { fn test_exec_extcodehash_precompile() { // Given let mut vm = VMBuilderTrait::new_with_presets().build(); - let precompile_evm_address: EthAddress = evm::model::LAST_ETHEREUM_PRECOMPILE_ADDRESS + let precompile_evm_address: EthAddress = evm::precompiles::LAST_ETHEREUM_PRECOMPILE_ADDRESS .try_into() .unwrap(); let precompile_starknet_address = compute_starknet_address( diff --git a/crates/evm/src/instructions/exchange_operations.cairo b/crates/evm/src/instructions/exchange_operations.cairo index 14518ddf4..4b6f458e3 100644 --- a/crates/evm/src/instructions/exchange_operations.cairo +++ b/crates/evm/src/instructions/exchange_operations.cairo @@ -1,145 +1,136 @@ //! Exchange Operations. use evm::errors::EVMError; +use evm::gas; use evm::model::vm::{VM, VMTrait}; use evm::stack::StackTrait; -use utils::helpers::load_word; -mod internal { - use evm::errors::EVMError; - use evm::gas; - use evm::model::vm::{VM, VMTrait}; - use evm::stack::StackTrait; - use utils::helpers::load_word; - - /// Place i bytes items on stack. - #[inline(always)] - fn exec_swap_i(ref self: VM, i: u8) -> Result<(), EVMError> { - self.charge_gas(gas::VERYLOW)?; - self.stack.swap_i(i.into()) - } +/// Place i bytes items on stack. +#[inline(always)] +fn exec_swap_i(ref self: VM, i: u8) -> Result<(), EVMError> { + self.charge_gas(gas::VERYLOW)?; + self.stack.swap_i(i.into()) } #[generate_trait] -impl ExchangeOperations of ExchangeOperationsTrait { +pub impl ExchangeOperations of ExchangeOperationsTrait { /// 0x90 - SWAP1 operation /// Exchange 1st and 2nd stack items. /// # Specification: https://www.evm.codes/#90?fork=shanghai fn exec_swap1(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 1) + exec_swap_i(ref self, 1) } /// 0x91 - SWAP2 operation /// Exchange 1st and 3rd stack items. /// # Specification: https://www.evm.codes/#91?fork=shanghai fn exec_swap2(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 2) + exec_swap_i(ref self, 2) } /// 0x92 - SWAP3 operation /// Exchange 1st and 4th stack items. /// # Specification: https://www.evm.codes/#92?fork=shanghai fn exec_swap3(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 3) + exec_swap_i(ref self, 3) } /// 0x93 - SWAP4 operation /// Exchange 1st and 5th stack items. /// # Specification: https://www.evm.codes/#93?fork=shanghai fn exec_swap4(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 4) + exec_swap_i(ref self, 4) } /// 0x94 - SWAP5 operation /// Exchange 1st and 6th stack items. /// # Specification: https://www.evm.codes/#94?fork=shanghai fn exec_swap5(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 5) + exec_swap_i(ref self, 5) } /// 0x95 - SWAP6 operation /// Exchange 1st and 7th stack items. /// # Specification: https://www.evm.codes/#95?fork=shanghai fn exec_swap6(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 6) + exec_swap_i(ref self, 6) } /// 0x96 - SWAP7 operation /// Exchange 1st and 8th stack items. /// # Specification: https://www.evm.codes/#96?fork=shanghai fn exec_swap7(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 7) + exec_swap_i(ref self, 7) } /// 0x97 - SWAP8 operation /// Exchange 1st and 9th stack items. /// # Specification: https://www.evm.codes/#97?fork=shanghai fn exec_swap8(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 8) + exec_swap_i(ref self, 8) } /// 0x98 - SWAP9 operation /// Exchange 1st and 10th stack items. /// # Specification: https://www.evm.codes/#98?fork=shanghai fn exec_swap9(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 9) + exec_swap_i(ref self, 9) } /// 0x99 - SWAP10 operation /// Exchange 1st and 11th stack items. /// # Specification: https://www.evm.codes/#99?fork=shanghai fn exec_swap10(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 10) + exec_swap_i(ref self, 10) } /// 0x9A - SWAP11 operation /// Exchange 1st and 12th stack items. /// # Specification: https://www.evm.codes/#9a?fork=shanghai fn exec_swap11(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 11) + exec_swap_i(ref self, 11) } /// 0x9B - SWAP12 operation /// Exchange 1st and 13th stack items. /// # Specification: https://www.evm.codes/#9b?fork=shanghai fn exec_swap12(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 12) + exec_swap_i(ref self, 12) } /// 0x9C - SWAP13 operation /// Exchange 1st and 14th stack items. /// # Specification: https://www.evm.codes/#9c?fork=shanghai fn exec_swap13(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 13) + exec_swap_i(ref self, 13) } /// 0x9D - SWAP14 operation /// Exchange 1st and 15th stack items. /// # Specification: https://www.evm.codes/#9d?fork=shanghai fn exec_swap14(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 14) + exec_swap_i(ref self, 14) } /// 0x9E - SWAP15 operation /// Exchange 1st and 16th stack items. /// # Specification: https://www.evm.codes/#9e?fork=shanghai fn exec_swap15(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 15) + exec_swap_i(ref self, 15) } /// 0x9F - SWAP16 operation /// Exchange 1st and 16th stack items. /// # Specification: https://www.evm.codes/#9f?fork=shanghai fn exec_swap16(ref self: VM) -> Result<(), EVMError> { - internal::exec_swap_i(ref self, 16) + exec_swap_i(ref self, 16) } } #[cfg(test)] mod tests { - use core::array::ArrayTrait; use evm::instructions::exchange_operations::ExchangeOperationsTrait; use evm::stack::StackTrait; use evm::test_utils::VMBuilderTrait; diff --git a/crates/evm/src/instructions/logging_operations.cairo b/crates/evm/src/instructions/logging_operations.cairo index 89b8e21d0..86c0422a7 100644 --- a/crates/evm/src/instructions/logging_operations.cairo +++ b/crates/evm/src/instructions/logging_operations.cairo @@ -1,103 +1,95 @@ -use evm::errors::EVMError; //! Logging Operations. -// Internal imports +use evm::errors::{EVMError, ensure}; +use evm::gas; +use evm::memory::MemoryTrait; +use evm::model::Event; use evm::model::vm::{VM, VMTrait}; +use evm::stack::StackTrait; +use evm::state::StateTrait; + #[generate_trait] -impl LoggingOperations of LoggingOperationsTrait { +pub impl LoggingOperations of LoggingOperationsTrait { /// 0xA0 - LOG0 operation /// Append log record with no topic. /// # Specification: https://www.evm.codes/#a0?fork=shanghai fn exec_log0(ref self: VM) -> Result<(), EVMError> { - internal::exec_log_i(ref self, 0) + exec_log_i(ref self, 0) } /// 0xA1 - LOG1 /// Append log record with one topic. /// # Specification: https://www.evm.codes/#a1?fork=shanghai fn exec_log1(ref self: VM) -> Result<(), EVMError> { - internal::exec_log_i(ref self, 1) + exec_log_i(ref self, 1) } /// 0xA2 - LOG2 /// Append log record with two topics. /// # Specification: https://www.evm.codes/#a2?fork=shanghai fn exec_log2(ref self: VM) -> Result<(), EVMError> { - internal::exec_log_i(ref self, 2) + exec_log_i(ref self, 2) } /// 0xA3 - LOG3 /// Append log record with three topics. /// # Specification: https://www.evm.codes/#a3?fork=shanghai fn exec_log3(ref self: VM) -> Result<(), EVMError> { - internal::exec_log_i(ref self, 3) + exec_log_i(ref self, 3) } /// 0xA4 - LOG4 /// Append log record with four topics. /// # Specification: https://www.evm.codes/#a4?fork=shanghai fn exec_log4(ref self: VM) -> Result<(), EVMError> { - internal::exec_log_i(ref self, 4) + exec_log_i(ref self, 4) } } -mod internal { - use evm::errors::{EVMError, ensure}; - use evm::gas; - use evm::memory::MemoryTrait; - use evm::model::Event; - use evm::model::vm::{VM, VMTrait}; - use evm::stack::StackTrait; - use evm::state::StateTrait; - use utils::helpers::ceil32; - - - /// Store a new event in the dynamic context using topics - /// popped from the stack and data from the memory. - /// - /// # Arguments - /// - /// * `self` - The context to which the event will be added - /// * `topics_len` - The amount of topics to pop from the stack - fn exec_log_i(ref self: VM, topics_len: u8) -> Result<(), EVMError> { - // Revert if the transaction is in a read only context - ensure(!self.message().read_only, EVMError::WriteInStaticContext)?; - - // TODO(optimization): check benefits of n `pop` instead of `pop_n` - let offset = self.stack.pop_usize()?; - let size = self.stack.pop_usize()?; - let topics: Array = self.stack.pop_n(topics_len.into())?; - - let memory_expansion = gas::memory_expansion(self.memory.size(), [(offset, size)].span()); - self.memory.ensure_length(memory_expansion.new_size); - self - .charge_gas( - gas::LOG - + topics_len.into() * gas::LOGTOPIC - + size.into() * gas::LOGDATA - + memory_expansion.expansion_cost - )?; - - let mut data: Array = Default::default(); - self.memory.load_n(size, ref data, offset); - - let event: Event = Event { keys: topics, data }; - self.env.state.add_event(event); - - Result::Ok(()) - } + +/// Store a new event in the dynamic context using topics +/// popped from the stack and data from the memory. +/// +/// # Arguments +/// +/// * `self` - The context to which the event will be added +/// * `topics_len` - The amount of topics to pop from the stack +fn exec_log_i(ref self: VM, topics_len: u8) -> Result<(), EVMError> { + // Revert if the transaction is in a read only context + ensure(!self.message().read_only, EVMError::WriteInStaticContext)?; + + // TODO(optimization): check benefits of n `pop` instead of `pop_n` + let offset = self.stack.pop_usize()?; + let size = self.stack.pop_usize()?; + let topics: Array = self.stack.pop_n(topics_len.into())?; + + let memory_expansion = gas::memory_expansion(self.memory.size(), [(offset, size)].span()); + self.memory.ensure_length(memory_expansion.new_size); + self + .charge_gas( + gas::LOG + + topics_len.into() * gas::LOGTOPIC + + size.into() * gas::LOGDATA + + memory_expansion.expansion_cost + )?; + + let mut data: Array = Default::default(); + self.memory.load_n(size, ref data, offset); + + let event: Event = Event { keys: topics, data }; + self.env.state.add_event(event); + + Result::Ok(()) } #[cfg(test)] mod tests { use core::num::traits::Bounded; use core::result::ResultTrait; - use evm::errors::{EVMError, EVMErrorTrait, TYPE_CONVERSION_ERROR}; + use evm::errors::{EVMError, TYPE_CONVERSION_ERROR}; use evm::instructions::LoggingOperationsTrait; - use evm::memory::MemoryTrait; use evm::stack::StackTrait; - use evm::state::StateTrait; use evm::test_utils::{VMBuilderTrait, MemoryTestUtilsTrait}; use utils::helpers::u256_to_bytes_array; diff --git a/crates/evm/src/instructions/memory_operations.cairo b/crates/evm/src/instructions/memory_operations.cairo index 0212d578f..03aa1c0b3 100644 --- a/crates/evm/src/instructions/memory_operations.cairo +++ b/crates/evm/src/instructions/memory_operations.cairo @@ -1,18 +1,12 @@ use core::cmp::max; -use core::hash::{HashStateTrait, HashStateExTrait}; -use core::poseidon::PoseidonTrait; -use core::starknet::{storage_base_address_from_felt252, Store}; 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::errors::{EVMError, ensure}; 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, compute_storage_key}; -use utils::helpers::U256Trait; +use evm::state::StateTrait; use utils::set::SetTrait; #[inline(always)] @@ -26,7 +20,7 @@ fn jump(ref self: VM, index: usize) -> Result<(), EVMError> { } #[generate_trait] -impl MemoryOperation of MemoryOperationTrait { +pub impl MemoryOperation of MemoryOperationTrait { /// 0x50 - POP operation. /// Pops the first item on the stack (top of the stack). /// # Specification: https://www.evm.codes/#50?fork=shanghai @@ -309,28 +303,23 @@ impl MemoryOperation of MemoryOperationTrait { #[cfg(test)] mod tests { - use contracts::account_contract::{AccountContract}; use core::cmp::max; use core::num::traits::Bounded; use core::result::ResultTrait; - use core::starknet::get_contract_address; - use evm::backend::starknet_backend::fetch_original_storage; - use evm::backend::starknet_backend; - use evm::errors::{EVMError, INVALID_DESTINATION}; + use evm::errors::EVMError; use evm::gas; - use evm::instructions::{MemoryOperationTrait, EnvironmentInformationTrait}; - use evm::memory::{InternalMemoryTrait, MemoryTrait}; + use evm::instructions::MemoryOperationTrait; + use evm::memory::MemoryTrait; use evm::model::Address; - use evm::model::vm::{VM, VMTrait}; + use evm::model::vm::VMTrait; use evm::model::{Account, AccountTrait}; use evm::stack::StackTrait; - use evm::state::{StateTrait, compute_storage_address}; + use evm::state::StateTrait; use evm::test_utils::{ - evm_address, VMBuilderTrait, MemoryTestUtilsTrait, setup_test_storages, register_account, - uninitialized_account, native_token + VMBuilderTrait, MemoryTestUtilsTrait, setup_test_storages, uninitialized_account, + native_token }; - use snforge_std::{test_address, start_mock_call, store}; - use snforge_utils::snforge_utils::store_evm; + use snforge_std::{test_address, start_mock_call}; use utils::helpers::compute_starknet_address; #[test] diff --git a/crates/evm/src/instructions/push_operations.cairo b/crates/evm/src/instructions/push_operations.cairo index cebec83db..d7cf51a46 100644 --- a/crates/evm/src/instructions/push_operations.cairo +++ b/crates/evm/src/instructions/push_operations.cairo @@ -4,29 +4,22 @@ use evm::errors::EVMError; use evm::gas; use evm::model::vm::{VM, VMTrait}; use evm::stack::StackTrait; +use utils::helpers::load_word; -mod internal { - use evm::errors::EVMError; - use evm::gas; - use evm::model::vm::{VM, VMTrait}; - use evm::stack::StackTrait; - use utils::helpers::load_word; - - /// Place i bytes items on stack. - #[inline(always)] - fn exec_push_i(ref self: VM, i: u8) -> Result<(), EVMError> { - self.charge_gas(gas::VERYLOW)?; - let i = i.into(); - let data = self.read_code(i); +/// Place i bytes items on stack. +#[inline(always)] +fn exec_push_i(ref self: VM, i: u8) -> Result<(), EVMError> { + self.charge_gas(gas::VERYLOW)?; + let i = i.into(); + let data = self.read_code(i); - self.set_pc(self.pc() + i); + self.set_pc(self.pc() + i); - self.stack.push(load_word(i, data)) - } + self.stack.push(load_word(i, data)) } #[generate_trait] -impl PushOperations of PushOperationsTrait { +pub impl PushOperations of PushOperationsTrait { /// 5F - PUSH0 operation /// # Specification: https://www.evm.codes/#5f?fork=shanghai #[inline(always)] @@ -40,7 +33,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#60?fork=shanghai #[inline(always)] fn exec_push1(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 1) + exec_push_i(ref self, 1) } @@ -48,7 +41,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#61?fork=shanghai #[inline(always)] fn exec_push2(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 2) + exec_push_i(ref self, 2) } @@ -56,42 +49,42 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#62?fork=shanghai #[inline(always)] fn exec_push3(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 3) + exec_push_i(ref self, 3) } /// 0x63 - PUSH4 operation /// # Specification: https://www.evm.codes/#63?fork=shanghai #[inline(always)] fn exec_push4(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 4) + exec_push_i(ref self, 4) } /// 0x64 - PUSH5 operation /// # Specification: https://www.evm.codes/#64?fork=shanghai #[inline(always)] fn exec_push5(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 5) + exec_push_i(ref self, 5) } /// 0x65 - PUSH6 operation /// # Specification: https://www.evm.codes/#65?fork=shanghai #[inline(always)] fn exec_push6(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 6) + exec_push_i(ref self, 6) } /// 0x66 - PUSH7 operation /// # Specification: https://www.evm.codes/#66?fork=shanghai #[inline(always)] fn exec_push7(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 7) + exec_push_i(ref self, 7) } /// 0x67 - PUSH8 operation /// # Specification: https://www.evm.codes/#67?fork=shanghai #[inline(always)] fn exec_push8(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 8) + exec_push_i(ref self, 8) } @@ -99,28 +92,28 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#68?fork=shanghai #[inline(always)] fn exec_push9(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 9) + exec_push_i(ref self, 9) } /// 0x69 - PUSH10 operation /// # Specification: https://www.evm.codes/#69?fork=shanghai #[inline(always)] fn exec_push10(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 10) + exec_push_i(ref self, 10) } /// 0x6A - PUSH11 operation /// # Specification: https://www.evm.codes/#6a?fork=shanghai #[inline(always)] fn exec_push11(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 11) + exec_push_i(ref self, 11) } /// 0x6B - PUSH12 operation /// # Specification: https://www.evm.codes/#6b?fork=shanghai #[inline(always)] fn exec_push12(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 12) + exec_push_i(ref self, 12) } @@ -128,14 +121,14 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#6c?fork=shanghai #[inline(always)] fn exec_push13(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 13) + exec_push_i(ref self, 13) } /// 0x6D - PUSH14 operation /// # Specification: https://www.evm.codes/#6d?fork=shanghai #[inline(always)] fn exec_push14(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 14) + exec_push_i(ref self, 14) } @@ -143,28 +136,28 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#6e?fork=shanghai #[inline(always)] fn exec_push15(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 15) + exec_push_i(ref self, 15) } /// 0x6F - PUSH16 operation /// # Specification: https://www.evm.codes/#6f?fork=shanghai #[inline(always)] fn exec_push16(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 16) + exec_push_i(ref self, 16) } /// 0x70 - PUSH17 operation /// # Specification: https://www.evm.codes/#70?fork=shanghai #[inline(always)] fn exec_push17(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 17) + exec_push_i(ref self, 17) } /// 0x71 - PUSH18 operation /// # Specification: https://www.evm.codes/#71?fork=shanghai #[inline(always)] fn exec_push18(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 18) + exec_push_i(ref self, 18) } @@ -172,14 +165,14 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#72?fork=shanghai #[inline(always)] fn exec_push19(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 19) + exec_push_i(ref self, 19) } /// 0x73 - PUSH20 operation /// # Specification: https://www.evm.codes/#73?fork=shanghai #[inline(always)] fn exec_push20(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 20) + exec_push_i(ref self, 20) } @@ -187,7 +180,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#74?fork=shanghai #[inline(always)] fn exec_push21(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 21) + exec_push_i(ref self, 21) } @@ -195,7 +188,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#75?fork=shanghai #[inline(always)] fn exec_push22(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 22) + exec_push_i(ref self, 22) } @@ -203,7 +196,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#76?fork=shanghai #[inline(always)] fn exec_push23(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 23) + exec_push_i(ref self, 23) } @@ -211,7 +204,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#77?fork=shanghai #[inline(always)] fn exec_push24(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 24) + exec_push_i(ref self, 24) } @@ -219,7 +212,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#78?fork=shanghai #[inline(always)] fn exec_push25(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 25) + exec_push_i(ref self, 25) } @@ -227,7 +220,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#79?fork=shanghai #[inline(always)] fn exec_push26(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 26) + exec_push_i(ref self, 26) } @@ -235,14 +228,14 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#7a?fork=shanghai #[inline(always)] fn exec_push27(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 27) + exec_push_i(ref self, 27) } /// 0x7B - PUSH28 operation /// # Specification: https://www.evm.codes/#7b?fork=shanghai #[inline(always)] fn exec_push28(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 28) + exec_push_i(ref self, 28) } @@ -250,7 +243,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#7c?fork=shanghai #[inline(always)] fn exec_push29(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 29) + exec_push_i(ref self, 29) } @@ -258,7 +251,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#7d?fork=shanghai #[inline(always)] fn exec_push30(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 30) + exec_push_i(ref self, 30) } @@ -266,7 +259,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#7e?fork=shanghai #[inline(always)] fn exec_push31(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 31) + exec_push_i(ref self, 31) } @@ -274,7 +267,7 @@ impl PushOperations of PushOperationsTrait { /// # Specification: https://www.evm.codes/#7f?fork=shanghai #[inline(always)] fn exec_push32(ref self: VM) -> Result<(), EVMError> { - internal::exec_push_i(ref self, 32) + exec_push_i(ref self, 32) } } diff --git a/crates/evm/src/instructions/sha3.cairo b/crates/evm/src/instructions/sha3.cairo index e5b04c5da..eb730916e 100644 --- a/crates/evm/src/instructions/sha3.cairo +++ b/crates/evm/src/instructions/sha3.cairo @@ -1,16 +1,17 @@ -use core::keccak::{cairo_keccak, u128_split}; +use core::cmp::min; //! SHA3. +use core::keccak::{cairo_keccak}; +// Internal imports use evm::errors::EVMError; use evm::gas; -// Internal imports use evm::memory::MemoryTrait; use evm::model::vm::{VM, VMTrait}; use evm::stack::StackTrait; use utils::helpers::{ArrayExtTrait, U256Trait, ceil32}; #[generate_trait] -impl Sha3Impl of Sha3Trait { +pub impl Sha3Impl of Sha3Trait { /// SHA3 operation : Hashes n bytes in memory at a given offset in memory /// and push the hash result to the stack. /// @@ -31,10 +32,8 @@ impl Sha3Impl of Sha3Trait { let mut to_hash: Array = Default::default(); - let (nb_words, nb_zeroes) = internal::compute_memory_words_amount( - size, offset, self.memory.size() - ); - let mut last_input_offset = internal::fill_array_with_memory_words( + let (nb_words, nb_zeroes) = compute_memory_words_amount(size, offset, self.memory.size()); + let mut last_input_offset = fill_array_with_memory_words( ref self, ref to_hash, offset, nb_words ); // Fill array to hash with zeroes for bytes out of memory bound @@ -46,7 +45,7 @@ impl Sha3Impl of Sha3Trait { // it to to_hash. let last_input: u64 = if (size % 32 != 0) { let loaded = self.memory.load(last_input_offset); - internal::prepare_last_input(ref to_hash, loaded, size % 32) + prepare_last_input(ref to_hash, loaded, size % 32) } else { 0 }; @@ -58,106 +57,97 @@ impl Sha3Impl of Sha3Trait { } -mod internal { - use core::cmp::min; - use evm::memory::MemoryTrait; - use evm::model::vm::{VM, VMTrait}; - use evm::stack::StackTrait; - use utils::helpers::U256Trait; - - /// Computes how many words are read from the memory - /// and how many words must be filled with zeroes - /// given a target size, a memory offset and the length of the memory. - /// - /// # Arguments - /// - /// * `size` - The amount of bytes to hash - /// * `offset` - Offset in memory - /// * `mem_len` - Size of the memory - /// Returns : (nb_words, nb_zeroes) - fn compute_memory_words_amount(size: u32, offset: u32, mem_len: u32) -> (u32, u32) { - // Bytes to hash are less than a word size - if size < 32 { - return (0, 0); - } - // Bytes out of memory bound are zeroes - if offset > mem_len { - return (0, size / 32); - } - // The only word to read from memory is less than 32 bytes - if mem_len - offset < 32 { - return (1, (size / 32) - 1); - } - - let bytes_to_read = min(mem_len - offset, size); - let nb_words = bytes_to_read / 32; - (nb_words, (size / 32) - nb_words) +/// Computes how many words are read from the memory +/// and how many words must be filled with zeroes +/// given a target size, a memory offset and the length of the memory. +/// +/// # Arguments +/// +/// * `size` - The amount of bytes to hash +/// * `offset` - Offset in memory +/// * `mem_len` - Size of the memory +/// Returns : (nb_words, nb_zeroes) +fn compute_memory_words_amount(size: u32, offset: u32, mem_len: u32) -> (u32, u32) { + // Bytes to hash are less than a word size + if size < 32 { + return (0, 0); } - - /// Fills the `to_hash` array with little endian u64s - /// by splitting words read from the memory and - /// returns the next offset to read from. - /// - /// # Arguments - /// - /// * `self` - The context in which the memory is read - /// * `to_hash` - A reference to the array to fill - /// * `offset` - Offset in memory to start reading from - /// * `amount` - The amount of words to read from memory - /// Return the new offset - fn fill_array_with_memory_words( - ref self: VM, ref to_hash: Array, mut offset: u32, mut amount: u32 - ) -> u32 { - while amount != 0 { - let loaded = self.memory.load(offset); - let ((high_h, low_h), (high_l, low_l)) = loaded.split_into_u64_le(); - to_hash.append(low_h); - to_hash.append(high_h); - to_hash.append(low_l); - to_hash.append(high_l); - - offset += 32; - amount -= 1; - }; - offset + // Bytes out of memory bound are zeroes + if offset > mem_len { + return (0, size / 32); + } + // The only word to read from memory is less than 32 bytes + if mem_len - offset < 32 { + return (1, (size / 32) - 1); } - /// Fills the `to_hash` array with the n-1 remaining little endian u64 - /// depending on size from a word and returns - /// the u64 containing the last 8 bytes word to hash. - /// - /// # Arguments - /// - /// * `to_hash` - A reference to the array to fill - /// * `value` - The word to split in u64 words - /// * `size` - The amount of bytes still required to hash - /// Returns the last u64 word that isn't 8 Bytes long. - fn prepare_last_input(ref to_hash: Array, value: u256, size: u32) -> u64 { - let ((high_h, low_h), (high_l, low_l)) = value.split_into_u64_le(); - if size < 8 { - return low_h; - } else if size < 16 { - to_hash.append(low_h); - return high_h; - } else if size < 24 { - to_hash.append(low_h); - to_hash.append(high_h); - return low_l; - } else { - to_hash.append(low_h); - to_hash.append(high_h); - to_hash.append(low_l); - return high_l; - } + let bytes_to_read = min(mem_len - offset, size); + let nb_words = bytes_to_read / 32; + (nb_words, (size / 32) - nb_words) +} + +/// Fills the `to_hash` array with little endian u64s +/// by splitting words read from the memory and +/// returns the next offset to read from. +/// +/// # Arguments +/// +/// * `self` - The context in which the memory is read +/// * `to_hash` - A reference to the array to fill +/// * `offset` - Offset in memory to start reading from +/// * `amount` - The amount of words to read from memory +/// Return the new offset +fn fill_array_with_memory_words( + ref self: VM, ref to_hash: Array, mut offset: u32, mut amount: u32 +) -> u32 { + while amount != 0 { + let loaded = self.memory.load(offset); + let ((high_h, low_h), (high_l, low_l)) = loaded.split_into_u64_le(); + to_hash.append(low_h); + to_hash.append(high_h); + to_hash.append(low_l); + to_hash.append(high_l); + + offset += 32; + amount -= 1; + }; + offset +} + +/// Fills the `to_hash` array with the n-1 remaining little endian u64 +/// depending on size from a word and returns +/// the u64 containing the last 8 bytes word to hash. +/// +/// # Arguments +/// +/// * `to_hash` - A reference to the array to fill +/// * `value` - The word to split in u64 words +/// * `size` - The amount of bytes still required to hash +/// Returns the last u64 word that isn't 8 Bytes long. +fn prepare_last_input(ref to_hash: Array, value: u256, size: u32) -> u64 { + let ((high_h, low_h), (high_l, low_l)) = value.split_into_u64_le(); + if size < 8 { + return low_h; + } else if size < 16 { + to_hash.append(low_h); + return high_h; + } else if size < 24 { + to_hash.append(low_h); + to_hash.append(high_h); + return low_l; + } else { + to_hash.append(low_h); + to_hash.append(high_h); + to_hash.append(low_l); + return high_l; } } #[cfg(test)] mod tests { - use evm::errors::{EVMError, TYPE_CONVERSION_ERROR}; use evm::instructions::Sha3Trait; - use evm::instructions::sha3::internal; - use evm::memory::{InternalMemoryTrait, MemoryTrait}; + use evm::instructions::sha3; + use evm::memory::MemoryTrait; use evm::stack::StackTrait; use evm::test_utils::{VMBuilderTrait, MemoryTestUtilsTrait}; @@ -519,10 +509,8 @@ mod tests { let mut offset = 0; // When - let (words_from_mem, _) = internal::compute_memory_words_amount( - size, offset, vm.memory.size() - ); - internal::fill_array_with_memory_words(ref vm, ref to_hash, offset, words_from_mem); + let (words_from_mem, _) = sha3::compute_memory_words_amount(size, offset, vm.memory.size()); + sha3::fill_array_with_memory_words(ref vm, ref to_hash, offset, words_from_mem); // Then assert(to_hash.len() == 4, 'wrong array length'); @@ -547,10 +535,8 @@ mod tests { let mut offset = 0; // When - let (words_from_mem, _) = internal::compute_memory_words_amount( - size, offset, vm.memory.size() - ); - internal::fill_array_with_memory_words(ref vm, ref to_hash, offset, words_from_mem); + let (words_from_mem, _) = sha3::compute_memory_words_amount(size, offset, vm.memory.size()); + sha3::fill_array_with_memory_words(ref vm, ref to_hash, offset, words_from_mem); // Then assert(to_hash.len() == 4, 'wrong array length'); @@ -568,7 +554,7 @@ mod tests { let size = 5; // When - let result = internal::prepare_last_input(ref to_hash, value, size); + let result = sha3::prepare_last_input(ref to_hash, value, size); // Then assert(result == 0xE5000000FFFFFFFA, 'wrong result'); @@ -583,7 +569,7 @@ mod tests { let size = 20; // When - let result = internal::prepare_last_input(ref to_hash, value, size); + let result = sha3::prepare_last_input(ref to_hash, value, size); // Then assert(result == 0x00200400000000AD, 'wrong result'); @@ -600,7 +586,7 @@ mod tests { let size = 50; // When - let result = internal::prepare_last_input(ref to_hash, value, size); + let result = sha3::prepare_last_input(ref to_hash, value, size); // Then assert(result == 0x0000450000DEFA00, 'wrong result'); diff --git a/crates/evm/src/instructions/stop_and_arithmetic_operations.cairo b/crates/evm/src/instructions/stop_and_arithmetic_operations.cairo index a14d9fc17..c27227971 100644 --- a/crates/evm/src/instructions/stop_and_arithmetic_operations.cairo +++ b/crates/evm/src/instructions/stop_and_arithmetic_operations.cairo @@ -1,16 +1,16 @@ //! Stop and Arithmetic Operations. -use core::integer::{u512_safe_div_rem_by_u256, u256_try_as_non_zero}; +use core::integer::{u512_safe_div_rem_by_u256}; use core::num::traits::{OverflowingAdd, OverflowingMul, OverflowingSub}; use evm::errors::EVMError; use evm::gas; use evm::model::vm::{VM, VMTrait}; use evm::stack::StackTrait; -use utils::helpers::{U256Trait, BytesUsedTrait}; +use utils::helpers::BytesUsedTrait; use utils::i256::i256; use utils::math::{Exponentiation, WrappingExponentiation, u256_wide_add}; #[generate_trait] -impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait { +pub impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait { /// 0x00 - STOP /// Halts the execution of the current program. /// # Specification: https://www.evm.codes/#00?fork=shanghai @@ -72,7 +72,7 @@ impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait { let a: u256 = *popped[0]; let b: u256 = *popped[1]; - let result: u256 = match u256_try_as_non_zero(b) { + let result: u256 = match TryInto::>::try_into(b) { Option::Some(_) => { // Won't panic because b is not zero a / b @@ -112,7 +112,7 @@ impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait { let a: u256 = *popped[0]; let b: u256 = *popped[1]; - let result: u256 = match u256_try_as_non_zero(b) { + let result: u256 = match TryInto::>::try_into(b) { Option::Some(_) => { // Won't panic because b is not zero a % b @@ -157,7 +157,7 @@ impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait { let b: u256 = *popped[1]; let n = *popped[2]; - let result: u256 = match u256_try_as_non_zero(n) { + let result: u256 = match TryInto::>::try_into(n) { Option::Some(nonzero_n) => { // This is more gas efficient than computing (a mod N) + (b mod N) mod N let sum = u256_wide_add(a, b); @@ -181,7 +181,7 @@ impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait { let b: u256 = self.stack.pop()?; let n = self.stack.pop()?; - let result: u256 = match u256_try_as_non_zero(n) { + let result: u256 = match TryInto::>::try_into(n) { Option::Some(_) => { // (x * y) mod N <=> (x mod N) * (y mod N) mod N // It is more gas-efficient than to use u256_wide_mul @@ -262,7 +262,7 @@ mod tests { use core::num::traits::Bounded; use core::result::ResultTrait; use evm::instructions::StopAndArithmeticOperationsTrait; - use evm::model::vm::{VM, VMTrait}; + use evm::model::vm::VMTrait; use evm::stack::StackTrait; use evm::test_utils::VMBuilderTrait; diff --git a/crates/evm/src/instructions/system_operations.cairo b/crates/evm/src/instructions/system_operations.cairo index 2ab2d627f..42fa5156a 100644 --- a/crates/evm/src/instructions/system_operations.cairo +++ b/crates/evm/src/instructions/system_operations.cairo @@ -1,22 +1,17 @@ -use contracts::kakarot_core::{KakarotCore, IKakarotCore}; -//! System operations. - -use core::box::BoxTrait; -use evm::call_helpers::{CallHelpers, CallType}; +use evm::call_helpers::CallHelpers; use evm::create_helpers::{CreateHelpers, CreateType}; -use evm::errors::{ensure, EVMError, VALUE_TRANSFER_IN_STATIC_CALL}; +use evm::errors::{ensure, EVMError}; use evm::gas; use evm::memory::MemoryTrait; +use evm::model::Transfer; use evm::model::account::{AccountTrait}; use evm::model::vm::{VM, VMTrait}; -use evm::model::{Address, Transfer}; use evm::stack::StackTrait; use evm::state::StateTrait; -use utils::math::Exponentiation; use utils::set::SetTrait; #[generate_trait] -impl SystemOperations of SystemOperationsTrait { +pub impl SystemOperations of SystemOperationsTrait { /// CREATE /// # Specification: https://www.evm.codes/#f0?fork=shanghai fn exec_create(ref self: VM) -> Result<(), EVMError> { @@ -371,29 +366,23 @@ impl SystemOperations of SystemOperationsTrait { #[cfg(test)] mod tests { - use contracts::kakarot_core::interface::IExtendedKakarotCoreDispatcherTrait; use contracts::test_data::{storage_evm_bytecode, storage_evm_initcode}; use core::result::ResultTrait; use core::starknet::EthAddress; - use core::starknet::testing::set_contract_address; use core::traits::TryInto; - use evm::backend::starknet_backend; - use evm::call_helpers::{CallHelpers, CallHelpersImpl}; - use evm::errors::EVMErrorTrait; + use evm::call_helpers::CallHelpersImpl; use evm::instructions::MemoryOperationTrait; use evm::instructions::SystemOperationsTrait; use evm::interpreter::{EVMTrait}; - use evm::memory::MemoryTrait; use evm::model::account::{Account}; - use evm::model::vm::{VM, VMTrait}; - use evm::model::{AccountTrait, Address, Transfer}; + use evm::model::vm::VMTrait; + use evm::model::{AccountTrait, Address}; use evm::stack::StackTrait; - use evm::state::{StateTrait, State}; + use evm::state::{StateTrait}; use evm::test_utils::{ - VMBuilderTrait, MemoryTestUtilsTrait, native_token, evm_address, test_dual_address, - other_evm_address, setup_test_storages, register_account, origin, uninitialized_account + VMBuilderTrait, MemoryTestUtilsTrait, native_token, evm_address, setup_test_storages, + origin, uninitialized_account }; - use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; use snforge_std::{test_address, start_mock_call}; use utils::helpers::compute_starknet_address; use utils::helpers::load_word; diff --git a/crates/evm/src/interpreter.cairo b/crates/evm/src/interpreter.cairo index 1e517022e..e3225aa22 100644 --- a/crates/evm/src/interpreter.cairo +++ b/crates/evm/src/interpreter.cairo @@ -1,10 +1,8 @@ -use core::starknet::{EthAddress, ContractAddress}; use evm::create_helpers::CreateHelpers; -use evm::errors::{EVMError, ensure, PC_OUT_OF_BOUNDS, EVMErrorTrait, CONTRACT_ACCOUNT_EXISTS}; +use evm::errors::{EVMError, EVMErrorTrait, CONTRACT_ACCOUNT_EXISTS}; use evm::instructions::{ - duplication_operations, environmental_information, ExchangeOperationsTrait, logging_operations, - LoggingOperationsTrait, memory_operations, sha3, StopAndArithmeticOperationsTrait, + ExchangeOperationsTrait, LoggingOperationsTrait, StopAndArithmeticOperationsTrait, ComparisonAndBitwiseOperationsTrait, SystemOperationsTrait, BlockInformationTrait, DuplicationOperationsTrait, EnvironmentInformationTrait, PushOperationsTrait, MemoryOperationTrait @@ -13,17 +11,16 @@ use evm::instructions::{ use evm::model::account::{AccountTrait}; use evm::model::vm::{VM, VMTrait}; use evm::model::{ - Message, Environment, Address, Transfer, ExecutionSummary, ExecutionSummaryTrait, - ExecutionResult, ExecutionResultTrait, ExecutionResultStatus, AddressTrait + Message, Environment, Transfer, ExecutionSummary, ExecutionSummaryTrait, ExecutionResult, + ExecutionResultTrait, ExecutionResultStatus, AddressTrait }; use evm::precompiles::Precompiles; -use evm::stack::{Stack, StackTrait}; -use evm::state::{State, StateTrait}; +use evm::state::StateTrait; use utils::constants; -use utils::helpers::{U256Trait, compute_starknet_address, EthAddressExTrait}; +use utils::helpers::EthAddressExTrait; #[generate_trait] -impl EVMImpl of EVMTrait { +pub impl EVMImpl of EVMTrait { fn process_message_call( message: Message, mut env: Environment, is_deploy_tx: bool, ) -> ExecutionSummary { diff --git a/crates/evm/src/lib.cairo b/crates/evm/src/lib.cairo index 37856560f..dc80be6c3 100644 --- a/crates/evm/src/lib.cairo +++ b/crates/evm/src/lib.cairo @@ -1,4 +1,4 @@ -mod backend; +pub mod backend; // Call opcodes helpers mod call_helpers; @@ -6,13 +6,13 @@ mod call_helpers; mod create_helpers; // Errors module -mod errors; +pub mod errors; // Gas module -mod gas; +pub mod gas; // instructions module -mod instructions; +pub mod instructions; // interpreter module mod interpreter; @@ -21,7 +21,7 @@ mod interpreter; mod memory; // Data Models module -mod model; +pub mod model; // instructions module pub mod precompiles; @@ -30,10 +30,11 @@ pub mod precompiles; mod stack; // Local state -mod state; +pub mod state; #[cfg(target: 'test')] -mod test_data; +pub mod test_data; #[cfg(target: 'test')] -mod test_utils; +pub mod test_utils; +pub use interpreter::EVMTrait; diff --git a/crates/evm/src/memory.cairo b/crates/evm/src/memory.cairo index 230fbd877..836750f32 100644 --- a/crates/evm/src/memory.cairo +++ b/crates/evm/src/memory.cairo @@ -1,27 +1,23 @@ -use core::cmp::{max, min}; -use core::integer::{ - u32_safe_divmod, u32_as_non_zero, u128_safe_divmod, u128_as_non_zero, u256_as_non_zero -}; +use core::cmp::min; +use core::dict::{Felt252Dict, Felt252DictTrait}; +use core::integer::{u32_safe_divmod}; use utils::constants::{ POW_2_0, POW_2_8, POW_2_16, POW_2_24, POW_2_32, POW_2_40, POW_2_48, POW_2_56, POW_2_64, POW_2_72, POW_2_80, POW_2_88, POW_2_96, POW_2_104, POW_2_112, POW_2_120, POW_256_16 }; -use utils::{ - helpers, helpers::SpanExtTrait, helpers::ArrayExtTrait, math::Exponentiation, - math::WrappingExponentiation, math::Bitshift -}; +use utils::{helpers, helpers::ArrayExtTrait, math::Bitshift}; // 2**17 const MEMORY_SEGMENT_SIZE: usize = 131072; #[derive(Destruct, Default)] -struct Memory { +pub struct Memory { items: Felt252Dict, bytes_len: usize, } -trait MemoryTrait { +pub trait MemoryTrait { fn new() -> Memory; fn size(self: @Memory) -> usize; fn store(ref self: Memory, element: u256, offset: usize); @@ -56,8 +52,10 @@ impl MemoryImpl of MemoryTrait { /// index = Y + i * MEMORY_SEGMENT_SIZE #[inline(always)] fn store(ref self: Memory, element: u256, offset: usize) { + let nonzero_16: NonZero = 16_u32.try_into().unwrap(); + // Check alignment of offset to bytes16 chunks - let (chunk_index, offset_in_chunk) = u32_safe_divmod(offset, u32_as_non_zero(16)); + let (chunk_index, offset_in_chunk) = u32_safe_divmod(offset, nonzero_16); if offset_in_chunk == 0 { // Offset is aligned. This is the simplest and most efficient case, @@ -88,12 +86,14 @@ impl MemoryImpl of MemoryTrait { /// * `offset` - The offset within memory to store the byte at. #[inline(always)] fn store_byte(ref self: Memory, value: u8, offset: usize) { + let nonzero_16: NonZero = 16_u32.try_into().unwrap(); + // Compute actual offset in Memory, given active_segment of Memory (current Execution // Context id) // And Memory Segment Size // Get offset's memory word index and left-based offset of byte in word. - let (chunk_index, left_offset) = u32_safe_divmod(offset, u32_as_non_zero(16)); + let (chunk_index, left_offset) = u32_safe_divmod(offset, nonzero_16); // As the memory words are in big-endian order, we need to convert our left-based offset // to a right-based one.a @@ -130,13 +130,15 @@ impl MemoryImpl of MemoryTrait { return; } + let nonzero_16: NonZero = 16_u32.try_into().unwrap(); + // Compute the offset inside the Memory, given its active segment, following the formula: // index = offset + self.active_segment * 125000 // Check alignment of offset to bytes16 chunks. - let (initial_chunk, offset_in_chunk_i) = u32_safe_divmod(offset, u32_as_non_zero(16)); + let (initial_chunk, offset_in_chunk_i) = u32_safe_divmod(offset, nonzero_16); let (final_chunk, mut offset_in_chunk_f) = u32_safe_divmod( - offset + elements.len() - 1, u32_as_non_zero(16) + offset + elements.len() - 1, nonzero_16 ); offset_in_chunk_f += 1; let mask_i: u256 = helpers::pow256_rev(offset_in_chunk_i); @@ -233,7 +235,7 @@ impl MemoryImpl of MemoryTrait { } #[generate_trait] -impl InternalMemoryMethods of InternalMemoryTrait { +pub(crate) impl InternalMemoryMethods of InternalMemoryTrait { /// Stores a `u256` element at a specified offset within a memory chunk. /// /// It first computes the @@ -253,8 +255,9 @@ impl InternalMemoryMethods of InternalMemoryTrait { let mask_c: u256 = POW_256_16 / mask; // Split the 2 input bytes16 chunks at offset_in_chunk. - let (el_hh, el_hl) = DivRem::div_rem(element.high.into(), u256_as_non_zero(mask_c)); - let (el_lh, el_ll) = DivRem::div_rem(element.low.into(), u256_as_non_zero(mask_c)); + let nonzero_mask_c: NonZero = mask_c.try_into().unwrap(); + let (el_hh, el_hl) = DivRem::div_rem(element.high.into(), nonzero_mask_c); + let (el_lh, el_ll) = DivRem::div_rem(element.low.into(), nonzero_mask_c); // Read the words at chunk_index, chunk_index + 2. let w0: u128 = self.items.get(chunk_index.into()); @@ -294,8 +297,10 @@ impl InternalMemoryMethods of InternalMemoryTrait { ref self: Memory, initial_chunk: usize, mask_i: u256, mask_f: u256, elements: Span ) { let word: u128 = self.items.get(initial_chunk.into()); - let (word_high, word_low) = DivRem::div_rem(word.into(), u256_as_non_zero(mask_i)); - let (_, word_low_l) = DivRem::div_rem(word_low, u256_as_non_zero(mask_f)); + let nonzero_mask_i: NonZero = mask_i.try_into().unwrap(); + let nonzero_mask_f: NonZero = mask_f.try_into().unwrap(); + let (word_high, word_low) = DivRem::div_rem(word.into(), nonzero_mask_i); + let (_, word_low_l) = DivRem::div_rem(word_low, nonzero_mask_f); let bytes_as_word = helpers::load_word(elements.len(), elements); let new_w: u128 = (word_high * mask_i + bytes_as_word.into() * mask_f + word_low_l) .try_into() @@ -387,8 +392,8 @@ impl InternalMemoryMethods of InternalMemoryTrait { fn load_internal(ref self: Memory, offset: usize) -> u256 { // Compute the offset inside the dict, given its active segment, following the formula: // index = offset + self.active_segment * 125000 - - let (chunk_index, offset_in_chunk) = u32_safe_divmod(offset, u32_as_non_zero(16)); + let nonzero_16: NonZero = 16_u32.try_into().unwrap(); + let (chunk_index, offset_in_chunk) = u32_safe_divmod(offset, nonzero_16); if offset_in_chunk == 0 { // Offset is aligned. This is the simplest and most efficient case, @@ -414,7 +419,8 @@ impl InternalMemoryMethods of InternalMemoryTrait { // Compute element words let w0_l: u256 = w0.into() % mask; - let (w1_h, w1_l): (u256, u256) = DivRem::div_rem(w1.into(), u256_as_non_zero(mask)); + let nonzero_mask: NonZero = mask.try_into().unwrap(); + let (w1_h, w1_l): (u256, u256) = DivRem::div_rem(w1.into(), nonzero_mask); let w2_h: u256 = w2.into() / mask; let el_h: u128 = (w0_l * mask_c + w1_h).try_into().unwrap(); let el_l: u128 = (w1_l * mask_c + w2_h).try_into().unwrap(); @@ -442,13 +448,15 @@ impl InternalMemoryMethods of InternalMemoryTrait { return; } + let nonzero_16: NonZero = 16_u32.try_into().unwrap(); + // Compute the offset inside the Memory, given its active segment, following the formula: // index = offset + self.active_segment * 125000 // Check alignment of offset to bytes16 chunks. - let (initial_chunk, offset_in_chunk_i) = u32_safe_divmod(offset, u32_as_non_zero(16)); + let (initial_chunk, offset_in_chunk_i) = u32_safe_divmod(offset, nonzero_16); let (final_chunk, mut offset_in_chunk_f) = u32_safe_divmod( - offset + elements_len - 1, u32_as_non_zero(16) + offset + elements_len - 1, nonzero_16 ); offset_in_chunk_f += 1; let mask_i: u256 = helpers::pow256_rev(offset_in_chunk_i); @@ -616,46 +624,42 @@ mod tests { use utils::constants::{POW_2_8, POW_2_56, POW_2_64, POW_2_120}; use utils::{math::Exponentiation, math::WrappingExponentiation, helpers, helpers::SpanExtTrait}; - mod internal { - use evm::memory::{MemoryTrait, InternalMemoryTrait}; - use utils::{math::Exponentiation, helpers}; - fn load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( - offset: usize, low: u128, high: u128 - ) { - // Given - let mut memory = MemoryTrait::new(); + fn load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( + offset: usize, low: u128, high: u128 + ) { + // Given + let mut memory = MemoryTrait::new(); - let value: u256 = u256 { low: low, high: high }; + let value: u256 = u256 { low: low, high: high }; - let bytes_array = helpers::u256_to_bytes_array(value); + let bytes_array = helpers::u256_to_bytes_array(value); - memory.store_n(bytes_array.span(), offset); + memory.store_n(bytes_array.span(), offset); - // When - let mut elements: Array = Default::default(); - memory.load_n_internal(32, ref elements, offset); + // When + let mut elements: Array = Default::default(); + memory.load_n_internal(32, ref elements, offset); - // Then - assert(elements == bytes_array, 'result not matching expected'); - } + // Then + assert(elements == bytes_array, 'result not matching expected'); + } - fn load_should_load_an_element_from_the_memory_with_offset_stored_with_store( - offset: usize, low: u128, high: u128, active_segment: usize, - ) { - // Given - let mut memory = MemoryTrait::new(); + fn load_should_load_an_element_from_the_memory_with_offset_stored_with_store( + offset: usize, low: u128, high: u128, active_segment: usize, + ) { + // Given + let mut memory = MemoryTrait::new(); - let value: u256 = u256 { low: low, high: high }; + let value: u256 = u256 { low: low, high: high }; - memory.store(value, offset); + memory.store(value, offset); - // When - let result: u256 = memory.load_internal(offset); + // When + let result: u256 = memory.load_internal(offset); - // Then - assert(result == value, 'result not matching expected'); - } + // Then + assert(result == value, 'result not matching expected'); } @@ -840,41 +844,39 @@ mod tests { #[test] fn test_load_should_load_an_element_from_the_memory_with_offset_8() { - internal::load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( + load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( 8, 2 * POW_2_64, POW_2_64 ); } #[test] fn test_load_should_load_an_element_from_the_memory_with_offset_7() { - internal::load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( + load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( 7, 2 * POW_2_56, POW_2_56 ); } #[test] fn test_load_should_load_an_element_from_the_memory_with_offset_23() { - internal::load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( + load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( 23, 3 * POW_2_56, 2 * POW_2_56 ); } #[test] fn test_load_should_load_an_element_from_the_memory_with_offset_33() { - internal::load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( + load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( 33, 4 * POW_2_8, 3 * POW_2_8 ); } #[test] fn test_load_should_load_an_element_from_the_memory_with_offset_63() { - internal::load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( + load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( 63, 0, 4 * POW_2_120 ); } #[test] fn test_load_should_load_an_element_from_the_memory_with_offset_500() { - internal::load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n( - 500, 0, 0 - ); + load_should_load_an_element_from_the_memory_with_offset_stored_with_store_n(500, 0, 0); } diff --git a/crates/evm/src/model.cairo b/crates/evm/src/model.cairo index 2ecb83fc9..fc4aef8d6 100644 --- a/crates/evm/src/model.cairo +++ b/crates/evm/src/model.cairo @@ -1,70 +1,68 @@ -mod account; -mod vm; +pub mod account; +pub mod vm; +pub use account::{Account, AccountTrait}; +pub use vm::{VM, VMTrait}; use contracts::kakarot_core::{KakarotCore, IKakarotCore}; - -use core::num::traits::Zero; -use core::num::traits::{CheckedAdd, CheckedSub, CheckedMul}; -use core::starknet::{EthAddress, get_contract_address, ContractAddress}; -use evm::errors::{EVMError, CONTRACT_SYSCALL_FAILED}; -use evm::model::account::{Account, AccountTrait}; +use core::num::traits::{CheckedSub, Zero}; +use core::starknet::{EthAddress, ContractAddress}; +use evm::errors::EVMError; use evm::precompiles::{ FIRST_ROLLUP_PRECOMPILE_ADDRESS, FIRST_ETHEREUM_PRECOMPILE_ADDRESS, LAST_ETHEREUM_PRECOMPILE_ADDRESS }; use evm::state::State; use utils::fmt::{TSpanSetDebug}; -use utils::helpers::{ResultExTrait}; -use utils::set::{Set, SpanSet}; +use utils::set::SpanSet; use utils::traits::{EthAddressDefault, ContractAddressDefault, SpanDefault}; #[derive(Destruct, Default)] -struct Environment { - origin: EthAddress, - gas_price: u128, - chain_id: u128, - prevrandao: u256, - block_number: u64, - block_gas_limit: u128, - block_timestamp: u64, - coinbase: EthAddress, - base_fee: u128, - state: State +pub struct Environment { + pub origin: EthAddress, + pub gas_price: u128, + pub chain_id: u128, + pub prevrandao: u256, + pub block_number: u64, + pub block_gas_limit: u128, + pub block_timestamp: u64, + pub coinbase: EthAddress, + pub base_fee: u128, + pub state: State } #[derive(Copy, Drop, Default, PartialEq, Debug)] -struct Message { - caller: Address, - target: Address, - gas_limit: u128, - data: Span, - code: Span, - code_address: Address, - value: u256, - should_transfer_value: bool, - depth: usize, - read_only: bool, - accessed_addresses: SpanSet, - accessed_storage_keys: SpanSet<(EthAddress, u256)>, +pub struct Message { + pub caller: Address, + pub target: Address, + pub gas_limit: u128, + pub data: Span, + pub code: Span, + pub code_address: Address, + pub value: u256, + pub should_transfer_value: bool, + pub depth: usize, + pub read_only: bool, + pub accessed_addresses: SpanSet, + pub accessed_storage_keys: SpanSet<(EthAddress, u256)>, } #[derive(Drop, Debug)] -struct ExecutionResult { - status: ExecutionResultStatus, - return_data: Span, - gas_left: u128, - accessed_addresses: SpanSet, - accessed_storage_keys: SpanSet<(EthAddress, u256)>, - gas_refund: u128, +pub struct ExecutionResult { + pub status: ExecutionResultStatus, + pub return_data: Span, + pub gas_left: u128, + pub accessed_addresses: SpanSet, + pub accessed_storage_keys: SpanSet<(EthAddress, u256)>, + pub gas_refund: u128, } #[derive(Copy, Drop, PartialEq, Debug)] -enum ExecutionResultStatus { +pub enum ExecutionResultStatus { Success, Revert, Exception, } #[generate_trait] -impl ExecutionResultImpl of ExecutionResultTrait { +pub impl ExecutionResultImpl of ExecutionResultTrait { fn exceptional_failure( error: Span, accessed_addresses: SpanSet, @@ -102,16 +100,16 @@ impl ExecutionResultImpl of ExecutionResultTrait { } #[derive(Destruct)] -struct ExecutionSummary { - status: ExecutionResultStatus, - return_data: Span, - gas_left: u128, - state: State, - gas_refund: u128 +pub struct ExecutionSummary { + pub status: ExecutionResultStatus, + pub return_data: Span, + pub gas_left: u128, + pub state: State, + pub gas_refund: u128 } #[generate_trait] -impl ExecutionSummaryImpl of ExecutionSummaryTrait { +pub impl ExecutionSummaryImpl of ExecutionSummaryTrait { fn exceptional_failure(error: Span) -> ExecutionSummary { ExecutionSummary { status: ExecutionResultStatus::Exception, @@ -135,15 +133,15 @@ impl ExecutionSummaryImpl of ExecutionSummaryTrait { } } -struct TransactionResult { - success: bool, - return_data: Span, - gas_used: u128, - state: State +pub struct TransactionResult { + pub success: bool, + pub return_data: Span, + pub gas_used: u128, + pub state: State } #[generate_trait] -impl TransactionResultImpl of TransactionResultTrait { +pub impl TransactionResultImpl of TransactionResultTrait { fn exceptional_failure(error: Span, gas_used: u128) -> TransactionResult { TransactionResult { success: false, return_data: error, gas_used, state: Default::default() @@ -153,17 +151,18 @@ impl TransactionResultImpl of TransactionResultTrait { /// The struct representing an EVM event. #[derive(Drop, Clone, Default, PartialEq)] -struct Event { - keys: Array, - data: Array, +pub struct Event { + pub keys: Array, + pub data: Array, } #[derive(Copy, Drop, PartialEq, Default, Debug)] -struct Address { - evm: EthAddress, - starknet: ContractAddress, +pub struct Address { + pub evm: EthAddress, + pub starknet: ContractAddress, } + impl ZeroAddress of core::num::traits::Zero
{ fn zero() -> Address { Address { evm: Zero::zero(), starknet: Zero::zero(), } @@ -177,7 +176,7 @@ impl ZeroAddress of core::num::traits::Zero
{ } #[generate_trait] -impl AddressImpl of AddressTrait { +pub impl AddressImpl of AddressTrait { fn is_deployed(self: @EthAddress) -> bool { let mut kakarot_state = KakarotCore::unsafe_new_contract_state(); let address = kakarot_state.address_registry(*self); @@ -197,29 +196,18 @@ impl AddressImpl of AddressTrait { /// A struct to save native token transfers to be made when finalizing /// a tx #[derive(Copy, Drop, PartialEq, Debug)] -struct Transfer { - sender: Address, - recipient: Address, - amount: u256 +pub struct Transfer { + pub sender: Address, + pub recipient: Address, + pub amount: u256 } #[cfg(test)] mod tests { - use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; - use contracts::kakarot_core::interface::IExtendedKakarotCoreDispatcherTrait; - use core::starknet::EthAddress; - use evm::backend::starknet_backend; - use evm::model::account::AccountTrait; - - use evm::state::StateTrait; - use evm::state::{State, StateChangeLog, StateChangeLogTrait}; - use evm::test_utils; - use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait; - mod test_is_deployed { - use evm::model::{Address, Account, AddressTrait}; + use evm::model::AddressTrait; use evm::test_utils; - use snforge_std::{test_address, start_mock_call}; + use snforge_std::test_address; use utils::helpers::compute_starknet_address; diff --git a/crates/evm/src/model/account.cairo b/crates/evm/src/model/account.cairo index 1f39eddb1..62226cd68 100644 --- a/crates/evm/src/model/account.cairo +++ b/crates/evm/src/model/account.cairo @@ -1,19 +1,10 @@ -use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait, IAccount}; -use contracts::kakarot_core::kakarot::KakarotCore::KakarotCoreInternal; +use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; use contracts::kakarot_core::{KakarotCore, IKakarotCore}; +use core::dict::{Felt252Dict, Felt252DictTrait}; use core::num::traits::Zero; -use core::starknet::{ - ContractAddress, EthAddress, get_contract_address, deploy_syscall, get_tx_info, - SyscallResultTrait -}; -use core::traits::TryInto; +use core::starknet::{ContractAddress, EthAddress}; use evm::backend::starknet_backend::fetch_balance; -use evm::errors::{EVMError, CONTRACT_SYSCALL_FAILED}; -use evm::model::{Address, AddressTrait, Transfer}; -use evm::state::State; -use evm::state::StateTrait; -use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; -use utils::helpers::{ResultExTrait, ByteArrayExTrait, compute_starknet_address}; +use evm::model::Address; #[derive(Drop)] struct AccountBuilder { @@ -68,17 +59,17 @@ impl AccountBuilderImpl of AccountBuilderTrait { } #[derive(Copy, Drop, PartialEq, Debug)] -struct Account { - address: Address, - code: Span, - nonce: u64, - balance: u256, - selfdestruct: bool, - is_created: bool, +pub struct Account { + pub address: Address, + pub code: Span, + pub nonce: u64, + pub balance: u256, + pub selfdestruct: bool, + pub is_created: bool, } #[generate_trait] -impl AccountImpl of AccountTrait { +pub impl AccountImpl of AccountTrait { /// Fetches an account from Starknet /// An non-deployed account is just an empty account. /// # Arguments @@ -249,7 +240,7 @@ impl AccountImpl of AccountTrait { } #[generate_trait] -impl AccountInternals of AccountInternalTrait { +pub(crate) impl AccountInternals of AccountInternalTrait { #[inline(always)] fn set_balance(ref self: Account, value: u256) { self.balance = value; @@ -259,7 +250,6 @@ impl AccountInternals of AccountInternalTrait { #[cfg(test)] mod tests { mod test_has_code_or_nonce { - use core::starknet::{ContractAddress, EthAddress}; use evm::model::account::{Account, AccountTrait, Address}; #[test] @@ -310,7 +300,7 @@ mod tests { register_account, setup_test_storages, uninitialized_account, evm_address, native_token, }; use snforge_std::{test_address, start_mock_call}; - use snforge_utils::snforge_utils::{assert_called, assert_called_with}; + use snforge_utils::snforge_utils::assert_called; use utils::helpers::compute_starknet_address; #[test] @@ -350,7 +340,7 @@ mod tests { fn test_should_return_none_if_not_registered() { // Given setup_test_storages(); - let starknet_address = compute_starknet_address( + let _starknet_address = compute_starknet_address( test_address(), evm_address(), uninitialized_account() ); @@ -364,7 +354,7 @@ mod tests { register_account, setup_test_storages, uninitialized_account, evm_address, native_token, }; use snforge_std::{test_address, start_mock_call}; - use snforge_utils::snforge_utils::{assert_called, assert_called_with}; + use snforge_utils::snforge_utils::assert_called; use utils::helpers::compute_starknet_address; #[test] diff --git a/crates/evm/src/model/vm.cairo b/crates/evm/src/model/vm.cairo index 4142899bc..993218eb4 100644 --- a/crates/evm/src/model/vm.cairo +++ b/crates/evm/src/model/vm.cairo @@ -1,33 +1,33 @@ +use core::dict::{Felt252Dict, Felt252DictTrait}; use core::num::traits::CheckedSub; use core::starknet::EthAddress; -use evm::errors::{EVMError, ensure}; -use evm::memory::{Memory, MemoryTrait}; -use evm::model::{Message, Environment, ExecutionResult, ExecutionResultStatus, AccountTrait}; -use evm::stack::{Stack, StackTrait}; -use utils::helpers::{SpanExtTrait, ArrayExtTrait}; -use utils::set::{Set, SetTrait, SpanSet}; +use evm::errors::EVMError; +use evm::memory::Memory; +use evm::model::{Message, Environment, ExecutionResultStatus, ExecutionResult, AccountTrait}; +use evm::stack::Stack; +use utils::set::{Set, SetTrait, SpanSet, SpanSetTrait}; use utils::traits::{SpanDefault}; #[derive(Default, Destruct)] -struct VM { - stack: Stack, - memory: Memory, - pc: usize, - valid_jumpdests: Felt252Dict, - return_data: Span, - env: Environment, - message: Message, - gas_left: u128, - running: bool, - error: bool, - accessed_addresses: Set, - accessed_storage_keys: Set<(EthAddress, u256)>, - gas_refund: u128 +pub struct VM { + pub stack: Stack, + pub memory: Memory, + pub pc: usize, + pub valid_jumpdests: Felt252Dict, + pub return_data: Span, + pub env: Environment, + pub message: Message, + pub gas_left: u128, + pub running: bool, + pub error: bool, + pub accessed_addresses: Set, + pub accessed_storage_keys: Set<(EthAddress, u256)>, + pub gas_refund: u128 } #[generate_trait] -impl VMImpl of VMTrait { +pub impl VMImpl of VMTrait { #[inline(always)] fn new(message: Message, env: Environment) -> VM { VM { @@ -41,8 +41,8 @@ impl VMImpl of VMTrait { gas_left: message.gas_limit, running: true, error: false, - accessed_addresses: message.accessed_addresses.inner.clone(), - accessed_storage_keys: message.accessed_storage_keys.inner.clone(), + accessed_addresses: message.accessed_addresses.clone_set(), + accessed_storage_keys: message.accessed_storage_keys.clone_set(), gas_refund: 0 } } @@ -162,13 +162,10 @@ impl VMImpl of VMTrait { #[cfg(test)] mod tests { - use evm::errors::DebugEVMError; - use evm::errors::{EVMError, READ_SYSCALL_FAILED}; - use evm::model::vm::{VM, VMTrait}; - use evm::model::{Message, Environment}; - use evm::test_utils::{ - tx_gas_limit, evm_address, starknet_address, VMBuilderTrait, test_address, gas_price - }; + use evm::errors::EVMError; + use evm::model::Message; + use evm::model::vm::VMTrait; + use evm::test_utils::{tx_gas_limit, VMBuilderTrait}; #[test] fn test_vm_default() { @@ -260,11 +257,11 @@ mod tests { let mut vm = VMTrait::new(message, Default::default()); - assert!(vm.is_valid_jump(0x3) == true, "expected jump to be valid"); - assert!(vm.is_valid_jump(0x9) == true, "expected jump to be valid"); + assert!(vm.is_valid_jump(0x3), "expected jump to be valid"); + assert!(vm.is_valid_jump(0x9), "expected jump to be valid"); - assert!(vm.is_valid_jump(0x4) == false, "expected jump to be invalid"); - assert!(vm.is_valid_jump(0x5) == false, "expected jump to be invalid"); + assert!(!vm.is_valid_jump(0x4), "expected jump to be invalid"); + assert!(!vm.is_valid_jump(0x5), "expected jump to be invalid"); } #[test] @@ -273,6 +270,6 @@ mod tests { message.code = [0x60, 0x5B, 0x60, 0x00].span(); let mut vm = VMTrait::new(message, Default::default()); - assert!(vm.is_valid_jump(0x1) == false, "expected false"); + assert!(!vm.is_valid_jump(0x1), "expected false"); } } diff --git a/crates/evm/src/precompiles.cairo b/crates/evm/src/precompiles.cairo index de389953e..0bc7e9eee 100644 --- a/crates/evm/src/precompiles.cairo +++ b/crates/evm/src/precompiles.cairo @@ -1,26 +1,35 @@ mod blake2f; + mod ec_add; + mod ec_mul; + mod ec_recover; + mod identity; + mod modexp; + mod p256verify; + mod sha256; + +pub use blake2f::Blake2f; +pub use ec_add::EcAdd; +pub use ec_mul::EcMul; +pub use ec_recover::EcRecover; +pub use identity::Identity; +pub use modexp::ModExp; +pub use p256verify::P256Verify; +pub use sha256::Sha256; + use core::starknet::EthAddress; use core::traits::Into; use evm::errors::EVMError; use evm::model::vm::VM; use evm::model::vm::VMTrait; -use evm::precompiles::blake2f::Blake2f; -use evm::precompiles::ec_add::EcAdd; -use evm::precompiles::ec_mul::EcMul; -use evm::precompiles::ec_recover::EcRecover; -use evm::precompiles::identity::Identity; -use evm::precompiles::modexp::ModExp; -use evm::precompiles::p256verify::P256Verify; -use evm::precompiles::sha256::Sha256; -use utils::set::{Set}; +use utils::set::{Set, SetTrait}; pub const FIRST_ETHEREUM_PRECOMPILE_ADDRESS: u256 = 0x01; @@ -35,25 +44,25 @@ pub fn eth_precompile_addresses() -> Set { precompile_addresses.append(i.try_into().unwrap()); i = i + 1; }; - Set { inner: precompile_addresses } + SetTrait::from_array(precompile_addresses) } -trait Precompile { +pub trait Precompile { fn address() -> EthAddress; fn exec(input: Span) -> Result<(u128, Span), EVMError>; } #[generate_trait] -impl PrecompilesImpl of Precompiles { +pub impl PrecompilesImpl of Precompiles { fn exec_precompile(ref vm: VM) -> Result<(), EVMError> { let precompile_address = vm.message.code_address.evm; let input = vm.message().data; - let (gas, result) = if precompile_address.address == 0x100 { + let (gas, result) = if precompile_address.into() == 0x100 { P256Verify::exec(input)? } else { - match precompile_address.address { + match precompile_address.into() { 0x00 => { // we should never reach this branch! panic!("pre-compile address can't be 0") @@ -62,10 +71,7 @@ impl PrecompilesImpl of Precompiles { 0x02 => { Sha256::exec(input)? }, 0x03 => { // we should never reach this branch! - panic!( - "pre-compile at address {} isn't implemented yet", - precompile_address.address - ) + panic!("pre-compile at address {:?} isn't implemented yet", precompile_address) }, 0x04 => { Identity::exec(input)? }, 0x05 => { ModExp::exec(input)? }, @@ -73,22 +79,16 @@ impl PrecompilesImpl of Precompiles { 0x07 => { EcMul::exec(input)? }, 0x08 => { // we should never reach this branch! - panic!( - "pre-compile at address {} isn't implemented yet", - precompile_address.address - ) + panic!("pre-compile at address {:?} isn't implemented yet", precompile_address) }, 0x09 => { Blake2f::exec(input)? }, 0x0a => { // Point Evaluation - panic!( - "pre-compile at address {} isn't implemented yet", - precompile_address.address - ) + panic!("pre-compile at address {:?} isn't implemented yet", precompile_address) }, _ => { // we should never reach this branch! - panic!("address {} isn't a pre-compile", precompile_address.address) + panic!("address {:?} isn't a pre-compile", precompile_address) } } }; @@ -104,12 +104,13 @@ impl PrecompilesImpl of Precompiles { #[cfg(test)] mod tests { use super::eth_precompile_addresses; + use utils::set::SetTrait; #[test] fn test_eth_precompile_addresses() { let addresses = eth_precompile_addresses(); assert_eq!( - addresses.inner.span(), + addresses.to_span(), [ 0x01.try_into().unwrap(), 0x02.try_into().unwrap(), diff --git a/crates/evm/src/precompiles/blake2f.cairo b/crates/evm/src/precompiles/blake2f.cairo index 1056579ce..0f49a26fb 100644 --- a/crates/evm/src/precompiles/blake2f.cairo +++ b/crates/evm/src/precompiles/blake2f.cairo @@ -3,7 +3,6 @@ use core::option::OptionTrait; use core::starknet::EthAddress; use evm::errors::{EVMError, ensure}; -use evm::model::vm::{VM, VMTrait}; use evm::precompiles::Precompile; use utils::crypto::blake2_compress::compress; use utils::helpers::{FromBytes, ToBytes}; @@ -11,10 +10,10 @@ use utils::helpers::{FromBytes, ToBytes}; const GF_ROUND: u64 = 1; const INPUT_LENGTH: usize = 213; -impl Blake2f of Precompile { +pub impl Blake2f of Precompile { #[inline(always)] fn address() -> EthAddress { - EthAddress { address: 0x9 } + 0x9.try_into().unwrap() } fn exec(input: Span) -> Result<(u128, Span), EVMError> { @@ -84,12 +83,9 @@ impl Blake2f of Precompile { #[cfg(test)] mod tests { use core::array::SpanTrait; - use core::starknet::testing::set_contract_address; use evm::errors::EVMError; - use evm::instructions::memory_operations::MemoryOperationTrait; - use evm::instructions::system_operations::SystemOperationsTrait; - use evm::interpreter::EVMTrait; - use evm::memory::InternalMemoryTrait; + use evm::instructions::MemoryOperationTrait; + use evm::instructions::SystemOperationsTrait; use evm::memory::MemoryTrait; use evm::precompiles::blake2f::Blake2f; use evm::stack::StackTrait; @@ -99,10 +95,8 @@ mod tests { blake2_precompile_fail_wrong_length_input_3_test_case, blake2_precompile_pass_1_test_case, blake2_precompile_pass_0_test_case, blake2_precompile_pass_2_test_case }; - use evm::test_utils::{ - VMBuilderTrait, native_token, other_starknet_address, setup_test_storages - }; - use snforge_std::{start_mock_call, test_address}; + use evm::test_utils::{VMBuilderTrait, native_token, setup_test_storages}; + use snforge_std::start_mock_call; use utils::helpers::FromBytes; #[test] diff --git a/crates/evm/src/precompiles/ec_add.cairo b/crates/evm/src/precompiles/ec_add.cairo index a8ef25764..1e4f54b8a 100644 --- a/crates/evm/src/precompiles/ec_add.cairo +++ b/crates/evm/src/precompiles/ec_add.cairo @@ -1,32 +1,27 @@ -use core::RangeCheck; use core::circuit::CircuitElement as CE; use core::circuit::CircuitInput as CI; use core::circuit::{ - RangeCheck96, AddMod, MulMod, u384, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub, - circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, CircuitOutputsTrait, - CircuitModulus, AddInputResultTrait, CircuitInputs, CircuitInputAccumulator + u384, CircuitElement, CircuitInput, circuit_add, circuit_sub, circuit_mul, circuit_inverse, + EvalCircuitTrait, CircuitOutputsTrait, CircuitModulus, CircuitInputs }; use core::num::traits::Zero; - - use core::option::Option; -use core::starknet::SyscallResultTrait; use core::starknet::{EthAddress}; -use evm::errors::{EVMError}; +use evm::errors::EVMError; use evm::precompiles::Precompile; use garaga::core::circuit::AddInputResultTrait2; -use utils::helpers::{U256Trait, ToBytes, FromBytes}; -use utils::helpers::{load_word, u256_to_bytes_array}; +use utils::helpers::ToBytes; +use utils::helpers::load_word; const BASE_COST: u128 = 150; const U256_BYTES_LEN: usize = 32; -impl EcAdd of Precompile { +pub impl EcAdd of Precompile { #[inline(always)] fn address() -> EthAddress { - EthAddress { address: 0x6 } + 0x6.try_into().unwrap() } fn exec(mut input: Span) -> Result<(u128, Span), EVMError> { @@ -123,7 +118,7 @@ fn ec_add(x1: u256, y1: u256, x2: u256, y2: u256) -> Option<(u256, u256)> { // assumes that the points are on the curve and not the point at infinity. // Returns None if the points are the same and opposite y coordinates (Point at infinity) -fn ec_safe_add(x1: u384, y1: u384, x2: u384, y2: u384) -> Option<(u384, u384)> { +pub fn ec_safe_add(x1: u384, y1: u384, x2: u384, y2: u384) -> Option<(u384, u384)> { let same_x = eq_mod_p(x1, x2); if same_x { @@ -144,7 +139,7 @@ fn ec_safe_add(x1: u384, y1: u384, x2: u384, y2: u384) -> Option<(u384, u384)> { // Check if a point is on the curve. // Point at infinity (0,0) will return false. -fn is_on_curve(x: u384, y: u384) -> bool { +pub fn is_on_curve(x: u384, y: u384) -> bool { let (b, _x, _y) = (CE::> {}, CE::> {}, CE::> {}); // Compute (y^2 - (x^2 + b)) % p_bn254 @@ -207,7 +202,7 @@ fn add_ec_point_unchecked(xP: u384, yP: u384, xQ: u384, yQ: u384) -> (u384, u384 } // Double BN254 EC point without checking if the point is on the curve -fn double_ec_point_unchecked(x: u384, y: u384) -> (u384, u384) { +pub fn double_ec_point_unchecked(x: u384, y: u384) -> (u384, u384) { // CONSTANT stack let in0 = CE::> {}; // 0x3 // INPUT stack @@ -270,91 +265,3 @@ fn eq_neg_mod_p(a: u384, b: u384) -> bool { return outputs.get_output(check).is_zero(); } -#[cfg(test)] -mod tests { - use super::{ - eq_mod_p, eq_neg_mod_p, double_ec_point_unchecked, add_ec_point_unchecked, is_on_curve, u384 - }; - use utils::helpers::{U256Trait, ToBytes, FromBytes}; - - #[test] - fn test_u384_to_u256() { - let x = u384 { limb0: 0x1, limb1: 0x0, limb2: 0x0, limb3: 0x0 }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x1, high: 0x0 }); - let x = u384 { limb0: 0x0, limb1: 0x0, limb2: 0x0, limb3: 0x0 }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x0, high: 0x0 }); - let x = u384 { limb0: 0xc77661, limb1: 0x0, limb2: 0x0, limb3: 0x0 }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0xc77661, high: 0x0 }); - let x = u384 { limb0: 0xa1f1ae97, limb1: 0x0, limb2: 0x0, limb3: 0x0 }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0xa1f1ae97, high: 0x0 }); - - let x = u384 { limb0: 0x6dbd0f5925f2ea8792be851d, limb1: 0x60, limb2: 0x0, limb3: 0x0 }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x606dbd0f5925f2ea8792be851d, high: 0x0 }); - - let x = u384 { limb0: 0x288ad273930c8e07bee0b040, limb1: 0x9a80, limb2: 0x0, limb3: 0x0 }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x9a80288ad273930c8e07bee0b040, high: 0x0 }); - - let x = u384 { - limb0: 0x79f59cab560d347406f8f978, limb1: 0x32355e68, limb2: 0x0, limb3: 0x0 - }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x32355e6879f59cab560d347406f8f978, high: 0x0 }); - - let x = u384 { - limb0: 0xf7c12fd7cd43a2091356f287, limb1: 0x5670d3784d, limb2: 0x0, limb3: 0x0 - }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x70d3784df7c12fd7cd43a2091356f287, high: 0x56 }); - - let x = u384 { - limb0: 0x4def54e61b4eee26c407edc8, limb1: 0x6a3d1d0cac6d, limb2: 0x0, limb3: 0x0 - }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x1d0cac6d4def54e61b4eee26c407edc8, high: 0x6a3d }); - - let x = u384 { - limb0: 0xa666c4bd0b0f6ac7bfc6697, - limb1: 0x55354b07685a19836f45e3, - limb2: 0x0, - limb3: 0x0 - }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x836f45e30a666c4bd0b0f6ac7bfc6697, high: 0x55354b07685a19 }); - - let x = u384 { - limb0: 0xf99e6e4a89d4c4bf4eeb5764, - limb1: 0xba69422bccfb0bf07a497f6b, - limb2: 0x0, - limb3: 0x0 - }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0x7a497f6bf99e6e4a89d4c4bf4eeb5764, high: 0xba69422bccfb0bf0 }); - - let x = u384 { - limb0: 0xa18fd325c835625f53342a9f, - limb1: 0x3f862f6ff3d3c356f4262ef4, - limb2: 0xda, - limb3: 0x0 - }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!(y, u256 { low: 0xf4262ef4a18fd325c835625f53342a9f, high: 0xda3f862f6ff3d3c356 }); - - let x = u384 { - limb0: 0x4332f4d7188cef59cbdef8db, - limb1: 0xbb3e59509bf71bec4abd71f1, - limb2: 0x4bb761b32d048, - limb3: 0x0 - }; - let y = TryInto::::try_into(x).unwrap(); - assert_eq!( - y, - u256 { low: 0x4abd71f14332f4d7188cef59cbdef8db, high: 0x4bb761b32d048bb3e59509bf71bec } - ); - } -} diff --git a/crates/evm/src/precompiles/ec_mul.cairo b/crates/evm/src/precompiles/ec_mul.cairo index b77825fde..37807f203 100644 --- a/crates/evm/src/precompiles/ec_mul.cairo +++ b/crates/evm/src/precompiles/ec_mul.cairo @@ -1,33 +1,20 @@ -use core::circuit::CircuitElement as CE; -use core::circuit::CircuitInput as CI; - -use core::circuit::{ - RangeCheck96, AddMod, MulMod, u384, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub, - circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, CircuitOutputsTrait, - CircuitModulus, AddInputResultTrait, CircuitInputs, CircuitInputAccumulator -}; +use core::circuit::u384; use core::option::Option; -use core::starknet::SyscallResultTrait; use core::starknet::{EthAddress}; -use evm::errors::{EVMError}; +use evm::errors::EVMError; use evm::precompiles::Precompile; -use evm::precompiles::ec_add::{ - is_on_curve, eq_mod_p, eq_neg_mod_p, double_ec_point_unchecked, add_ec_point_unchecked, - ec_safe_add, -}; -use garaga::core::circuit::AddInputResultTrait2; -use garaga::utils::u384_eq_zero; -use utils::helpers::{load_word, u256_to_bytes_array, U256Trait, ToBytes, FromBytes}; +use evm::precompiles::ec_add::{is_on_curve, double_ec_point_unchecked, ec_safe_add}; +use utils::helpers::{load_word, ToBytes}; // const BN254_ORDER: u256 = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001; const BASE_COST: u128 = 6000; const U256_BYTES_LEN: usize = 32; -impl EcMul of Precompile { +pub impl EcMul of Precompile { fn address() -> EthAddress { - EthAddress { address: 0x7 } + 0x7.try_into().unwrap() } fn exec(mut input: Span) -> Result<(u128, Span), EVMError> { diff --git a/crates/evm/src/precompiles/ec_recover.cairo b/crates/evm/src/precompiles/ec_recover.cairo index 1336de202..75e5ebeee 100644 --- a/crates/evm/src/precompiles/ec_recover.cairo +++ b/crates/evm/src/precompiles/ec_recover.cairo @@ -1,24 +1,20 @@ +use core::starknet::secp256_trait::{recover_public_key, Signature}; use core::starknet::{ - EthAddress, eth_signature::{recover_public_key, public_key_point_to_eth_address, Signature}, - secp256k1::{Secp256k1Point} + EthAddress, eth_signature::{public_key_point_to_eth_address}, secp256k1::{Secp256k1Point} }; use core::traits::Into; -use evm::errors::{EVMError, TYPE_CONVERSION_ERROR}; -use evm::model::vm::VM; -use evm::model::vm::VMTrait; +use evm::errors::EVMError; use evm::precompiles::Precompile; -use evm::stack::StackTrait; -use utils::helpers::EthAddressExTrait; -use utils::helpers::U8SpanExTrait; -use utils::helpers::{U256Trait, BoolIntoNumeric, ToBytes, FromBytes}; +use utils::helpers::{ToBytes, FromBytes}; +use utils::traits::BoolIntoNumeric; use utils::traits::EthAddressIntoU256; const EC_RECOVER_PRECOMPILE_GAS_COST: u128 = 3000; -impl EcRecover of Precompile { +pub impl EcRecover of Precompile { #[inline(always)] fn address() -> EthAddress { - EthAddress { address: 0x1 } + 0x1.try_into().unwrap() } fn exec(input: Span) -> Result<(u128, Span), EVMError> { @@ -73,18 +69,15 @@ impl EcRecover of Precompile { #[cfg(test)] mod tests { use core::array::ArrayTrait; - use evm::instructions::system_operations::SystemOperationsTrait; - use evm::memory::InternalMemoryTrait; + use evm::instructions::SystemOperationsTrait; use evm::memory::MemoryTrait; use evm::precompiles::ec_recover::EcRecover; use evm::stack::StackTrait; use evm::test_utils::setup_test_storages; - use evm::test_utils::{ - VMBuilderTrait, MemoryTestUtilsTrait, native_token, other_starknet_address - }; - use snforge_std::{start_mock_call, test_address}; - use utils::helpers::{U256Trait, ToBytes, FromBytes}; + use evm::test_utils::{VMBuilderTrait, MemoryTestUtilsTrait, native_token}; + use snforge_std::start_mock_call; + use utils::helpers::{ToBytes, FromBytes}; // source: diff --git a/crates/evm/src/precompiles/identity.cairo b/crates/evm/src/precompiles/identity.cairo index 9e478f013..932a7a3ad 100644 --- a/crates/evm/src/precompiles/identity.cairo +++ b/crates/evm/src/precompiles/identity.cairo @@ -1,16 +1,14 @@ use core::starknet::EthAddress; use evm::errors::EVMError; -use evm::model::vm::VM; -use evm::model::vm::VMTrait; use evm::precompiles::Precompile; const BASE_COST: u128 = 15; const COST_PER_WORD: u128 = 3; -impl Identity of Precompile { +pub impl Identity of Precompile { #[inline(always)] fn address() -> EthAddress { - EthAddress { address: 0x4 } + 0x4.try_into().unwrap() } fn exec(input: Span) -> Result<(u128, Span), EVMError> { @@ -23,19 +21,14 @@ impl Identity of Precompile { #[cfg(test)] mod tests { - use core::clone::Clone; use core::result::ResultTrait; - use core::starknet::testing::set_contract_address; - use evm::instructions::system_operations::SystemOperationsTrait; + use evm::instructions::SystemOperationsTrait; use evm::memory::MemoryTrait; use evm::precompiles::identity::Identity; use evm::stack::StackTrait; - use evm::test_utils::{ - VMBuilderTrait, MemoryTestUtilsTrait, native_token, other_starknet_address, - setup_test_storages - }; - use snforge_std::{start_mock_call, test_address}; + use evm::test_utils::{VMBuilderTrait, MemoryTestUtilsTrait, native_token, setup_test_storages}; + use snforge_std::start_mock_call; // source: // diff --git a/crates/evm/src/precompiles/modexp.cairo b/crates/evm/src/precompiles/modexp.cairo index d95eb5fa3..0997e432a 100644 --- a/crates/evm/src/precompiles/modexp.cairo +++ b/crates/evm/src/precompiles/modexp.cairo @@ -10,20 +10,18 @@ use core::starknet::EthAddress; use core::traits::TryInto; use evm::errors::EVMError; -use evm::model::vm::VM; -use evm::model::vm::VMTrait; use evm::precompiles::Precompile; use utils::crypto::modexp::lib::modexp; -use utils::helpers::{U256Trait, U8SpanExTrait, U64Trait, FromBytes, BitsUsed}; +use utils::helpers::{U8SpanExTrait, FromBytes, BitsUsed}; const HEADER_LENGTH: usize = 96; const MIN_GAS: u128 = 200; -impl ModExp of Precompile { +pub impl ModExp of Precompile { #[inline(always)] fn address() -> EthAddress { - EthAddress { address: 0x5 } + 0x5.try_into().unwrap() } fn exec(input: Span) -> Result<(u128, Span), EVMError> { @@ -158,7 +156,7 @@ mod tests { use core::starknet::EthAddress; use core::starknet::testing::set_contract_address; - use evm::instructions::system_operations::SystemOperationsTrait; + use evm::instructions::SystemOperationsTrait; use evm::memory::MemoryTrait; use evm::precompiles::Precompiles; diff --git a/crates/evm/src/precompiles/p256verify.cairo b/crates/evm/src/precompiles/p256verify.cairo index 829e459f5..6f0e06e17 100644 --- a/crates/evm/src/precompiles/p256verify.cairo +++ b/crates/evm/src/precompiles/p256verify.cairo @@ -1,11 +1,9 @@ use core::starknet::SyscallResultTrait; -use core::starknet::{ - EthAddress, eth_signature::{recover_public_key, public_key_point_to_eth_address, Signature}, - secp256r1::{Secp256r1Point, secp256r1_new_syscall}, secp256_trait::is_valid_signature -}; +use core::starknet::secp256_trait::{Secp256Trait}; +use core::starknet::{EthAddress, secp256r1::{Secp256r1Point}, secp256_trait::is_valid_signature}; use evm::errors::{EVMError}; use evm::precompiles::Precompile; -use utils::helpers::{U256Trait, ToBytes, FromBytes}; +use utils::helpers::FromBytes; const P256VERIFY_PRECOMPILE_GAS_COST: u128 = 3450; @@ -46,10 +44,10 @@ const ONE_32_BYTES: [ 0x01 ]; -impl P256Verify of Precompile { +pub impl P256Verify of Precompile { #[inline(always)] fn address() -> EthAddress { - EthAddress { address: 0x100 } + 0x100.try_into().unwrap() } fn exec(input: Span) -> Result<(u128, Span), EVMError> { @@ -89,7 +87,8 @@ impl P256Verify of Precompile { Option::None => { return Result::Ok((gas, [].span())); } }; - let public_key: Option = secp256r1_new_syscall(x, y).unwrap_syscall(); + let public_key: Option = Secp256Trait::secp256_ec_new_syscall(x, y) + .unwrap_syscall(); let public_key = match public_key { Option::Some(public_key) => public_key, Option::None => { return Result::Ok((gas, [].span())); } @@ -106,16 +105,15 @@ impl P256Verify of Precompile { #[cfg(test)] mod tests { use core::array::ArrayTrait; - use evm::instructions::system_operations::SystemOperationsTrait; - use evm::memory::InternalMemoryTrait; + use evm::instructions::SystemOperationsTrait; use evm::memory::MemoryTrait; use evm::precompiles::p256verify::P256Verify; use evm::stack::StackTrait; use evm::test_utils::{VMBuilderTrait}; use evm::test_utils::{setup_test_storages, native_token}; - use snforge_std::{start_mock_call, test_address}; - use utils::helpers::{U256Trait, ToBytes, FromBytes}; + use snforge_std::start_mock_call; + use utils::helpers::{ToBytes, FromBytes}; // source: diff --git a/crates/evm/src/precompiles/sha256.cairo b/crates/evm/src/precompiles/sha256.cairo index 489fc9a15..7737f3c71 100644 --- a/crates/evm/src/precompiles/sha256.cairo +++ b/crates/evm/src/precompiles/sha256.cairo @@ -1,21 +1,17 @@ -use core::circuit::CircuitInputs; -use core::iter::IntoIterator; use core::sha256::compute_sha256_u32_array; use core::starknet::EthAddress; use evm::errors::EVMError; -use evm::model::vm::VM; -use evm::model::vm::VMTrait; use evm::precompiles::Precompile; -use utils::helpers::Bitshift; use utils::helpers::{FromBytes, ToBytes}; +use utils::math::Bitshift; const BASE_COST: u128 = 60; const COST_PER_WORD: u128 = 12; -impl Sha256 of Precompile { +pub impl Sha256 of Precompile { #[inline(always)] fn address() -> EthAddress { - EthAddress { address: 0x2 } + 0x2.try_into().unwrap() } fn exec(mut input: Span) -> Result<(u128, Span), EVMError> { @@ -55,16 +51,12 @@ impl Sha256 of Precompile { #[cfg(test)] mod tests { use core::result::ResultTrait; - use core::starknet::testing::set_contract_address; - use evm::instructions::system_operations::SystemOperationsTrait; + use evm::instructions::SystemOperationsTrait; use evm::memory::MemoryTrait; use evm::precompiles::sha256::Sha256; use evm::stack::StackTrait; - use evm::test_utils::{ - VMBuilderTrait, MemoryTestUtilsTrait, native_token, other_starknet_address, - setup_test_storages - }; + use evm::test_utils::{VMBuilderTrait, MemoryTestUtilsTrait, native_token, setup_test_storages}; use snforge_std::{start_mock_call}; use utils::helpers::ToBytes; use utils::helpers::{FromBytes}; diff --git a/crates/evm/src/stack.cairo b/crates/evm/src/stack.cairo index 8483f0d7e..dbcfc8b67 100644 --- a/crates/evm/src/stack.cairo +++ b/crates/evm/src/stack.cairo @@ -1,7 +1,4 @@ -use core::fmt::{Debug, Formatter, Error, Display}; -use core::nullable::{NullableTrait}; -use core::num::traits::Bounded; -use core::starknet::{StorageBaseAddress, EthAddress}; +use core::dict::{Felt252Dict, Felt252DictTrait}; //! Stack implementation. //! # Example //! ``` @@ -17,7 +14,10 @@ use core::starknet::{StorageBaseAddress, EthAddress}; //! let value = stack.pop()?; //! ``` -use evm::errors::{ensure, EVMError, TYPE_CONVERSION_ERROR}; +use core::nullable::{NullableTrait}; +use core::num::traits::Bounded; +use core::starknet::EthAddress; +use evm::errors::{ensure, EVMError}; use utils::constants; use utils::i256::i256; @@ -26,12 +26,12 @@ use utils::traits::{TryIntoResult}; //TODO(optimization): make len `felt252` based to avoid un-necessary checks #[derive(Destruct, Default)] -struct Stack { - items: Felt252Dict>, - len: usize, +pub struct Stack { + pub items: Felt252Dict>, + pub len: usize, } -trait StackTrait { +pub trait StackTrait { fn new() -> Stack; fn push(ref self: Stack, item: u256) -> Result<(), EVMError>; fn pop(ref self: Stack) -> Result; @@ -340,8 +340,7 @@ mod tests { mod pop { use core::num::traits::Bounded; - use core::starknet::storage_base_address_const; - use evm::errors::{EVMError, TYPE_CONVERSION_ERROR}; + use evm::errors::EVMError; use super::StackTrait; use utils::traits::StorageBaseAddressPartialEq; diff --git a/crates/evm/src/state.cairo b/crates/evm/src/state.cairo index f8dda1633..1e2e15321 100644 --- a/crates/evm/src/state.cairo +++ b/crates/evm/src/state.cairo @@ -1,20 +1,15 @@ -use contracts::kakarot_core::{IKakarotCore, KakarotCore}; +use core::dict::{Felt252Dict, Felt252DictTrait}; use core::hash::{HashStateTrait, HashStateExTrait}; use core::nullable::{match_nullable, FromNullableResult}; -use core::num::traits::{OverflowingAdd, OverflowingSub, OverflowingMul}; +use core::num::traits::{OverflowingAdd, OverflowingSub}; use core::poseidon::PoseidonTrait; -use core::starknet::SyscallResultTrait; -use core::starknet::{ - Store, StorageBaseAddress, storage_base_address_from_felt252, ContractAddress, EthAddress, - emit_event_syscall -}; +use core::starknet::storage_access::{StorageBaseAddress, storage_base_address_from_felt252}; +use core::starknet::{EthAddress}; use evm::backend::starknet_backend::fetch_original_storage; -use evm::errors::{ensure, EVMError, WRITE_SYSCALL_FAILED, READ_SYSCALL_FAILED, BALANCE_OVERFLOW}; +use evm::errors::{ensure, EVMError, BALANCE_OVERFLOW}; use evm::model::account::{AccountTrait, AccountInternalTrait}; -use evm::model::{Event, Transfer, Account, Address, AddressTrait}; -use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait}; -use utils::helpers::{ArrayExtTrait, ResultExTrait}; +use evm::model::{Event, Transfer, Account}; use utils::set::{Set, SetTrait}; /// The `StateChangeLog` tracks the changes applied to storage during the execution of a @@ -32,9 +27,9 @@ use utils::set::{Set, SetTrait}; /// * `changes` - A `Felt252Dict` of contextual changes. Tracks the changes applied inside a single /// execution context. /// * `keyset` - An `Array` of contextual keys. -struct StateChangeLog { - changes: Felt252Dict>, - keyset: Set, +pub struct StateChangeLog { + pub changes: Felt252Dict>, + pub keyset: Set, } impl StateChangeLogDestruct> of Destruct> { @@ -99,28 +94,28 @@ impl StateChangeLogImpl, +Copy> of StateChangeLogTrait { } #[derive(Default, Destruct)] -struct State { +pub struct State { /// Accounts states - without storage and balances, which are handled separately. - accounts: StateChangeLog, + pub accounts: StateChangeLog, /// Account storage states. `EthAddress` indicates the target contract, /// `u256` indicates the storage key. /// `u256` indicates the value stored. /// We have to store the target contract, as we can't derive it from the /// hashed address only when finalizing. - accounts_storage: StateChangeLog<(EthAddress, u256, u256)>, + pub accounts_storage: StateChangeLog<(EthAddress, u256, u256)>, /// Account states /// Pending emitted events - events: Array, + pub events: Array, /// Pending transfers - transfers: Array, + pub transfers: Array, /// Account transient storage states. `EthAddress` indicates the target contract, /// `u256` indicates the storage key. /// `u256` indicates the value stored. - transient_account_storage: StateChangeLog<(EthAddress, u256, u256)>, + pub transient_account_storage: StateChangeLog<(EthAddress, u256, u256)>, } #[generate_trait] -impl StateImpl of StateTrait { +pub impl StateImpl of StateTrait { fn get_account(ref self: State, evm_address: EthAddress) -> Account { let maybe_account = self.accounts.read(evm_address.into()); match maybe_account { @@ -225,7 +220,7 @@ impl StateImpl of StateTrait { /// The key is computed as follows: /// 1. Compute the hash of the EVM address and the key(low, high) using Poseidon. /// 2. Return the hash -fn compute_storage_key(evm_address: EthAddress, key: u256) -> felt252 { +pub fn compute_storage_key(evm_address: EthAddress, key: u256) -> felt252 { let hash = PoseidonTrait::new().update_with(evm_address).update_with(key).finalize(); hash } @@ -237,7 +232,7 @@ fn compute_storage_key(evm_address: EthAddress, key: u256) -> felt252 { /// Note: the storage_base_address_from_felt252 function always works for any felt - and returns the /// number normalized into the range [0, 2^251 - 256). (x % (2^251 - 256)) /// https://github.com/starkware-libs/cairo/issues/4187 -fn compute_storage_address(key: u256) -> StorageBaseAddress { +pub fn compute_storage_address(key: u256) -> StorageBaseAddress { let hash = PoseidonTrait::new().update_with(key).finalize(); storage_base_address_from_felt252(hash) } @@ -279,7 +274,7 @@ mod tests { mod test_state_changelog { use evm::state::{StateChangeLog, StateChangeLogTrait}; use evm::test_utils; - use utils::set::{Set, SetTrait}; + use utils::set::SetTrait; #[test] fn test_read_empty_log() { @@ -312,19 +307,13 @@ mod tests { mod test_state { use core::starknet::EthAddress; - use evm::model::account::{Account, AccountTrait, AccountInternalTrait}; + use evm::model::account::{Account, AccountTrait}; use evm::model::{Event, Transfer, Address}; use evm::state::{State, StateTrait}; use evm::test_utils; - use openzeppelin::token::erc20::interface::{ - IERC20CamelDispatcher, IERC20CamelDispatcherTrait - }; - use snforge_std::{ - declare, DeclareResultTrait, start_cheat_caller_address, test_address, start_mock_call, - stop_mock_call - }; + use snforge_std::{test_address, start_mock_call}; use utils::helpers::compute_starknet_address; - use utils::set::{Set, SetTrait}; + use utils::set::SetTrait; #[test] fn test_get_account_when_inexistant() { diff --git a/crates/evm/src/test_data.cairo b/crates/evm/src/test_data.cairo index 4c967af57..dff05e57a 100644 --- a/crates/evm/src/test_data.cairo +++ b/crates/evm/src/test_data.cairo @@ -1,2 +1,2 @@ -mod test_data_blake2f; -mod test_data_modexp; +pub mod test_data_blake2f; +pub mod test_data_modexp; diff --git a/crates/evm/src/test_data/test_data_blake2f.cairo b/crates/evm/src/test_data/test_data_blake2f.cairo index b1d5c2158..2edd31c01 100644 --- a/crates/evm/src/test_data/test_data_blake2f.cairo +++ b/crates/evm/src/test_data/test_data_blake2f.cairo @@ -1,5 +1,5 @@ // source: [EIP-152](https://eips.ethereum.org/EIPS/eip-152), Test Vector 1 -fn blake2_precompile_fail_wrong_length_input_1_test_case() -> (Span, Span) { +pub fn blake2_precompile_fail_wrong_length_input_1_test_case() -> (Span, Span) { let input = [ 0, 0, @@ -221,7 +221,7 @@ fn blake2_precompile_fail_wrong_length_input_1_test_case() -> (Span, Span (Span, Span) { +pub fn blake2_precompile_fail_wrong_length_input_2_test_case() -> (Span, Span) { let input = [ 0, 0, @@ -445,7 +445,7 @@ fn blake2_precompile_fail_wrong_length_input_2_test_case() -> (Span, Span (Span, Span) { +pub fn blake2_precompile_fail_wrong_length_input_3_test_case() -> (Span, Span) { let input = [ 0, 0, @@ -668,7 +668,7 @@ fn blake2_precompile_fail_wrong_length_input_3_test_case() -> (Span, Span (Span, Span) { +pub fn blake2_precompile_pass_0_test_case() -> (Span, Span) { let input = [ 0, 0, @@ -957,7 +957,7 @@ fn blake2_precompile_pass_0_test_case() -> (Span, Span) { // source: [EIP-152](https://eips.ethereum.org/EIPS/eip-152), Test Vector 5 -fn blake2_precompile_pass_1_test_case() -> (Span, Span) { +pub fn blake2_precompile_pass_1_test_case() -> (Span, Span) { let input = [ 0, 0, @@ -1245,7 +1245,7 @@ fn blake2_precompile_pass_1_test_case() -> (Span, Span) { } // source: [EIP-152](https://eips.ethereum.org/EIPS/eip-152), Test Vector 6 -fn blake2_precompile_pass_2_test_case() -> (Span, Span) { +pub fn blake2_precompile_pass_2_test_case() -> (Span, Span) { let input = [ 0, 0, diff --git a/crates/evm/src/test_utils.cairo b/crates/evm/src/test_utils.cairo index f64eccd4f..ec5477bd6 100644 --- a/crates/evm/src/test_utils.cairo +++ b/crates/evm/src/test_utils.cairo @@ -1,40 +1,27 @@ -use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait}; use contracts::kakarot_core::KakarotCore; -use contracts::kakarot_core::interface::{ - IExtendedKakarotCoreDispatcher, IExtendedKakarotCoreDispatcherTrait -}; -use contracts::test_utils::{deploy_contract_account, deploy_native_token}; -use contracts::uninitialized_account::UninitializedAccount; -use core::nullable::{match_nullable, FromNullableResult}; use core::ops::DerefMut; -use core::ops::SnapshotDeref; -use core::starknet::storage::{StorageMapWriteAccess, StoragePathEntry}; -use core::starknet::{ - StorageBaseAddress, storage_base_address_from_felt252, contract_address_try_from_felt252, - ContractAddress, EthAddress, deploy_syscall, get_contract_address, contract_address_const, - ClassHash, class_hash_const -}; +use core::starknet::storage::{StoragePointerWriteAccess, StoragePathEntry}; +use core::starknet::storage_access::{StorageBaseAddress, storage_base_address_from_felt252}; +use core::starknet::{ContractAddress, EthAddress, contract_address_const, ClassHash}; use core::traits::TryInto; -use evm::errors::{EVMError}; +use evm::memory::{Memory, MemoryTrait}; use evm::model::vm::{VM, VMTrait}; -use evm::model::{Message, Environment, Address, Account, AccountTrait}; -use evm::state::State; -use evm::{stack::{Stack, StackTrait}, memory::{Memory, MemoryTrait}}; -use snforge_std::{declare, DeclareResultTrait, ContractClassTrait, store, test_address}; +use evm::model::{Message, Environment, Address, AccountTrait}; +use snforge_std::test_address; use starknet::storage::StorageTraitMut; use utils::constants; -fn uninitialized_account() -> ClassHash { - class_hash_const::<'uninitialized_account'>() +pub fn uninitialized_account() -> ClassHash { + 'uninitialized_account'.try_into().unwrap() } -fn account_contract() -> ClassHash { - class_hash_const::<'account_contract'>() +pub fn account_contract() -> ClassHash { + 'account_contract'.try_into().unwrap() } -fn setup_test_storages() { +pub fn setup_test_storages() { let mut kakarot_core = KakarotCore::contract_state_for_testing(); let mut kakarot_storage = kakarot_core.deref_mut().storage_mut(); kakarot_storage.Kakarot_account_contract_class_hash.write(account_contract()); @@ -42,7 +29,7 @@ fn setup_test_storages() { kakarot_storage.Kakarot_native_token_address.write(native_token()); } -fn register_account(evm_address: EthAddress, starknet_address: ContractAddress) { +pub fn register_account(evm_address: EthAddress, starknet_address: ContractAddress) { let mut kakarot_core = KakarotCore::contract_state_for_testing(); let mut kakarot_storage = kakarot_core.deref_mut().storage_mut(); kakarot_storage.Kakarot_evm_to_starknet_address.entry(evm_address).write(starknet_address); @@ -50,7 +37,7 @@ fn register_account(evm_address: EthAddress, starknet_address: ContractAddress) #[generate_trait] -impl MemoryUtilsImpl of MemoryTestUtilsTrait { +pub impl MemoryUtilsImpl of MemoryTestUtilsTrait { fn store_with_expansion(ref self: Memory, element: u256, offset: usize) { self.ensure_length(offset + 32); self.store(element, offset); @@ -68,7 +55,7 @@ struct VMBuilder { } #[generate_trait] -impl VMBuilderImpl of VMBuilderTrait { +pub impl VMBuilderImpl of VMBuilderTrait { fn new() -> VMBuilder { VMBuilder { vm: Default::default() }.with_gas_limit(0x100000000000000000000) } @@ -107,7 +94,7 @@ impl VMBuilderImpl of VMBuilderTrait { self } - // fn with_nested_vm(mut self: VMBuilder) -> VMBuilder { + // pub fn with_nested_vm(mut self: VMBuilder) -> VMBuilder { // let current_ctx = self.machine.current_ctx.unbox(); // // Second Execution Context @@ -138,93 +125,93 @@ impl VMBuilderImpl of VMBuilderTrait { } } -fn origin() -> EthAddress { +pub fn origin() -> EthAddress { 'origin'.try_into().unwrap() } -fn caller() -> EthAddress { +pub fn caller() -> EthAddress { 'caller'.try_into().unwrap() } -fn coinbase() -> EthAddress { +pub fn coinbase() -> EthAddress { 'coinbase'.try_into().unwrap() } -fn starknet_address() -> ContractAddress { +pub fn starknet_address() -> ContractAddress { contract_address_const::<'starknet_address'>() } -fn evm_address() -> EthAddress { +pub fn evm_address() -> EthAddress { 'evm_address'.try_into().unwrap() } -fn test_dual_address() -> Address { +pub fn test_dual_address() -> Address { Address { evm: evm_address(), starknet: starknet_address() } } -fn other_evm_address() -> EthAddress { +pub fn other_evm_address() -> EthAddress { 'other_evm_address'.try_into().unwrap() } -fn other_starknet_address() -> ContractAddress { +pub fn other_starknet_address() -> ContractAddress { contract_address_const::<'other_starknet_address'>() } -fn other_address() -> Address { +pub fn other_address() -> Address { Address { evm: other_evm_address(), starknet: other_starknet_address() } } -fn storage_base_address() -> StorageBaseAddress { +pub fn storage_base_address() -> StorageBaseAddress { storage_base_address_from_felt252('storage_base_address') } -fn zero_address() -> ContractAddress { +pub fn zero_address() -> ContractAddress { contract_address_const::<0x00>() } -fn callvalue() -> u256 { +pub fn callvalue() -> u256 { 123456789 } -fn native_token() -> ContractAddress { +pub fn native_token() -> ContractAddress { contract_address_const::<'native_token'>() } -fn chain_id() -> u128 { +pub fn chain_id() -> u128 { 'KKRT'.try_into().unwrap() } -fn kakarot_address() -> ContractAddress { +pub fn kakarot_address() -> ContractAddress { contract_address_const::<'kakarot'>() } -fn sequencer_evm_address() -> EthAddress { +pub fn sequencer_evm_address() -> EthAddress { 'sequencer'.try_into().unwrap() } -fn eoa_address() -> EthAddress { +pub fn eoa_address() -> EthAddress { let evm_address: EthAddress = 0xe0a.try_into().unwrap(); evm_address } -fn tx_gas_limit() -> u128 { +pub fn tx_gas_limit() -> u128 { 15000000000 } -fn gas_price() -> u128 { +pub fn gas_price() -> u128 { 32 } -fn value() -> u256 { +pub fn value() -> u256 { 0xffffffffffffffffffffffffffffffff } -fn ca_address() -> EthAddress { +pub fn ca_address() -> EthAddress { let evm_address: EthAddress = 0xca.try_into().unwrap(); evm_address } -fn preset_message() -> Message { +pub fn preset_message() -> Message { let code: Span = [0x00].span(); let data: Span = [4, 5, 6].span(); let value: u256 = callvalue(); @@ -260,7 +247,7 @@ fn preset_message() -> Message { } } -fn preset_environment() -> Environment { +pub fn preset_environment() -> Environment { let block_info = starknet::get_block_info().unbox(); Environment { origin: origin(), @@ -276,7 +263,7 @@ fn preset_environment() -> Environment { } } -fn preset_vm() -> VM { +pub fn preset_vm() -> VM { let message = preset_message(); let environment = preset_environment(); let return_data = [1, 2, 3].span(); diff --git a/crates/snforge_utils/Scarb.toml b/crates/snforge_utils/Scarb.toml index 1c0d12acc..0a90d0ae6 100644 --- a/crates/snforge_utils/Scarb.toml +++ b/crates/snforge_utils/Scarb.toml @@ -1,7 +1,7 @@ [package] name = "snforge_utils" version = "0.1.0" -edition = "2023_11" +edition = "2024_07" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html diff --git a/crates/snforge_utils/src/lib.cairo b/crates/snforge_utils/src/lib.cairo index c3aa04e76..38ca7e5df 100644 --- a/crates/snforge_utils/src/lib.cairo +++ b/crates/snforge_utils/src/lib.cairo @@ -4,19 +4,15 @@ mod contracts; pub mod snforge_utils { use core::array::ArrayTrait; use core::option::OptionTrait; - use starknet::testing::cheatcode; use evm::state::compute_storage_key; use starknet::ContractAddress; use evm::model::Address; - use snforge_std::cheatcodes::handle_cheatcode; use snforge_std::cheatcodes::storage::store_felt252; - use snforge_std::{Event, spy_events, EventSpy, EventSpyAssertionsTrait, EventSpyTrait}; + use snforge_std::Event; use snforge_std::cheatcodes::events::{Events}; use array_utils::ArrayExtTrait; - use snforge_std::trace::{ - get_call_trace, CallTrace, CallEntryPoint, CallResult, EntryPointType, CallType, CallFailure - }; + use snforge_std::trace::{get_call_trace, CallTrace, CallEntryPoint}; pub fn is_called(contract_address: ContractAddress, selector: felt252) -> bool { let call_trace = get_call_trace(); diff --git a/crates/utils/Scarb.toml b/crates/utils/Scarb.toml index ee3ce2097..150dd137b 100644 --- a/crates/utils/Scarb.toml +++ b/crates/utils/Scarb.toml @@ -1,7 +1,7 @@ [package] name = "utils" version = "0.1.0" -edition = "2023_10" +edition = "2024_07" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html diff --git a/crates/utils/src/address.cairo b/crates/utils/src/address.cairo index 169d272da..128414436 100644 --- a/crates/utils/src/address.cairo +++ b/crates/utils/src/address.cairo @@ -3,9 +3,7 @@ use core::starknet::EthAddress; use core::traits::TryInto; use evm::errors::EVMError; -use utils::errors::RLPErrorTrait; -use utils::helpers::{U8SpanExTrait, U64Trait, U256Trait, EthAddressExTrait, ArrayExtTrait, ToBytes}; -use utils::math::WrappingBitshift; +use utils::helpers::{U8SpanExTrait, EthAddressExTrait, ToBytes}; use utils::rlp::{RLPTrait, RLPItem}; use utils::traits::{TryIntoResult}; diff --git a/crates/utils/src/constants.cairo b/crates/utils/src/constants.cairo index 0c2ecfe12..4206aebe4 100644 --- a/crates/utils/src/constants.cairo +++ b/crates/utils/src/constants.cairo @@ -1,28 +1,26 @@ -use core::starknet::EthAddress; -use evm::precompiles::{FIRST_ETHEREUM_PRECOMPILE_ADDRESS, LAST_ETHEREUM_PRECOMPILE_ADDRESS}; use utils::traits::{U8IntoEthAddress}; // FELT PRIME // 2^251 + 17 * 2^192 + 1 -const FELT252_PRIME: u256 = 0x800000000000011000000000000000000000000000000000000000000000001; +pub const FELT252_PRIME: u256 = 0x800000000000011000000000000000000000000000000000000000000000001; // Prefix used to compute the address of a Starknet contract being deployed. // -const CONTRACT_ADDRESS_PREFIX: felt252 = 'STARKNET_CONTRACT_ADDRESS'; +pub const CONTRACT_ADDRESS_PREFIX: felt252 = 'STARKNET_CONTRACT_ADDRESS'; // BLOCK //TODO(gas): determine correct block gas limit -const BLOCK_GAS_LIMIT: u128 = 30_000_000; +pub const BLOCK_GAS_LIMIT: u128 = 30_000_000; // CHAIN_ID = KKRT (0x4b4b5254) in ASCII -const CHAIN_ID: u128 = 1263227476; +pub const CHAIN_ID: u128 = 1263227476; // STACK -const STACK_MAX_DEPTH: usize = 1024; +pub const STACK_MAX_DEPTH: usize = 1024; // CODE -const MAX_CODE_SIZE: usize = 0x6000; -const MAX_INITCODE_SIZE: usize = 0x6000 * 2; +pub const MAX_CODE_SIZE: usize = 0x6000; +pub const MAX_INITCODE_SIZE: usize = 0x6000 * 2; // KECCAK // The empty keccak256 hash, Solidity equivalent: @@ -33,9 +31,9 @@ const MAX_INITCODE_SIZE: usize = 0x6000 * 2; // } // Reproducing link: // -const EMPTY_KECCAK: u256 = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; +pub const EMPTY_KECCAK: u256 = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; -const BURN_ADDRESS: felt252 = 0xdead; +pub const BURN_ADDRESS: felt252 = 0xdead; // Numeric constants @@ -212,22 +210,22 @@ pub const POW_2: [ 0x80000000000000000000000000000000 ]; -const POW_2_0: u128 = 0x1; -const POW_2_8: u128 = 0x100; -const POW_2_16: u128 = 0x10000; -const POW_2_24: u128 = 0x1000000; -const POW_2_32: u128 = 0x100000000; -const POW_2_40: u128 = 0x10000000000; -const POW_2_48: u128 = 0x1000000000000; -const POW_2_56: u128 = 0x100000000000000; -const POW_2_64: u128 = 0x10000000000000000; -const POW_2_72: u128 = 0x1000000000000000000; -const POW_2_80: u128 = 0x100000000000000000000; -const POW_2_88: u128 = 0x10000000000000000000000; -const POW_2_96: u128 = 0x1000000000000000000000000; -const POW_2_104: u128 = 0x100000000000000000000000000; -const POW_2_112: u128 = 0x10000000000000000000000000000; -const POW_2_120: u128 = 0x1000000000000000000000000000000; -const POW_2_127: u128 = 0x80000000000000000000000000000000; +pub const POW_2_0: u128 = 0x1; +pub const POW_2_8: u128 = 0x100; +pub const POW_2_16: u128 = 0x10000; +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_56: u128 = 0x100000000000000; +pub const POW_2_64: u128 = 0x10000000000000000; +pub const POW_2_72: u128 = 0x1000000000000000000; +pub const POW_2_80: u128 = 0x100000000000000000000; +pub const POW_2_88: u128 = 0x10000000000000000000000; +pub const POW_2_96: u128 = 0x1000000000000000000000000; +pub const POW_2_104: u128 = 0x100000000000000000000000000; +pub const POW_2_112: u128 = 0x10000000000000000000000000000; +pub const POW_2_120: u128 = 0x1000000000000000000000000000000; +pub const POW_2_127: u128 = 0x80000000000000000000000000000000; -const MAX_ADDRESS: u256 = 0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; +pub const MAX_ADDRESS: u256 = 0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; diff --git a/crates/utils/src/crypto.cairo b/crates/utils/src/crypto.cairo index d0616713a..261fd6b16 100644 --- a/crates/utils/src/crypto.cairo +++ b/crates/utils/src/crypto.cairo @@ -1,2 +1,2 @@ -mod blake2_compress; -mod modexp; +pub mod blake2_compress; +pub mod modexp; diff --git a/crates/utils/src/crypto/blake2_compress.cairo b/crates/utils/src/crypto/blake2_compress.cairo index dbd5ad38d..0cce040c9 100644 --- a/crates/utils/src/crypto/blake2_compress.cairo +++ b/crates/utils/src/crypto/blake2_compress.cairo @@ -1,8 +1,6 @@ use alexandria_data_structures::vec::{Felt252Vec, VecTrait}; -use core::num::traits::Bounded; use core::num::traits::{BitSize, WrappingAdd}; -use core::option::OptionTrait; -use utils::math::{Bitshift, WrappingBitshift}; +use utils::math::WrappingBitshift; const SIGMA_LINE_1: [usize; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; const SIGMA_LINE_2: [usize; 16] = [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]; @@ -70,7 +68,7 @@ fn rotate_right(value: u64, n: u32) -> u64 { /// * `f` - final block indicator flag /// # Returns /// updated state vector -fn compress(rounds: usize, h: Span, m: Span, t: Span, f: bool) -> Span { +pub fn compress(rounds: usize, h: Span, m: Span, t: Span, f: bool) -> Span { let mut v = VecTrait::::new(); let mut i = 0; while i != 16 { diff --git a/crates/utils/src/crypto/modexp.cairo b/crates/utils/src/crypto/modexp.cairo index 372b1d244..0fde2f4c2 100644 --- a/crates/utils/src/crypto/modexp.cairo +++ b/crates/utils/src/crypto/modexp.cairo @@ -1,3 +1,3 @@ -mod arith; -mod lib; -mod mpnat; +pub mod arith; +pub mod lib; +pub mod mpnat; diff --git a/crates/utils/src/crypto/modexp/arith.cairo b/crates/utils/src/crypto/modexp/arith.cairo index 9773cc2f1..513c5286e 100644 --- a/crates/utils/src/crypto/modexp/arith.cairo +++ b/crates/utils/src/crypto/modexp/arith.cairo @@ -1,15 +1,13 @@ // CREDITS: The implementation has been take from // [aurora-engine](https://github.com/aurora-is-near/aurora-engine/tree/develop/engine-modexp) use alexandria_data_structures::vec::{Felt252Vec, Felt252VecImpl}; -use core::keccak::u128_split; -use core::num::traits::{WideMul, OverflowingAdd, OverflowingSub}; +use core::num::traits::{WideMul, OverflowingAdd, OverflowingSub, WrappingMul}; use core::option::OptionTrait; -use core::traits::TryInto; use super::mpnat::{MPNat, Word, DoubleWord, WORD_BITS, BASE, DOUBLE_WORD_MAX, WORD_MAX}; -use utils::helpers::{Felt252VecTrait, U128Trait}; +use utils::helpers::{u128_split, Felt252VecTrait, U128Trait}; use utils::math::WrappingBitshift; -use utils::math::{Bitshift, WrappingMul}; +use utils::math::{Bitshift}; use utils::traits::BoolIntoNumeric; @@ -20,7 +18,7 @@ use utils::traits::BoolIntoNumeric; // digits needs to represent `n`. `n_prime` has the property that `r(r^(-1)) - nn' = 1`. // Note: This algorithm only works if `xy < rn` (generally we will either have both `x < n`, `y < n` // or we will have `x < r`, `y < n`). -fn monpro(ref x: MPNat, ref y: MPNat, ref n: MPNat, n_prime: Word, ref out: Felt252Vec) { +pub fn monpro(ref x: MPNat, ref y: MPNat, ref n: MPNat, n_prime: Word, ref out: Felt252Vec) { let s = out.len() - 2; let mut i = 0; @@ -119,7 +117,7 @@ fn monpro(ref x: MPNat, ref y: MPNat, ref n: MPNat, n_prime: Word, ref out: Felt } // Equivalent to `monpro(x, x, n, n_prime, out)`, but more efficient. -fn monsq(ref x: MPNat, ref n: MPNat, n_prime: Word, ref out: Felt252Vec) { +pub fn monsq(ref x: MPNat, ref n: MPNat, n_prime: Word, ref out: Felt252Vec) { let s = n.digits.len(); big_sq(ref x, ref out); @@ -259,7 +257,7 @@ pub fn big_wrapping_pow( } /// Computes `(x * y) mod 2^(WORD_BITS*out.len())`. -fn big_wrapping_mul(ref x: MPNat, ref y: MPNat, ref out: Felt252Vec) { +pub fn big_wrapping_mul(ref x: MPNat, ref y: MPNat, ref out: Felt252Vec) { let s = out.len(); let mut i = 0; @@ -292,7 +290,7 @@ fn big_wrapping_mul(ref x: MPNat, ref y: MPNat, ref out: Felt252Vec) { // Given x odd, computes `x^(-1) mod 2^32`. // See `MODULAR-INVERSE` in https://link.springer.com/content/pdf/10.1007/3-540-46877-3_21.pdf -fn mod_inv(x: Word) -> Word { +pub fn mod_inv(x: Word) -> Word { let mut y = 1; let mut i = 2; @@ -325,7 +323,7 @@ fn mod_inv(x: Word) -> Word { /// then computes the difference to get the remainder. It is possible that this /// quotient is too big by 1; we can catch that case by looking for overflow /// in the subtraction. -fn compute_r_mod_n(ref n: MPNat, ref out: Felt252Vec) { +pub fn compute_r_mod_n(ref n: MPNat, ref out: Felt252Vec) { let k = n.digits.len(); if k == 1 { @@ -376,7 +374,7 @@ fn compute_r_mod_n(ref n: MPNat, ref out: Felt252Vec) { /// the second part of the output. The arithmetic in this function is /// guaranteed to never overflow because even when all 4 variables are /// equal to `WORD_MAX` the output is smaller than `DOUBLEWORD_MAX`. -fn shifted_carrying_mul(a: Word, x: Word, y: Word, c: Word) -> (Word, Word) { +pub fn shifted_carrying_mul(a: Word, x: Word, y: Word, c: Word) -> (Word, Word) { let res: DoubleWord = a.into() + x.wide_mul(y) + c.into(); let (top_word, bottom_word) = u128_split(res); (bottom_word, top_word) @@ -386,14 +384,14 @@ fn shifted_carrying_mul(a: Word, x: Word, y: Word, c: Word) -> (Word, Word) { /// the second part of the output. The arithmetic in this function is /// guaranteed to never overflow because even when all 3 variables are /// equal to `Word::MAX` the output is smaller than `DoubleWord::MAX`. -fn carrying_mul(x: Word, y: Word, c: Word) -> (Word, Word) { +pub fn carrying_mul(x: Word, y: Word, c: Word) -> (Word, Word) { let wide = x.wide_mul(y) + c.into(); let (top_word, bottom_word) = u128_split(wide); (bottom_word, top_word) } /// computes x + y accounting for any carry from a previous addition -fn carrying_add(x: Word, y: Word, carry: bool) -> (Word, bool) { +pub fn carrying_add(x: Word, y: Word, carry: bool) -> (Word, bool) { let (a, b) = x.overflowing_add(y); let (c, d) = a.overflowing_add(carry.into()); (c, b | d) @@ -414,7 +412,7 @@ pub fn borrowing_sub(x: Word, y: Word, borrow: bool) -> (Word, bool) { /// /// # Returns /// The double word obtained by joining `hi` and `lo` -fn join_as_double(hi: Word, lo: Word) -> DoubleWord { +pub fn join_as_double(hi: Word, lo: Word) -> DoubleWord { let hi: DoubleWord = hi.into(); (hi.shl(WORD_BITS.into())).into() + lo.into() } @@ -458,7 +456,7 @@ fn big_sq(ref x: MPNat, ref out: Felt252Vec) { } out.set(i + j, res.as_u64()); - c = new_c + ((res.shr(WORD_BITS.into()))); + c = new_c + res.shr(WORD_BITS.into()); j += 1; }; @@ -472,7 +470,7 @@ fn big_sq(ref x: MPNat, ref out: Felt252Vec) { } // Performs `a <<= shift`, returning the overflow -fn in_place_shl(ref a: Felt252Vec, shift: u32) -> Word { +pub fn in_place_shl(ref a: Felt252Vec, shift: u32) -> Word { let mut c: Word = 0; let carry_shift = WORD_BITS - shift; @@ -496,7 +494,7 @@ fn in_place_shl(ref a: Felt252Vec, shift: u32) -> Word { } // Performs `a >>= shift`, returning the overflow -fn in_place_shr(ref a: Felt252Vec, shift: u32) -> Word { +pub fn in_place_shr(ref a: Felt252Vec, shift: u32) -> Word { let mut b: Word = 0; let borrow_shift = WORD_BITS - shift; @@ -546,7 +544,7 @@ pub fn in_place_add(ref a: Felt252Vec, ref b: Felt252Vec) -> bool { } // Performs `a -= xy`, returning the "borrow". -fn in_place_mul_sub(ref a: Felt252Vec, ref x: Felt252Vec, y: Word) -> Word { +pub fn in_place_mul_sub(ref a: Felt252Vec, ref x: Felt252Vec, y: Word) -> Word { // a -= x*0 leaves a unchanged, so return early if y == 0 { return 0; @@ -592,7 +590,7 @@ fn in_place_mul_sub(ref a: Felt252Vec, ref x: Felt252Vec, y: Word) - mod tests { use alexandria_data_structures::vec::VecTrait; use alexandria_data_structures::vec::{Felt252Vec, Felt252VecImpl}; - use core::num::traits::WrappingSub; + use core::num::traits::{WrappingSub, WrappingMul}; use core::result::ResultTrait; use core::traits::Into; @@ -600,13 +598,12 @@ mod tests { mod_inv, monsq, monpro, compute_r_mod_n, in_place_shl, in_place_shr, big_wrapping_pow, big_wrapping_mul, big_sq, borrowing_sub, shifted_carrying_mul }; - use utils::crypto::modexp::mpnat::tests::{mp_nat_to_u128}; use utils::crypto::modexp::mpnat::{ - MPNat, MPNatTrait, WORD_MAX, DOUBLE_WORD_MAX, BASE, Word, DoubleWord, WORD_BYTES + MPNat, MPNatTrait, WORD_MAX, DOUBLE_WORD_MAX, BASE, Word, WORD_BYTES }; + use utils::crypto::modexp::mpnat::{mp_nat_to_u128}; use utils::helpers::{Felt252VecTrait, ToBytes}; - use utils::helpers::{U128Trait}; - use utils::math::{WrappingMul, WrappingBitshift, WrappingExponentiation}; + use utils::math::{WrappingBitshift, WrappingExponentiation}; // the tests are taken from // [aurora-engine](https://github.com/aurora-is-near/aurora-engine/blob/1213f2c7c035aa523601fced8f75bef61b4728ab/engine-modexp/src/arith.rs#L401) diff --git a/crates/utils/src/crypto/modexp/mpnat.cairo b/crates/utils/src/crypto/modexp/mpnat.cairo index e14653c07..fbca2a900 100644 --- a/crates/utils/src/crypto/modexp/mpnat.cairo +++ b/crates/utils/src/crypto/modexp/mpnat.cairo @@ -2,37 +2,32 @@ // [aurora-engine](https://github.com/aurora-is-near/aurora-engine/tree/develop/engine-modexp) use alexandria_data_structures::vec::VecTrait; use alexandria_data_structures::vec::{Felt252Vec, Felt252VecImpl}; -use core::array::ArrayTrait; use core::array::SpanTrait; -use core::dict::Felt252DictTrait; -use core::num::traits::BitSize; -use core::num::traits::{CheckedAdd, CheckedSub, CheckedMul}; +use core::num::traits::CheckedMul; use core::option::OptionTrait; use core::result::ResultTrait; -use core::traits::Destruct; -use core::traits::TryInto; use super::arith::{ big_wrapping_pow, mod_inv, compute_r_mod_n, join_as_double, in_place_shl, in_place_shr, in_place_add, in_place_mul_sub, big_wrapping_mul, monsq, monpro, borrowing_sub, carrying_add }; use utils::helpers::{FromBytes, U64Trait, Felt252VecTrait, U128Trait, BitsUsed, ByteSize}; -use utils::math::{Bitshift, WrappingBitshift}; +use utils::math::Bitshift; -type Word = u64; -type DoubleWord = u128; -const WORD_BYTES: usize = 8; -const WORD_BITS: usize = 64; -const WORD_MAX: Word = 18446744073709551615; +pub type Word = u64; +pub type DoubleWord = u128; +pub const WORD_BYTES: usize = 8; +pub const WORD_BITS: usize = 64; +pub const WORD_MAX: Word = 18446744073709551615; // 2**64 -const BASE: DoubleWord = 18446744073709551616; -const DOUBLE_WORD_MAX: DoubleWord = 340282366920938463463374607431768211455; +pub const BASE: DoubleWord = 18446744073709551616; +pub const DOUBLE_WORD_MAX: DoubleWord = 340282366920938463463374607431768211455; /// Multi-precision natural number, represented in base `Word::MAX + 1 = 2^WORD_BITS`. /// The digits are stored in little-endian order, i.e. digits[0] is the least /// significant digit. #[derive(Destruct)] pub struct MPNat { - digits: Felt252Vec + pub digits: Felt252Vec } @@ -684,39 +679,31 @@ pub impl MPNatTraitImpl of MPNatTrait { } } +pub fn mp_nat_to_u128(ref x: MPNat) -> u128 { + let result = x.digits.to_le_bytes(); + let mut i: usize = 0; + loop { + if i == result.len() { + break; + }; + + i += 1; + }; + result.from_le_bytes_partial().expect('mpnat_to_u128') +} + #[cfg(test)] mod tests { + use alexandria_data_structures::vec::Felt252VecImpl; use alexandria_data_structures::vec::VecTrait; - use alexandria_data_structures::vec::{Felt252Vec, Felt252VecImpl}; - use core::result::ResultTrait; - use core::traits::Into; - - use utils::crypto::modexp::arith::{ - mod_inv, monsq, monpro, compute_r_mod_n, in_place_shl, in_place_shr, big_wrapping_pow, - big_wrapping_mul, big_sq, borrowing_sub, shifted_carrying_mul - }; - use utils::crypto::modexp::mpnat::{ - MPNat, MPNatTrait, WORD_MAX, DOUBLE_WORD_MAX, Word, DoubleWord, WORD_BYTES - }; - use utils::helpers::{Felt252VecTrait, ToBytes, FromBytes}; + use super::mp_nat_to_u128; + use utils::crypto::modexp::mpnat::MPNatTrait; + use utils::helpers::ToBytes; use utils::math::{Bitshift, WrappingBitshift}; // the tests are taken from // [aurora-engine](https://github.com/aurora-is-near/aurora-engine/blob/1213f2c7c035aa523601fced8f75bef61b4728ab/engine-modexp/src/mpnat.rs#L825) - pub fn mp_nat_to_u128(ref x: MPNat) -> u128 { - let result = x.digits.to_le_bytes(); - let mut i: usize = 0; - loop { - if i == result.len() { - break; - }; - - i += 1; - }; - result.from_le_bytes_partial().expect('mpnat_to_u128') - } - fn check_modpow_even(base: u128, exp: u128, modulus: u128, expected: u128) { let mut x = MPNatTrait::from_big_endian(base.to_be_bytes()); let mut m = MPNatTrait::from_big_endian(modulus.to_be_bytes()); diff --git a/crates/utils/src/errors.cairo b/crates/utils/src/errors.cairo index 996b284e5..93a1000d9 100644 --- a/crates/utils/src/errors.cairo +++ b/crates/utils/src/errors.cairo @@ -1,6 +1,6 @@ // LENGTH -const RLP_EMPTY_INPUT: felt252 = 'KKT: EmptyInput'; -const RLP_INPUT_TOO_SHORT: felt252 = 'KKT: InputTooShort'; +pub const RLP_EMPTY_INPUT: felt252 = 'KKT: EmptyInput'; +pub const RLP_INPUT_TOO_SHORT: felt252 = 'KKT: InputTooShort'; #[derive(Drop, Copy, PartialEq)] pub enum RLPError { diff --git a/crates/utils/src/eth_transaction.cairo b/crates/utils/src/eth_transaction.cairo index 197c45920..9833dc98b 100644 --- a/crates/utils/src/eth_transaction.cairo +++ b/crates/utils/src/eth_transaction.cairo @@ -1,14 +1,12 @@ use core::array::SpanTrait; - -use core::keccak::cairo_keccak; use core::option::OptionTrait; -use core::starknet::{EthAddress, eth_signature::{Signature, verify_eth_signature}}; +use core::starknet::{EthAddress, secp256_trait::Signature, eth_signature::{verify_eth_signature}}; use core::traits::TryInto; use utils::errors::RLPErrorTrait; use utils::errors::{EthTransactionError, RLPErrorImpl, RLPHelpersErrorImpl, RLPHelpersErrorTrait}; -use utils::helpers::{U256Trait, U256Impl, ByteArrayExt, U8SpanExTrait}; +use utils::helpers::{U256Impl, ByteArrayExt, U8SpanExTrait}; use utils::rlp::RLPItem; use utils::rlp::{RLPTrait, RLPHelpersTrait}; @@ -36,46 +34,46 @@ pub impl AccessListItemImpl of AccessListItemTrait { #[derive(Drop)] pub struct TransactionMetadata { - address: EthAddress, - account_nonce: u128, - chain_id: u128, - signature: Signature, + pub address: EthAddress, + pub account_nonce: u128, + pub chain_id: u128, + pub signature: Signature, } #[derive(Drop, Copy, Clone, Serde, Debug)] pub struct LegacyTransaction { - chain_id: u128, - nonce: u128, - gas_price: u128, - gas_limit: u128, - destination: Option, - amount: u256, - calldata: Span + pub chain_id: u128, + pub nonce: u128, + pub gas_price: u128, + pub gas_limit: u128, + pub destination: Option, + pub amount: u256, + pub calldata: Span } #[derive(Drop, Copy, Clone, Serde, Debug)] pub struct AccessListTransaction { - chain_id: u128, - nonce: u128, - gas_price: u128, - gas_limit: u128, - destination: Option, - amount: u256, - calldata: Span, - access_list: Span + pub chain_id: u128, + pub nonce: u128, + pub gas_price: u128, + pub gas_limit: u128, + pub destination: Option, + pub amount: u256, + pub calldata: Span, + pub access_list: Span } #[derive(Drop, Copy, Clone, Serde, Debug)] pub struct FeeMarketTransaction { - chain_id: u128, - nonce: u128, - max_priority_fee_per_gas: u128, - max_fee_per_gas: u128, - gas_limit: u128, - destination: Option, - amount: u256, - calldata: Span, - access_list: Span + pub chain_id: u128, + pub nonce: u128, + pub max_priority_fee_per_gas: u128, + pub max_fee_per_gas: u128, + pub gas_limit: u128, + pub destination: Option, + pub amount: u256, + pub calldata: Span, + pub access_list: Span } #[derive(Drop, Serde, Debug)] @@ -486,17 +484,17 @@ pub impl EthTransactionImpl of EthTransactionTrait { #[cfg(test)] mod tests { - use contracts::test_utils::chain_id; use core::option::OptionTrait; - use core::starknet::eth_signature::{EthAddress, Signature}; + use core::starknet::EthAddress; + use core::starknet::secp256_trait::{Signature}; + use evm::test_utils::chain_id; use utils::eth_transaction::{ deserialize_encoded_transaction, EthTransactionTrait, EncodedTransactionTrait, EncodedTransaction, TransactionMetadata, EthTransactionError, EthereumTransaction, EthereumTransactionTrait, AccessListItem }; - use utils::helpers::{U256Trait, ToBytes}; - use utils::rlp::{RLPTrait, RLPItem, RLPHelpersTrait}; + use utils::helpers::ToBytes; use utils::test_data::{ legacy_rlp_encoded_tx, legacy_rlp_encoded_deploy_tx, eip_2930_encoded_tx, eip_1559_encoded_tx @@ -598,9 +596,7 @@ mod tests { let expected_access_list = [ AccessListItem { - ethereum_address: EthAddress { - address: 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 - }, + ethereum_address: 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984.try_into().unwrap(), storage_keys: [ 0xde9fbe35790b85c23f42b7430c78f122636750cc217a534c80a9a0520969fa65, 0xd5362e94136f76bfc8dad0b510b94561af7a387f1a9d0d45e777c11962e5bd94 @@ -647,9 +643,7 @@ mod tests { let expected_access_list = [ AccessListItem { - ethereum_address: EthAddress { - address: 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 - }, + ethereum_address: 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984.try_into().unwrap(), storage_keys: [ 0xde9fbe35790b85c23f42b7430c78f122636750cc217a534c80a9a0520969fa65, 0xd5362e94136f76bfc8dad0b510b94561af7a387f1a9d0d45e777c11962e5bd94 @@ -668,7 +662,7 @@ mod tests { let encoded_tx_data = legacy_rlp_encoded_tx(); let result = EncodedTransactionTrait::is_legacy_tx(encoded_tx_data); - assert(result == true, 'is_legacy_tx expected true'); + assert(result, 'is_legacy_tx expected true'); } #[test] @@ -676,7 +670,7 @@ mod tests { let encoded_tx_data = eip_1559_encoded_tx(); let result = EncodedTransactionTrait::is_legacy_tx(encoded_tx_data); - assert(result == false, 'is_legacy_tx expected false'); + assert(!result, 'is_legacy_tx expected false'); } #[test] @@ -684,7 +678,7 @@ mod tests { let encoded_tx_data = eip_2930_encoded_tx(); let result = EncodedTransactionTrait::is_legacy_tx(encoded_tx_data); - assert(result == false, 'is_legacy_tx expected false'); + assert(!result, 'is_legacy_tx expected false'); } @@ -708,7 +702,7 @@ mod tests { let result = EthTransactionTrait::validate_eth_tx(validate_tx_param, encoded_tx_data) .expect('signature verification failed'); - assert(result == true, 'result is not true'); + assert(result, 'result is not true'); } @@ -732,7 +726,7 @@ mod tests { let result = EthTransactionTrait::validate_eth_tx(validate_tx_param, encoded_tx_data) .expect('signature verification failed'); - assert(result == true, 'result is not true'); + assert(result, 'result is not true'); } @@ -756,7 +750,7 @@ mod tests { let result = EthTransactionTrait::validate_eth_tx(validate_tx_param, encoded_tx_data) .expect('signature verification failed'); - assert(result == true, 'result is not true'); + assert(result, 'result is not true'); } #[test] diff --git a/crates/utils/src/fmt.cairo b/crates/utils/src/fmt.cairo index f3ccc12ab..3948f2fe9 100644 --- a/crates/utils/src/fmt.cairo +++ b/crates/utils/src/fmt.cairo @@ -1,5 +1,4 @@ -use core::fmt::{Display, Debug, Formatter, Error}; -use core::starknet::{EthAddress, ContractAddress}; +use core::fmt::{Debug, Formatter, Error}; use utils::set::{SpanSet, SpanSetTrait}; mod display_felt252_based { @@ -17,7 +16,6 @@ mod display_felt252_based { mod debug_display_based { use core::fmt::{Display, Debug, Formatter, Error}; - use core::to_byte_array::AppendFormattedToByteArray; pub impl TDisplay> of Debug { fn fmt(self: @T, ref f: Formatter) -> Result<(), Error> { Display::fmt(self, ref f) diff --git a/crates/utils/src/helpers.cairo b/crates/utils/src/helpers.cairo index 8b3b00d1d..4a29f6dd8 100644 --- a/crates/utils/src/helpers.cairo +++ b/crates/utils/src/helpers.cairo @@ -4,26 +4,31 @@ use core::array::ArrayTrait; use core::array::SpanTrait; use core::cmp::min; use core::hash::{HashStateExTrait, HashStateTrait}; -use core::integer::{u32_as_non_zero, U32TryIntoNonZero}; use core::integer; -use core::keccak::{cairo_keccak, u128_split}; +use core::keccak::{cairo_keccak}; use core::num::traits::Bounded; use core::num::traits::{SaturatingAdd}; use core::num::traits::{Zero, One, BitSize}; use core::panic_with_felt252; -use core::pedersen::{HashState, PedersenTrait}; -use core::starknet::{ - EthAddress, EthAddressIntoFelt252, ContractAddress, ClassHash, - eth_signature::{Signature as EthSignature} -}; -use core::traits::DivRem; +use core::pedersen::PedersenTrait; +use core::starknet::{EthAddress, ContractAddress, ClassHash}; use core::traits::TryInto; +use core::traits::{DivRem, BitAnd}; use utils::constants::{CONTRACT_ADDRESS_PREFIX, MAX_ADDRESS}; use utils::constants::{POW_2, POW_256_1, POW_256_REV}; -use utils::eth_transaction::{TransactionType}; use utils::math::{Bitshift, WrappingBitshift, Exponentiation}; -use utils::traits::{U256TryIntoContractAddress, EthAddressIntoU256, TryIntoResult, BoolIntoNumeric}; +use utils::traits::{U256TryIntoContractAddress, EthAddressIntoU256, BoolIntoNumeric}; + + +pub fn u128_split(input: u128) -> (u64, u64) { + let (high, low) = core::integer::u128_safe_divmod( + input, 0x10000000000000000_u128.try_into().unwrap() + ); + + (high.try_into().unwrap(), low.try_into().unwrap()) +} + /// Converts a value to the next closest multiple of 32 /// @@ -244,9 +249,8 @@ pub impl U8SpanExImpl of U8SpanExTrait { /// Transforms a Span into an Array of u64 full words, a pending u64 word and its length in /// bytes fn to_u64_words(self: Span) -> (Array, u64, usize) { - let (full_u64_word_count, last_input_num_bytes) = DivRem::div_rem( - self.len(), u32_as_non_zero(8) - ); + let nonzero_8: NonZero = 8_u32.try_into().unwrap(); + let (full_u64_word_count, last_input_num_bytes) = DivRem::div_rem(self.len(), nonzero_8); let mut u64_words: Array = Default::default(); let mut byte_counter: u8 = 0; @@ -692,7 +696,7 @@ pub impl ByteArrayExt of ByteArrayExTrait { word = word * POW_256_1.into() + (*bytes.pop_front().unwrap()).into(); j += 1; }; - arr.data.append(word.try_into().unwrap()); + arr.append_word(word.try_into().unwrap(), 31); i += 1; }; @@ -707,8 +711,7 @@ pub impl ByteArrayExt of ByteArrayExTrait { pending_word = pending_word * POW_256_1.into() + (*bytes.pop_front().unwrap()).into(); i += 1; }; - arr.pending_word_len = pending_word_len; - arr.pending_word = pending_word; + arr.append_word(pending_word.try_into().unwrap(), pending_word_len); arr } @@ -735,9 +738,8 @@ pub impl ByteArrayExt of ByteArrayExTrait { // because `at` takes a snap and if this snap is automatically done by // the compiler in the loop, it won't compile let self = @self; - let (full_u64_word_count, last_input_num_bytes) = DivRem::div_rem( - self.len(), u32_as_non_zero(8) - ); + let nonzero_8: NonZero = 8_u32.try_into().unwrap(); + let (full_u64_word_count, last_input_num_bytes) = DivRem::div_rem(self.len(), nonzero_8); let mut u64_words: Array = Default::default(); let mut byte_counter: u8 = 0; @@ -1016,13 +1018,13 @@ pub impl BitsUsedImpl< } } -mod bits_used_internal { +pub(crate) mod bits_used_internal { /// Returns the number of bits used to represent the value in binary representation /// # Arguments /// * `self` - The value to compute the number of bits used /// # Returns /// * The number of bits used to represent the value in binary representation - fn bits_used_in_byte(self: u8) -> u8 { + pub(crate) fn bits_used_in_byte(self: u8) -> u8 { if self < 0b100000 { if self < 0b1000 { if self < 0b100 { @@ -1432,7 +1434,6 @@ pub impl Felt252VecTraitImpl< #[cfg(test)] mod tests { - use utils::helpers::{BitsUsed, BytesUsedTrait, ToBytes}; use utils::helpers; #[test] @@ -1621,8 +1622,8 @@ mod tests { } mod u32_test { - use utils::helpers::Bitshift; - use utils::helpers::{BitsUsed, BytesUsedTrait, ToBytes, FromBytes}; + use utils::helpers::{BytesUsedTrait, ToBytes, FromBytes}; + use utils::math::Bitshift; #[test] fn test_u32_from_be_bytes() { @@ -1849,9 +1850,9 @@ mod tests { } mod u64_test { - use utils::helpers::Bitshift; use utils::helpers::U64Trait; use utils::helpers::{BitsUsed, BytesUsedTrait, ToBytes}; + use utils::math::Bitshift; #[test] @@ -1911,9 +1912,8 @@ mod tests { mod u128_test { use core::num::traits::Bounded; - use utils::helpers::Bitshift; - use utils::helpers::U128Trait; - use utils::helpers::{BitsUsed, BytesUsedTrait, ToBytes}; + use utils::helpers::{BytesUsedTrait, ToBytes}; + use utils::math::Bitshift; #[test] fn test_u128_bytes_used() { @@ -1963,9 +1963,9 @@ mod tests { } mod u256_test { - use utils::helpers::Bitshift; use utils::helpers::U256Trait; use utils::helpers::{BitsUsed, BytesUsedTrait}; + use utils::math::Bitshift; #[test] fn test_reverse_bytes_u256() { @@ -2262,7 +2262,7 @@ mod tests { mod felt252_vec_u8_test { - use alexandria_data_structures::vec::{VecTrait, Felt252Vec, Felt252VecImpl}; + use alexandria_data_structures::vec::{VecTrait, Felt252Vec}; use utils::helpers::{Felt252VecTrait}; #[test] @@ -2281,7 +2281,7 @@ mod tests { } mod felt252_vec_u64_test { - use alexandria_data_structures::vec::{VecTrait, Felt252Vec, Felt252VecImpl}; + use alexandria_data_structures::vec::{VecTrait, Felt252Vec}; use utils::helpers::{Felt252VecTrait}; #[test] @@ -2347,7 +2347,7 @@ mod tests { } mod felt252_vec_test { - use alexandria_data_structures::vec::{VecTrait, Felt252Vec, Felt252VecImpl}; + use alexandria_data_structures::vec::{VecTrait, Felt252Vec}; use utils::helpers::{Felt252VecTrait, Felt252VecTraitErrors}; #[test] diff --git a/crates/utils/src/i256.cairo b/crates/utils/src/i256.cairo index 4278ef3dd..7aa9b2faf 100644 --- a/crates/utils/src/i256.cairo +++ b/crates/utils/src/i256.cairo @@ -1,13 +1,12 @@ -use core::integer::{u256_try_as_non_zero}; use core::num::traits::Bounded; use utils::constants::POW_2_127; -use utils::math::{Bitshift, Exponentiation}; #[derive(Copy, Drop, PartialEq)] pub struct i256 { - value: u256, + pub value: u256, } + pub impl U256IntoI256 of Into { #[inline(always)] fn into(self: u256) -> i256 { @@ -140,7 +139,6 @@ fn i256_neg(a: i256) -> i256 { mod tests { use core::num::traits::Bounded; use utils::i256::{i256, i256_neg, i256_signed_div_rem}; - use utils::math::Bitshift; const MAX_SIGNED_VALUE: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; @@ -180,7 +178,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = 2_u256.into(); - assert(lhs < rhs == true, 'lhs should be lt rhs'); + assert(lhs < rhs, 'lhs should be lt rhs'); } #[test] @@ -188,7 +186,7 @@ mod tests { let lhs: i256 = (Bounded::::MAX - 1).into(); // -2 let rhs: i256 = Bounded::::MAX.into(); // -1 - assert(lhs < rhs == true, 'lhs should be lt rhs'); + assert(lhs < rhs, 'lhs should be lt rhs'); } #[test] @@ -196,7 +194,7 @@ mod tests { let lhs: i256 = Bounded::::MAX.into(); // -1 let rhs: i256 = 1_u256.into(); - assert(lhs < rhs == true, 'lhs should be lt rhs'); + assert(lhs < rhs, 'lhs should be lt rhs'); } #[test] @@ -204,7 +202,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = Bounded::::MAX.into(); // -1 - assert(lhs < rhs == false, 'lhs should not be lt rhs'); + assert(!(lhs < rhs), 'lhs should not be lt rhs'); } #[test] @@ -212,7 +210,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = 1_u256.into(); - assert(lhs < rhs == false, 'lhs should not be lt rhs'); + assert(!(lhs < rhs), 'lhs should not be lt rhs'); } #[test] @@ -220,7 +218,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = 2_u256.into(); - assert(lhs <= rhs == true, 'lhs should be le rhs'); + assert(lhs <= rhs, 'lhs should be le rhs'); } #[test] @@ -228,7 +226,7 @@ mod tests { let lhs: i256 = (Bounded::::MAX - 1).into(); // -2 let rhs: i256 = Bounded::::MAX.into(); // -1 - assert(lhs <= rhs == true, 'lhs should be le rhs'); + assert(lhs <= rhs, 'lhs should be le rhs'); } #[test] @@ -236,7 +234,7 @@ mod tests { let lhs: i256 = Bounded::::MAX.into(); // -1 let rhs: i256 = 1_u256.into(); - assert(lhs <= rhs == true, 'lhs should be le rhs'); + assert(lhs <= rhs, 'lhs should be le rhs'); } #[test] @@ -244,7 +242,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = Bounded::::MAX.into(); // -1 - assert(lhs <= rhs == false, 'lhs should not be le rhs'); + assert(!(lhs <= rhs), 'lhs should not be le rhs'); } #[test] @@ -252,7 +250,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = 1_u256.into(); - assert(lhs <= rhs == true, 'lhs should be le rhs'); + assert(lhs <= rhs, 'lhs should be le rhs'); } #[test] @@ -260,7 +258,7 @@ mod tests { let lhs: i256 = 2_u256.into(); let rhs: i256 = 1_u256.into(); - assert(lhs > rhs == true, 'lhs should be gt rhs'); + assert(lhs > rhs, 'lhs should be gt rhs'); } #[test] @@ -268,7 +266,7 @@ mod tests { let lhs: i256 = Bounded::::MAX.into(); // -1 let rhs: i256 = (Bounded::::MAX - 1).into(); // -2 - assert(lhs > rhs == true, 'lhs should be gt rhs'); + assert(lhs > rhs, 'lhs should be gt rhs'); } #[test] @@ -276,7 +274,7 @@ mod tests { let lhs: i256 = Bounded::::MAX.into(); // -1 let rhs: i256 = 1_u256.into(); - assert(lhs > rhs == false, 'lhs should not be gt rhs'); + assert(!(lhs > rhs), 'lhs should not be gt rhs'); } #[test] @@ -284,7 +282,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = Bounded::::MAX.into(); // -1 - assert(lhs > rhs == true, 'lhs should be gt rhs'); + assert(lhs > rhs, 'lhs should be gt rhs'); } #[test] @@ -292,7 +290,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = 1_u256.into(); - assert(lhs > rhs == false, 'lhs should not be gt rhs'); + assert(!(lhs > rhs), 'lhs should not be gt rhs'); } #[test] @@ -300,7 +298,7 @@ mod tests { let lhs: i256 = 2_u256.into(); let rhs: i256 = 1_u256.into(); - assert(lhs >= rhs == true, 'lhs should be ge rhs'); + assert(lhs >= rhs, 'lhs should be ge rhs'); } #[test] @@ -308,7 +306,7 @@ mod tests { let lhs: i256 = Bounded::::MAX.into(); // -1 let rhs: i256 = (Bounded::::MAX - 1).into(); // -2 - assert(lhs >= rhs == true, 'lhs should be ge rhs'); + assert(lhs >= rhs, 'lhs should be ge rhs'); } #[test] @@ -316,7 +314,7 @@ mod tests { let lhs: i256 = Bounded::::MAX.into(); // -1 let rhs: i256 = 1_u256.into(); - assert(lhs >= rhs == false, 'lhs should not be ge rhs'); + assert(!(lhs >= rhs), 'lhs should not be ge rhs'); } #[test] @@ -324,7 +322,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = Bounded::::MAX.into(); // -1 - assert(lhs >= rhs == true, 'lhs should be ge rhs'); + assert(lhs >= rhs, 'lhs should be ge rhs'); } #[test] @@ -332,7 +330,7 @@ mod tests { let lhs: i256 = 1_u256.into(); let rhs: i256 = 1_u256.into(); - assert(lhs >= rhs == true, 'lhs should be ge rhs'); + assert(lhs >= rhs, 'lhs should be ge rhs'); } #[test] diff --git a/crates/utils/src/lib.cairo b/crates/utils/src/lib.cairo index df98710c1..2817428af 100644 --- a/crates/utils/src/lib.cairo +++ b/crates/utils/src/lib.cairo @@ -11,7 +11,7 @@ pub mod rlp; pub mod serialization; pub mod set; -mod test_data; +pub mod test_data; pub mod traits; //! Utilities for kakarot standard library. diff --git a/crates/utils/src/math.cairo b/crates/utils/src/math.cairo index b1d6efd2f..d18498191 100644 --- a/crates/utils/src/math.cairo +++ b/crates/utils/src/math.cairo @@ -1,12 +1,7 @@ use core::integer::{u512}; -use core::keccak::u128_split; -use core::num::traits::Bounded; -use core::num::traits::{ - Zero, One, BitSize, OverflowingAdd, OverflowingMul, WrappingMul, SaturatingAdd -}; -use core::ops; +use core::num::traits::{Zero, One, BitSize, OverflowingAdd, OverflowingMul}; use core::panic_with_felt252; -use core::starknet::secp256_trait::Secp256PointTrait; +use core::traits::{BitAnd}; // === Exponentiation === @@ -17,7 +12,7 @@ pub trait Exponentiation { fn pow(self: T, exponent: T) -> T; } -pub impl ExponentiationImpl< +impl ExponentiationImpl< T, +Zero, +One, @@ -182,7 +177,7 @@ pub trait Bitshift { fn shr(self: T, shift: T) -> T; } -pub impl BitshiftImpl< +impl BitshiftImpl< T, +Zero, +One, diff --git a/crates/utils/src/rlp.cairo b/crates/utils/src/rlp.cairo index efaed5777..cc79e70ca 100644 --- a/crates/utils/src/rlp.cairo +++ b/crates/utils/src/rlp.cairo @@ -1,13 +1,9 @@ use core::array::ArrayTrait; use core::array::SpanTrait; -use core::byte_array::ByteArrayTrait; use core::option::OptionTrait; use core::panic_with_felt252; -use core::result::ResultTrait; use core::starknet::EthAddress; - -use utils::errors::RLPHelpersErrorTrait; -use utils::errors::{RLPError, RLPHelpersError, RLP_EMPTY_INPUT, RLP_INPUT_TOO_SHORT}; +use utils::errors::{RLPError, RLPHelpersError}; use utils::eth_transaction::AccessListItem; use utils::helpers::{EthAddressExTrait, ArrayExtension, ToBytes, FromBytes}; @@ -341,10 +337,7 @@ mod tests { use core::option::OptionTrait; use core::result::ResultTrait; - - use core::starknet::eth_address::EthAddress; - use core::traits::Into; - use utils::errors::{RLPError, RLP_EMPTY_INPUT, RLP_INPUT_TOO_SHORT}; + use utils::errors::RLPError; use utils::eth_transaction::AccessListItem; use utils::rlp::{RLPType, RLPTrait, RLPItem, RLPHelpersTrait}; @@ -713,7 +706,7 @@ mod tests { let mut i = 0; loop { if i == 0x80 { - break (); + break; } let mut arr = ArrayTrait::new(); arr.append(i); diff --git a/crates/utils/src/serialization.cairo b/crates/utils/src/serialization.cairo index 288643902..564153220 100644 --- a/crates/utils/src/serialization.cairo +++ b/crates/utils/src/serialization.cairo @@ -1,7 +1,5 @@ use core::starknet::secp256_trait::{Signature}; -use utils::eth_transaction::{ - TransactionType, EthereumTransaction, EthereumTransactionTrait, LegacyTransaction -}; +use utils::eth_transaction::TransactionType; use utils::traits::BoolIntoNumeric; pub fn deserialize_signature(signature: Span, chain_id: u128) -> Option { @@ -35,7 +33,7 @@ fn compute_y_parity(v: u128, chain_id: u128) -> Option { return Option::None; } -fn serialize_transaction_signature( +pub fn serialize_transaction_signature( sig: Signature, tx_type: TransactionType, chain_id: u128 ) -> Array { let mut res: Array = array![ @@ -52,7 +50,7 @@ fn serialize_transaction_signature( res } -fn deserialize_bytes(self: Span) -> Option> { +pub fn deserialize_bytes(self: Span) -> Option> { let mut i = 0; let mut bytes: Array = Default::default(); @@ -75,7 +73,7 @@ fn deserialize_bytes(self: Span) -> Option> { } } -fn serialize_bytes(self: Span) -> Array { +pub fn serialize_bytes(self: Span) -> Array { let mut array: Array = Default::default(); let mut i = 0; @@ -92,7 +90,7 @@ fn serialize_bytes(self: Span) -> Array { #[cfg(test)] mod tests { - use core::starknet::eth_signature::Signature; + use core::starknet::secp256_trait::Signature; use utils::constants::CHAIN_ID; use utils::eth_transaction::TransactionType; use utils::serialization::{deserialize_signature, serialize_transaction_signature}; diff --git a/crates/utils/src/set.cairo b/crates/utils/src/set.cairo index 39f201829..1348bc40b 100644 --- a/crates/utils/src/set.cairo +++ b/crates/utils/src/set.cairo @@ -13,7 +13,6 @@ pub impl SetDefault> of Default> { } } - #[generate_trait] pub impl SetImpl, +Copy> of SetTrait { #[inline] @@ -21,6 +20,10 @@ pub impl SetImpl, +Copy> of SetTrait { Set { inner: Default::default() } } + fn from_array(arr: Array) -> Set { + Set { inner: arr } + } + #[inline] fn add<+PartialEq>(ref self: Set, item: T) { self.inner.append_unique(item); diff --git a/crates/utils/src/test_data.cairo b/crates/utils/src/test_data.cairo index 800506d07..b9084552b 100644 --- a/crates/utils/src/test_data.cairo +++ b/crates/utils/src/test_data.cairo @@ -1,4 +1,4 @@ -fn legacy_rlp_encoded_tx() -> Span { +pub fn legacy_rlp_encoded_tx() -> Span { // tx_format (EIP-155, unsigned): [nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0] // expected rlp decoding: [ "0x", "0x3b9aca00", "0x1e8480", // "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", "0x016345785d8a0000", "0xabcdef", "0x4b4b5254", @@ -61,7 +61,7 @@ fn legacy_rlp_encoded_tx() -> Span { ].span() } -fn legacy_rlp_encoded_deploy_tx() -> Span { +pub fn legacy_rlp_encoded_deploy_tx() -> Span { // tx_format (EIP-155, unsigned): [nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0] // expected rlp decoding: // ["0x","0x0a","0x061a80","0x","0x0186a0","0x600160010a5060006000f3","0x4b4b5254","0x","0x"] @@ -101,7 +101,7 @@ fn legacy_rlp_encoded_deploy_tx() -> Span { } -fn eip_2930_encoded_tx() -> Span { +pub fn eip_2930_encoded_tx() -> Span { // tx_format (EIP-2930, unsigned): 0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, // data, accessList]) // expected rlp decoding: [ "0x4b4b5254", "0x", "0x3b9aca00", "0x1e8480", @@ -260,7 +260,7 @@ fn eip_2930_encoded_tx() -> Span { ].span() } -fn eip_1559_encoded_tx() -> Span { +pub fn eip_1559_encoded_tx() -> Span { // tx_format (EIP-1559, unsigned): 0x02 || rlp([chain_id, nonce, max_priority_fee_per_gas, // max_fee_per_gas, gas_limit, destination, amount, data, access_list]) // expected rlp decoding: [ "0x4b4b5254", "0x", "0x", "0x3b9aca00", "0x1e8480", diff --git a/crates/utils/src/traits.cairo b/crates/utils/src/traits.cairo index b6ef8cfcb..5da27b18b 100644 --- a/crates/utils/src/traits.cairo +++ b/crates/utils/src/traits.cairo @@ -1,9 +1,7 @@ use core::array::SpanTrait; use core::num::traits::{Zero, One}; -use core::starknet::{ - StorageBaseAddress, storage_address_from_base, storage_base_address_from_felt252, EthAddress, - ContractAddress, Store, SyscallResult -}; +use core::starknet::storage_access::{StorageBaseAddress, storage_address_from_base}; +use core::starknet::{EthAddress, ContractAddress}; use evm::errors::{EVMError, ensure, TYPE_CONVERSION_ERROR}; use utils::math::{Bitshift}; @@ -125,10 +123,7 @@ pub impl U8IntoEthAddress of Into { #[cfg(test)] mod tests { - use core::starknet::{ - StorageBaseAddress, StorageAddress, storage_address_from_base, - storage_address_try_from_felt252, storage_base_address_from_felt252 - }; + use core::starknet::storage_access::storage_base_address_from_felt252; use utils::traits::{StorageBaseAddressPartialEq}; #[test] diff --git a/crates/utils/src/utils.cairo b/crates/utils/src/utils.cairo index df223e9ac..6d3ac14bb 100644 --- a/crates/utils/src/utils.cairo +++ b/crates/utils/src/utils.cairo @@ -1,5 +1,3 @@ -use core::array; -use core::felt252_div; use core::num::traits::Zero; /// Pack an array of bytes into 31-byte words and a final word.