Skip to content

Commit

Permalink
tests: adapt testing strategy to leverage snforge feature (#881)
Browse files Browse the repository at this point in the history
* fix state tests

* add py util to find a selector

* add snforge utils to assert a call has / hasnt happened

* migrate model+backend tests

* migrate precompiles tests

* add store_evm util to snforge utils

* migrate memory operation tests

* migrate block_information tests

* migrate environmental_information tests

* fix precompiles range to be dencun's one

* migrate system_operations tests

* use mock classes - addresses everywhere

* fix process_transaction test
  • Loading branch information
enitrat authored Aug 29, 2024
1 parent 5191cc8 commit 2902d76
Show file tree
Hide file tree
Showing 22 changed files with 1,476 additions and 1,311 deletions.
1 change: 1 addition & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ dependencies = [
name = "snforge_utils"
version = "0.1.0"
dependencies = [
"evm",
"snforge_std",
]

Expand Down
52 changes: 32 additions & 20 deletions crates/contracts/tests/test_kakarot_core.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ use snforge_std::{
declare, DeclareResultTrait, start_cheat_caller_address, stop_cheat_caller_address,
start_cheat_signature, stop_cheat_signature, start_cheat_chain_id, stop_cheat_chain_id,
start_cheat_transaction_hash, stop_cheat_transaction_hash, spy_events, Event, EventSpyTrait,
test_address, cheat_caller_address, CheatSpan, store, load, EventSpyAssertionsTrait
test_address, cheat_caller_address, CheatSpan, store, load, EventSpyAssertionsTrait,
start_mock_call, stop_mock_call
};
use snforge_utils::snforge_utils::{
EventsFilterBuilderTrait, ContractEvents, ContractEventsTrait, store_evm
};
use snforge_utils::snforge_utils::{EventsFilterBuilderTrait, ContractEvents, ContractEventsTrait};
use starknet::storage::StorageTrait;
use utils::eth_transaction::{EthereumTransaction, EthereumTransactionTrait, LegacyTransaction};
use utils::helpers::{EthAddressExTrait, u256_to_bytes_array};
Expand Down Expand Up @@ -268,25 +271,33 @@ fn test_eth_call() {
}

#[test]
#[ignore]
//TODO(sn-foundry): fix `Contract not deployed at address: 0x0`
fn test_process_transaction() {
// Given
let (native_token, kakarot_core) = contract_utils::setup_contracts_for_testing();
// Pre
test_utils::setup_test_storages();
let chain_id = chain_id();

let evm_address = test_utils::evm_address();
let eoa = kakarot_core.deploy_externally_owned_account(evm_address);
contract_utils::fund_account_with_native_token(
eoa, native_token, 0xfffffffffffffffffffffffffff
// Given
let eoa_evm_address = test_utils::evm_address();
let eoa_starknet_address = utils::helpers::compute_starknet_address(
test_address(), eoa_evm_address, test_utils::uninitialized_account()
);
let chain_id = chain_id();
test_utils::register_account(eoa_evm_address, eoa_starknet_address);
start_mock_call::<u256>(eoa_starknet_address, selector!("get_nonce"), 0);
start_mock_call::<Span<u8>>(eoa_starknet_address, selector!("bytecode"), [].span());

let _account = contract_utils::deploy_contract_account(
kakarot_core, test_utils::other_evm_address(), counter_evm_bytecode()
let contract_evm_address = test_utils::other_evm_address();
let contract_starknet_address = utils::helpers::compute_starknet_address(
test_address(), contract_evm_address, test_utils::uninitialized_account()
);
test_utils::register_account(contract_evm_address, contract_starknet_address);
start_mock_call::<u256>(contract_starknet_address, selector!("get_nonce"), 1);
start_mock_call::<
Span<u8>
>(contract_starknet_address, selector!("bytecode"), counter_evm_bytecode());
start_mock_call::<u256>(contract_starknet_address, selector!("storage"), 0);

let nonce = 0;
let to = Option::Some(test_utils::other_evm_address());
let to = Option::Some(contract_evm_address);
let gas_limit = test_utils::tx_gas_limit();
let gas_price = test_utils::gas_price();
let value = 0;
Expand All @@ -300,18 +311,19 @@ fn test_process_transaction() {
);

// When
let test_address: ContractAddress = test_address();
start_cheat_caller_address(test_address, eoa);
//TODO(sn-foundry): fix this that fails because the local state doesn't have the correct
//addresses/classes
let mut kakarot_core = KakarotCore::unsafe_new_contract_state();
start_mock_call::<
u256
>(test_utils::native_token(), selector!("balanceOf"), 0xfffffffffffffffffffffffffff);
let result = kakarot_core
.process_transaction(origin: Address { evm: evm_address, starknet: eoa }, :tx);
.process_transaction(
origin: Address { evm: eoa_evm_address, starknet: eoa_starknet_address }, :tx
);
let return_data = result.return_data;

// Then
assert!(result.success);
assert(return_data == u256_to_bytes_array(0).span(), 'wrong result');
assert_eq!(return_data, u256_to_bytes_array(0).span());
}

#[test]
Expand Down
13 changes: 0 additions & 13 deletions crates/evm/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,6 @@ snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag
snforge_utils = { path = "../snforge_utils" }
assert_macros = "0.1.0"

[[target.starknet-contract]]
casm = true
casm-add-pythonic-hints = true
build-external-contracts = [
"openzeppelin::token::erc20::erc20::ERC20",
"contracts::uninitialized_account::UninitializedAccount",
"contracts::account_contract::AccountContract",
"contracts::kakarot_core::kakarot::KakarotCore",
]


[lib]
name = "evm"
[tool]
fmt.workspace = true

Expand Down
133 changes: 116 additions & 17 deletions crates/evm/src/backend/starknet_backend.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -264,40 +264,139 @@ mod internals {
mod tests {
use contracts::account_contract::{IAccountDispatcher, IAccountDispatcherTrait};
use contracts::kakarot_core::KakarotCore;
use contracts::test_utils::setup_contracts_for_testing;
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::state::{State, StateTrait};
use evm::test_utils::{
setup_test_storages, uninitialized_account, account_contract, register_account
};
use evm::test_utils::{chain_id, evm_address, VMBuilderTrait};
use evm::test_utils::{declare_and_store_classes};
use openzeppelin::token::erc20::interface::IERC20CamelDispatcherTrait;
use snforge_std::{spy_events, EventSpyTrait, test_address};
use snforge_std::{spy_events, EventSpyTrait, test_address, start_mock_call, get_class_hash};
use snforge_utils::snforge_utils::{
ContractEvents, ContractEventsTrait, EventsFilterBuilderTrait
ContractEvents, ContractEventsTrait, EventsFilterBuilderTrait, assert_not_called,
assert_called, assert_called_with
};
use utils::helpers::compute_starknet_address;

#[test]
#[ignore]
//TODO(sn-foundry): fix Entrypoint not found
//`0x11f99ee2dc5094f0126c3db5401e3a1a2b6b440f4740e6cce884709cd4526df`
fn test_account_deploy() {
//TODO(starknet-fonudry): it's impossible to deploy an un-declared class, nor is it possible to
//mock_deploy.
fn test_deploy() {
// store the classes in the context of the local execution, to be used for deploying the
// account class
declare_and_store_classes();
setup_test_storages();
let test_address = test_address();

let mut spy = spy_events();
start_mock_call::<
ClassHash
>(test_address, selector!("get_account_contract_class_hash"), account_contract());
start_mock_call::<()>(test_address, selector!("initialize"), ());
let eoa_address = starknet_backend::deploy(evm_address())
.expect('deployment of EOA failed');

let expected = KakarotCore::Event::AccountDeployed(
KakarotCore::AccountDeployed {
evm_address: evm_address(), starknet_address: eoa_address.starknet
}
let class_hash = get_class_hash(eoa_address.starknet);
assert_eq!(class_hash, account_contract());
}

#[test]
#[ignore]
//TODO(starknet-foundry): it's impossible to deploy an un-declared class, nor is it possible to
//mock_deploy.
fn test_account_commit_undeployed_create_should_change_set_all() {
setup_test_storages();
let test_address = test_address();
let evm_address = evm_address();
let starknet_address = compute_starknet_address(
test_address, evm_address, uninitialized_account()
);

let mut state: State = Default::default();

// When
let mut account = Account {
address: Address { evm: evm_address, starknet: starknet_address }, nonce: 420, code: [
0x1
].span(), balance: 0, selfdestruct: false, is_created: true,
};
state.set_account(account);

start_mock_call::<()>(starknet_address, selector!("set_nonce"), ());
start_mock_call::<
ClassHash
>(test_address, selector!("get_account_contract_class_hash"), account_contract());
starknet_backend::commit(ref state).expect('commitment failed');

// Then
//TODO(starknet-foundry): we should be able to assert this has been called with specific
//data, to pass in mock_call
assert_called(starknet_address, selector!("set_nonce"));
assert_not_called(starknet_address, selector!("write_bytecode"));
}

#[test]
fn test_account_commit_deployed_and_created_should_write_code() {
setup_test_storages();
let test_address = test_address();
let evm_address = evm_address();
let starknet_address = compute_starknet_address(
test_address, evm_address, uninitialized_account()
);
register_account(evm_address, starknet_address);

let mut state: State = Default::default();
let mut account = Account {
address: Address { evm: evm_address, starknet: starknet_address }, nonce: 420, code: [
0x1
].span(), balance: 0, selfdestruct: false, is_created: true,
};
state.set_account(account);

start_mock_call::<()>(starknet_address, selector!("write_bytecode"), ());
start_mock_call::<()>(starknet_address, selector!("set_nonce"), ());
starknet_backend::commit(ref state).expect('commitment failed');

// Then the account should have a new code.
//TODO(starknet-foundry): we should be able to assert this has been called with specific
//data, to pass in mock_call
assert_called(starknet_address, selector!("write_bytecode"));
assert_called(starknet_address, selector!("set_nonce"));
}

#[test]
#[ignore]
//TODO(starknet-foundry): it's impossible to deploy an un-declared class, nor is it possible to
//mock_deploy.
fn test_exec_sstore_finalized() { // // Given
// setup_test_storages();
// let mut vm = VMBuilderTrait::new_with_presets().build();
// let evm_address = vm.message().target.evm;
// let starknet_address = compute_starknet_address(
// test_address(), evm_address, uninitialized_account()
// );
// let account = Account {
// address: Address { evm: evm_address, starknet: starknet_address },
// code: [].span(),
// nonce: 1,
// balance: 0,
// selfdestruct: false,
// is_created: false,
// };
// let key: u256 = 0x100000000000000000000000000000001;
// let value: u256 = 0xABDE1E11A5;
// vm.stack.push(value).expect('push failed');
// vm.stack.push(key).expect('push failed');

// // When

// vm.exec_sstore().expect('exec_sstore failed');
// starknet_backend::commit(ref vm.env.state).expect('commit storage failed');

let contract_events = EventsFilterBuilderTrait::from_events(@spy.get_events())
.with_contract_address(test_address)
.build();
contract_events.assert_emitted(@expected);
// // Then
// assert(fetch_original_storage(@account, key) == value, 'wrong committed value')
}
}
74 changes: 20 additions & 54 deletions crates/evm/src/instructions/block_information.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,21 @@ mod tests {
IExtendedKakarotCoreDispatcher, IExtendedKakarotCoreDispatcherTrait
};

use contracts::test_utils::{
setup_contracts_for_testing, fund_account_with_native_token, deploy_contract_account,
};
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::vm::VMTrait;
use evm::stack::StackTrait;
use evm::test_utils::{evm_address, VMBuilderTrait, tx_gas_limit, gas_price};
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_cheat_caller_address, test_address, start_mock_call
};
use utils::constants;
use utils::traits::{EthAddressIntoU256};
Expand Down Expand Up @@ -268,62 +271,25 @@ mod tests {
// 0x47: SELFBALANCE
// *************************************************************************
#[test]
#[ignore]
//TODO(sn-foundry): fix `Contract not deployed at address: 0x0`
fn test_exec_selfbalance_eoa() {
fn test_exec_selfbalance_should_push_balance() {
// Given
let (native_token, kakarot_core) = setup_contracts_for_testing();
let eoa = kakarot_core.deploy_externally_owned_account(evm_address());

fund_account_with_native_token(eoa, native_token, 0x1);

// And
let mut vm = VMBuilderTrait::new_with_presets().build();

// When
start_cheat_caller_address(test_address(), kakarot_core.contract_address);
vm.exec_selfbalance().unwrap();

// Then
assert(vm.stack.peek().unwrap() == native_token.balanceOf(eoa), 'wrong balance');
}

#[test]
#[ignore]
//TODO(sn-foundry): fix `Contract not deployed at address: 0x0`. Needs to deploy an EOA to get
//the selfbalance.
fn test_exec_selfbalance_zero() {
// Given
let (_, kakarot_core) = setup_contracts_for_testing();

// And
let mut vm = VMBuilderTrait::new_with_presets().build();

// When
// start_cheat_caller_address(kakarot_core.contract_address, evm_address());
vm.exec_selfbalance().unwrap();

// Then
assert(vm.stack.peek().unwrap() == 0x00, 'wrong balance');
}

#[test]
#[ignore]
//TODO(sn-foundry): fix `Contract not deployed at address: 0x0`
fn test_exec_selfbalance_contract_account() {
// Given
let (native_token, kakarot_core) = setup_contracts_for_testing();
let mut ca_address = deploy_contract_account(kakarot_core, evm_address(), [].span());

fund_account_with_native_token(ca_address.starknet, native_token, 0x1);
setup_test_storages();
let mut vm = VMBuilderTrait::new_with_presets().build();
let account = Account {
address: vm.message().target,
balance: 400,
nonce: 0,
code: [].span(),
selfdestruct: false,
is_created: true,
};
vm.env.state.set_account(account);

// When
// start_cheat_caller_address(kakarot_core.contract_address, evm_address());
vm.exec_selfbalance().unwrap();

// Then
assert(vm.stack.peek().unwrap() == 0x1, 'wrong balance');
assert_eq!(vm.stack.peek().unwrap(), 400);
}


Expand Down
Loading

0 comments on commit 2902d76

Please sign in to comment.