Skip to content
This repository has been archived by the owner on Aug 2, 2024. It is now read-only.

Commit

Permalink
adding tests for transactions v3
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerson2102 committed May 28, 2024
1 parent 4634579 commit 91127b7
Show file tree
Hide file tree
Showing 3 changed files with 310 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
- feat: Remove generic hasher from block hash computation
- refacto: git submodules removed
- test: Add pallet test for transaction declare V0
- test: Adding tests for txv3

## v0.7.0

Expand Down
202 changes: 199 additions & 3 deletions crates/pallets/starknet/src/tests/invoke_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use sp_runtime::transaction_validity::{
InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction,
};
use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey};
use starknet_api::data_availability::DataAvailabilityMode;
use starknet_api::hash::StarkFelt;
use starknet_api::state::StorageKey;
use starknet_api::transaction::{
Expand All @@ -28,13 +29,15 @@ use super::constants::{
use super::mock::default_mock::*;
use super::mock::*;
use super::utils::{
get_balance_contract_call, get_contract_class, set_account_erc20_balance_to_zero, sign_message_hash,
create_resource_bounds, get_balance_contract_call, get_contract_class, set_account_erc20_balance_to_zero,
sign_message_hash,
};
use crate::tests::constants::{UDC_ADDRESS, UDC_SELECTOR};
use crate::tests::{
get_invoke_argent_dummy, get_invoke_braavos_dummy, get_invoke_dummy, get_invoke_emit_event_dummy,
get_invoke_nonce_dummy, get_invoke_openzeppelin_dummy, get_invoke_v3_dummy, get_storage_read_write_dummy,
set_infinite_tokens, set_nonce,
get_invoke_nonce_dummy, get_invoke_openzeppelin_dummy, get_invoke_v3_argent_dummy, get_invoke_v3_braavos_dummy,
get_invoke_v3_dummy, get_invoke_v3_openzeppelin_dummy, get_storage_read_write_dummy, set_infinite_tokens,
set_nonce,
};
use crate::{Call, Error, StorageView};

Expand Down Expand Up @@ -904,3 +907,196 @@ fn given_hardcoded_contract_set_erc20_balance_to_zero() {
);
});
}

#[test]
fn given_hardcoded_contract_run_invoke_tx_v3_fails_sender_not_deployed() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);

let none_origin = RuntimeOrigin::none();

// Wrong address (not deployed)
let contract_address = ContractAddress(PatriciaKey(
StarkFelt::try_from("0x03e437FB56Bb213f5708Fcd6966502070e276c093ec271aA33433b89E21fd32f").unwrap(),
));

let mut transaction = get_invoke_v3_dummy(Starknet::chain_id(), NONCE_ZERO);
if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx {
tx.sender_address = contract_address;
};

assert_err!(Starknet::invoke(none_origin, transaction), Error::<MockRuntime>::AccountNotDeployed);
})
}

#[test]
fn given_hardcoded_contract_run_invoke_tx_v3_on_argent_account_then_it_works() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);
let none_origin = RuntimeOrigin::none();
// NOT WORKING
let chain_id = Starknet::chain_id();
let mut transaction = get_invoke_v3_argent_dummy(chain_id);
if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx {
tx.signature = sign_message_hash(transaction.tx_hash);
};

assert_ok!(Starknet::invoke(none_origin, transaction));
});
}

#[test]
fn given_hardcoded_contract_run_invoke_tx_v3_on_openzeppelin_account_then_it_works() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);
let none_origin = RuntimeOrigin::none();
// NOT WORKING
let transaction = get_invoke_v3_openzeppelin_dummy(Starknet::chain_id());

assert_ok!(Starknet::invoke(none_origin, transaction));
});
}

#[test]
fn given_hardcoded_contract_run_invoke_tx_v3_on_argent_account_with_incorrect_signature_then_it_fails() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);
let none_origin = RuntimeOrigin::none();

let mut transaction = get_invoke_v3_argent_dummy(Starknet::chain_id());
if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx {
tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]);
};

let validate_result = Starknet::validate_unsigned(
TransactionSource::InBlock,
&crate::Call::invoke { transaction: transaction.clone() },
);
assert!(matches!(validate_result.unwrap_err(), TransactionValidityError::Invalid(_)));

assert_err!(Starknet::invoke(none_origin, transaction), Error::<MockRuntime>::TransactionExecutionFailed);
});
}

#[test]
fn given_hardcoded_contract_run_invoke_tx_v3_on_braavos_account_then_it_works() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);
let none_origin = RuntimeOrigin::none();
// NOT WORKING
let mut transaction = get_invoke_v3_braavos_dummy(Starknet::chain_id());
if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx {
tx.signature = sign_message_hash(transaction.tx_hash);
};

assert_ok!(Starknet::invoke(none_origin, transaction));
});
}

#[test]
fn given_hardcoded_contract_run_invoke_tx_v3_on_braavos_account_with_incorrect_signature_then_it_fails() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);
let none_origin = RuntimeOrigin::none();

let mut transaction = get_invoke_v3_braavos_dummy(Starknet::chain_id());
if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx {
tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]);
};

let validate_result = Starknet::validate_unsigned(
TransactionSource::InBlock,
&crate::Call::invoke { transaction: transaction.clone() },
);
assert!(matches!(validate_result.unwrap_err(), TransactionValidityError::Invalid(_)));

assert_err!(Starknet::invoke(none_origin, transaction), Error::<MockRuntime>::TransactionExecutionFailed);
});
}

#[test]
fn given_hardcoded_contract_run_invoke_tx_v3_with_inner_call_in_validate_then_it_fails() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);
let none_origin = RuntimeOrigin::none();

let sender_address = get_account_address(None, AccountType::V0(AccountTypeV0Inner::InnerCall));
let mut transaction = get_invoke_v3_dummy(Starknet::chain_id(), NONCE_ZERO);
if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx {
tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]);
tx.sender_address = sender_address;
};

let storage_key = get_storage_var_address("destination", &[]);
let destination = StarkFelt::try_from(TEST_CONTRACT_ADDRESS).unwrap();
StorageView::<MockRuntime>::insert((sender_address, storage_key), destination);

let storage_key = get_storage_var_address("function_selector", &[]);
let selector = get_selector_from_name("without_arg").unwrap();
StorageView::<MockRuntime>::insert(
(sender_address, storage_key),
StarkFelt::from(Felt252Wrapper::from(selector)),
);

assert_err!(Starknet::invoke(none_origin, transaction), Error::<MockRuntime>::TransactionExecutionFailed);
});
}

#[test]
fn given_account_not_deployed_invoke_tx_v3_validate_works_for_nonce_one() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);
// Wrong address (not deployed)
let contract_address = ContractAddress(PatriciaKey(StarkFelt::try_from("0x13123131").unwrap()));
// NOT WORKING
let transaction = starknet_api::transaction::InvokeTransactionV3 {
resource_bounds: create_resource_bounds(),
tip: starknet_api::transaction::Tip::default(),
calldata: Calldata::default(),
sender_address: contract_address,
nonce: Nonce(StarkFelt::ZERO),
signature: TransactionSignature::default(),
nonce_data_availability_mode: DataAvailabilityMode::L1,
fee_data_availability_mode: DataAvailabilityMode::L1,
paymaster_data: starknet_api::transaction::PaymasterData(vec![StarkFelt::ZERO]),
account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![StarkFelt::ZERO]),
};

set_infinite_tokens::<MockRuntime>(&contract_address);
assert_ok!(Starknet::validate_unsigned(
TransactionSource::InBlock,
&crate::Call::invoke { transaction: transaction.into() }
));
})
}

#[test]
fn given_account_not_deployed_invoke_tx_v3_fails_for_nonce_not_one() {
new_test_ext::<MockRuntime>().execute_with(|| {
basic_test_setup(2);

// Wrong address (not deployed)
let contract_address = ContractAddress(PatriciaKey(StarkFelt::try_from("0x13123131").unwrap()));

let transaction = starknet_api::transaction::InvokeTransactionV3 {
resource_bounds: create_resource_bounds(),
tip: starknet_api::transaction::Tip::default(),
calldata: Calldata::default(),
sender_address: contract_address,
nonce: Nonce(StarkFelt::ZERO),
signature: TransactionSignature::default(),
nonce_data_availability_mode: DataAvailabilityMode::L1,
fee_data_availability_mode: DataAvailabilityMode::L1,
paymaster_data: starknet_api::transaction::PaymasterData(vec![StarkFelt::ZERO]),
account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![StarkFelt::ZERO]),
};

assert_eq!(
Starknet::validate_unsigned(
TransactionSource::InBlock,
&crate::Call::invoke { transaction: transaction.into() }
),
Err(TransactionValidityError::Invalid(InvalidTransaction::BadProof))
);
})
}
110 changes: 110 additions & 0 deletions crates/pallets/starknet/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,40 @@ fn get_invoke_argent_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction:
blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false }
}

fn get_invoke_v3_argent_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction {
let sender_address = ContractAddress(PatriciaKey(
StarkFelt::try_from("0x02e63de215f650e9d7e2313c6e9ed26b4f920606fb08576b1663c21a7c4a28c5").unwrap(),
));
let nonce = Nonce(StarkFelt::ZERO);
let signature = TransactionSignature::default();
let calldata = Calldata(Arc::new(vec![
StarkFelt::try_from("0x1").unwrap(), // call_array_len
StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to
StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), // selector
StarkFelt::try_from("0x0").unwrap(), // data_offset
StarkFelt::try_from("0x1").unwrap(), // data_len
StarkFelt::try_from("0x1").unwrap(), // calldata_len
StarkFelt::try_from("0x19").unwrap(), // calldata[0]
]));

let tx = starknet_api::transaction::InvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 {
resource_bounds: create_resource_bounds(),
tip: starknet_api::transaction::Tip::default(),
calldata,
sender_address,
nonce,
signature,
nonce_data_availability_mode: DataAvailabilityMode::L1,
fee_data_availability_mode: DataAvailabilityMode::L1,
paymaster_data: starknet_api::transaction::PaymasterData(vec![]),
account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![]),
});

let tx_hash = tx.compute_hash(chain_id, false);

blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false }
}

// ref: https://github.com/myBraavos/braavos-account-cairo/blob/develop/src/account/Account.cairo
fn get_invoke_braavos_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction {
let signature = TransactionSignature(vec![
Expand Down Expand Up @@ -177,6 +211,43 @@ fn get_invoke_braavos_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction
blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false }
}

fn get_invoke_v3_braavos_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction {
let signature = TransactionSignature(vec![
StarkFelt::try_from("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(),
StarkFelt::try_from("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(),
]);
let sender_address = ContractAddress(PatriciaKey(
StarkFelt::try_from("0x05ef3fba22df259bf84890945352df711bcc9a4e3b6858cb93e9c90d053cf122").unwrap(),
));
let nonce = Nonce(StarkFelt::ZERO);
let calldata = Calldata(Arc::new(vec![
StarkFelt::try_from("0x1").unwrap(), // call_array_len
StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to
StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), // selector
StarkFelt::try_from("0x0").unwrap(), // data_offset
StarkFelt::try_from("0x1").unwrap(), // data_len
StarkFelt::try_from("0x1").unwrap(), // calldata_len
StarkFelt::try_from("0x19").unwrap(), // calldata[0]
]));

let tx = starknet_api::transaction::InvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 {
resource_bounds: create_resource_bounds(),
tip: starknet_api::transaction::Tip::default(),
calldata,
sender_address,
nonce,
signature,
nonce_data_availability_mode: DataAvailabilityMode::L1,
fee_data_availability_mode: DataAvailabilityMode::L1,
paymaster_data: starknet_api::transaction::PaymasterData(vec![]),
account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![]),
});

let tx_hash = tx.compute_hash(chain_id, false);

blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false }
}

// ref: https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/token/erc20/IERC20.cairo
fn get_invoke_emit_event_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction {
let signature = TransactionSignature(vec![
Expand Down Expand Up @@ -295,6 +366,45 @@ fn get_invoke_openzeppelin_dummy(chain_id: Felt252Wrapper) -> blockifier::transa
blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false }
}

fn get_invoke_v3_openzeppelin_dummy(
chain_id: Felt252Wrapper,
) -> blockifier::transaction::transactions::InvokeTransaction {
let signature = TransactionSignature(vec![
StarkFelt::try_from("0x028ef1ae6c37314bf9df65663db1cf68f95d67c4b4cf7f6590654933a84912b0").unwrap(),
StarkFelt::try_from("0x0625aae99c58b18e5161c719fef0f99579c6468ca6c1c866f9b2b968a5447e4").unwrap(),
]);
let sender_address = ContractAddress(PatriciaKey(
StarkFelt::try_from("0x06e2616a2dceff4355997369246c25a78e95093df7a49e5ca6a06ce1544ffd50").unwrap(),
));
let nonce = Nonce(StarkFelt::ZERO);
let calldata = Calldata(Arc::new(vec![
StarkFelt::try_from("0x1").unwrap(), // call_array_len
StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to
StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), // selector
StarkFelt::try_from("0x0").unwrap(), // data offset
StarkFelt::try_from("0x1").unwrap(), // data length
StarkFelt::try_from("0x1").unwrap(), // calldata_len
StarkFelt::try_from("0x19").unwrap(), // calldata[0]
]));

let tx = starknet_api::transaction::InvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 {
resource_bounds: create_resource_bounds(),
tip: starknet_api::transaction::Tip::default(),
calldata,
sender_address,
nonce,
signature,
nonce_data_availability_mode: DataAvailabilityMode::L1,
fee_data_availability_mode: DataAvailabilityMode::L1,
paymaster_data: starknet_api::transaction::PaymasterData(vec![]),
account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![]),
});

let tx_hash = tx.compute_hash(chain_id, false);

blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false }
}

/// Returns a dummy declare transaction for the given account type.
/// The declared class hash is a ERC20 contract, class hash calculated
/// with starkli.
Expand Down

0 comments on commit 91127b7

Please sign in to comment.