Skip to content

Commit

Permalink
feat(mempool_test_utils,starknet_integration_tests): test(starknet_in…
Browse files Browse the repository at this point in the history
…tegration_tests): test deploy account txs in flow test
  • Loading branch information
yair-starkware committed Dec 31, 2024
1 parent bc8f41c commit be95926
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 65 deletions.
22 changes: 21 additions & 1 deletion crates/mempool_test_utils/src/starknet_api_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,26 @@ impl MultiAccountTransactionGenerator {
pub fn accounts(&self) -> &[AccountTransactionGenerator] {
self.account_tx_generators.as_slice()
}

pub fn account_tx_generators(&mut self) -> &mut Vec<AccountTransactionGenerator> {
&mut self.account_tx_generators
}

pub fn deployed_accounts(&self) -> Vec<Contract> {
self.account_tx_generators
.iter()
.filter_map(|tx_gen| if tx_gen.is_deployed() { Some(&tx_gen.account) } else { None })
.copied()
.collect()
}

pub fn undeployed_accounts(&self) -> Vec<Contract> {
self.account_tx_generators
.iter()
.filter_map(|tx_gen| if !tx_gen.is_deployed() { Some(&tx_gen.account) } else { None })
.copied()
.collect()
}
}

/// Manages transaction generation for a single account.
Expand Down Expand Up @@ -417,7 +437,7 @@ impl AccountTransactionGenerator {
// Note: feature contracts have their own address generating method, but it a mocked address and is
// not related to an actual deploy account transaction, which is the way real account addresses are
// calculated.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Contract {
pub contract: FeatureContract,
pub sender_address: ContractAddress,
Expand Down
2 changes: 1 addition & 1 deletion crates/starknet_integration_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ cairo-lang-starknet-classes.workspace = true
futures.workspace = true
indexmap.workspace = true
infra_utils.workspace = true
itertools.workspace = true
mempool_test_utils.workspace = true
papyrus_common.workspace = true
papyrus_config.workspace = true
Expand Down Expand Up @@ -46,7 +47,6 @@ url.workspace = true

[dev-dependencies]
futures.workspace = true
itertools.workspace = true
pretty_assertions.workspace = true
rstest.workspace = true
starknet_sequencer_infra.workspace = true
17 changes: 10 additions & 7 deletions crates/starknet_integration_tests/src/state_reader.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;

Expand All @@ -8,6 +9,7 @@ use blockifier::test_utils::{CairoVersion, RunnableCairo1, BALANCE};
use blockifier::versioned_constants::VersionedConstants;
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use indexmap::IndexMap;
use itertools::Itertools;
use mempool_test_utils::starknet_api_test_utils::{AccountTransactionGenerator, Contract};
use papyrus_common::pending_classes::PendingClasses;
use papyrus_rpc::{run_server, RpcConfig};
Expand Down Expand Up @@ -195,35 +197,36 @@ fn prepare_sierra_classes(
) -> Vec<(ClassHash, SierraContractClass)> {
contract_classes_to_retrieve
.filter(|contract| !contract.cairo_version().is_cairo0())
.dedup_by(|c1, c2| c1.class_hash() == c2.class_hash())
.map(|contract| (contract.class_hash(), contract.sierra()))
.collect()
}

fn prepare_compiled_contract_classes(
contract_classes_to_retrieve: impl Iterator<Item = Contract>,
) -> ContractClassesMap {
let mut cairo0_contract_classes = Vec::new();
let mut cairo1_contract_classes = Vec::new();
let mut cairo0_contract_classes = HashMap::new();
let mut cairo1_contract_classes = HashMap::new();
for contract in contract_classes_to_retrieve {
match contract.cairo_version() {
CairoVersion::Cairo0 => {
cairo0_contract_classes.push((
cairo0_contract_classes.insert(
contract.class_hash(),
serde_json::from_str(&contract.raw_class()).unwrap(),
));
);
}
// todo(rdr): including both Cairo1 and Native versions for now. Temporal solution to
// avoid compilation errors when using the "cairo_native" feature
_ => {
cairo1_contract_classes.push((
cairo1_contract_classes.insert(
contract.class_hash(),
serde_json::from_str(&contract.raw_class()).unwrap(),
));
);
}
}
}

(cairo0_contract_classes, cairo1_contract_classes)
(cairo0_contract_classes.into_iter().collect(), cairo1_contract_classes.into_iter().collect())
}

fn write_state_to_papyrus_storage(
Expand Down
35 changes: 34 additions & 1 deletion crates/starknet_integration_tests/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ use std::time::Duration;
use blockifier::context::ChainInfo;
use blockifier::test_utils::contracts::FeatureContract;
use blockifier::test_utils::{CairoVersion, RunnableCairo1};
use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator};
use mempool_test_utils::starknet_api_test_utils::{
AccountId,
AccountTransactionGenerator,
Contract,
MultiAccountTransactionGenerator,
};
use papyrus_consensus::config::ConsensusConfig;
use papyrus_consensus::types::ValidatorId;
use papyrus_network::network_manager::test_utils::{
Expand All @@ -18,6 +23,7 @@ use papyrus_storage::StorageConfig;
use starknet_api::block::BlockNumber;
use starknet_api::core::ChainId;
use starknet_api::rpc_transaction::RpcTransaction;
use starknet_api::transaction::fields::ContractAddressSalt;
use starknet_api::transaction::TransactionHash;
use starknet_batcher::block_builder::BlockBuilderConfig;
use starknet_batcher::config::BatcherConfig;
Expand All @@ -42,6 +48,8 @@ use url::Url;

pub const ACCOUNT_ID_0: AccountId = 0;
pub const ACCOUNT_ID_1: AccountId = 1;
pub const NEW_ACCOUNT_SALT: ContractAddressSalt = ContractAddressSalt(Felt::THREE);
pub const UNDEPLOYED_ACCOUNT_ID: AccountId = 2;

pub fn create_chain_info() -> ChainInfo {
let mut chain_info = ChainInfo::create_for_testing();
Expand Down Expand Up @@ -169,6 +177,13 @@ pub fn create_integration_test_tx_generator() -> MultiAccountTransactionGenerato
] {
tx_generator.register_deployed_account(account);
}
// TODO(yair): This is a hack to fund the new account during the setup. Move the registration to
// the test body once funding is supported.
let new_account_id = tx_generator.register_undeployed_account(
FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)),
NEW_ACCOUNT_SALT,
);
assert_eq!(new_account_id, UNDEPLOYED_ACCOUNT_ID);
tx_generator
}

Expand All @@ -186,6 +201,24 @@ pub fn create_txs_for_integration_test(
vec![account0_invoke_nonce1, account0_invoke_nonce2, account1_invoke_nonce1]
}

pub fn create_funding_txs(
tx_generator: &mut MultiAccountTransactionGenerator,
) -> Vec<RpcTransaction> {
// TODO(yair): Register the undeployed account here instead of in the test setup
// once funding is implemented.
let undeployed_account = tx_generator.account_with_id(UNDEPLOYED_ACCOUNT_ID).account;
assert!(tx_generator.undeployed_accounts().contains(&undeployed_account));
fund_new_account(tx_generator.account_with_id_mut(ACCOUNT_ID_0), &undeployed_account)
}

fn fund_new_account(
funding_acount: &mut AccountTransactionGenerator,
receipient: &Contract,
) -> Vec<RpcTransaction> {
let funding_tx = funding_acount.generate_transfer(receipient);
vec![funding_tx]
}

fn create_account_txs(
mut tx_generator: MultiAccountTransactionGenerator,
account_id: AccountId,
Expand Down
110 changes: 55 additions & 55 deletions crates/starknet_integration_tests/tests/end_to_end_flow_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::collections::HashSet;

use blockifier::test_utils::contracts::FeatureContract;
use blockifier::test_utils::{CairoVersion, RunnableCairo1};
use futures::StreamExt;
use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator;
use papyrus_consensus::types::ValidatorId;
Expand All @@ -18,24 +16,23 @@ use pretty_assertions::assert_eq;
use rstest::{fixture, rstest};
use starknet_api::block::{BlockHash, BlockNumber};
use starknet_api::rpc_transaction::RpcTransaction;
use starknet_api::transaction::fields::ContractAddressSalt;
use starknet_api::transaction::TransactionHash;
use starknet_integration_tests::flow_test_setup::{FlowSequencerSetup, FlowTestSetup};
use starknet_integration_tests::test_identifiers::TestIdentifier;
use starknet_integration_tests::utils::{
create_funding_txs,
create_integration_test_tx_generator,
create_txs_for_integration_test,
run_integration_test_scenario,
test_tx_hashes_for_integration_test,
ACCOUNT_ID_0,
UNDEPLOYED_ACCOUNT_ID,
};
use starknet_sequencer_infra::trace_util::configure_tracing;
use starknet_types_core::felt::Felt;
use tracing::debug;

const INITIAL_HEIGHT: BlockNumber = BlockNumber(0);
const LAST_HEIGHT: BlockNumber = BlockNumber(3);
const NEW_ACCOUNT_SALT: ContractAddressSalt = ContractAddressSalt(Felt::THREE);
const LAST_HEIGHT: BlockNumber = BlockNumber(4);

#[fixture]
fn tx_generator() -> MultiAccountTransactionGenerator {
Expand All @@ -62,19 +59,7 @@ async fn end_to_end_flow(mut tx_generator: MultiAccountTransactionGenerator) {
);

let next_height = INITIAL_HEIGHT.unchecked_next();
let n_heights = next_height.iter_up_to(LAST_HEIGHT.unchecked_next()).count();
let heights_to_build = next_height.iter_up_to(LAST_HEIGHT.unchecked_next());
let expected_content_ids = [
Felt::from_hex_unchecked(
"0x58ad05a6987a675eda038663d8e7dcc8e1d91c9057dd57f16d9b3b9602fc840",
),
Felt::from_hex_unchecked(
"0x79b59c5036c9427b5194796ede67bdfffed1f311a77382d715174fcfcc33003",
),
Felt::from_hex_unchecked(
"0x36e1f3e0c71b77474494a5baa0a04a4e406626141eba2b2944e4b568f70ff48",
),
];

let sequencers = [&mock_running_system.sequencer_0, &mock_running_system.sequencer_1];
// We use only the first sequencer's gateway to test that the mempools are syncing.
Expand All @@ -83,35 +68,12 @@ async fn end_to_end_flow(mut tx_generator: MultiAccountTransactionGenerator) {
// We start at height 1, so we need to skip the proposer of the initial height.
expected_proposer_iter.next().unwrap();

let create_rpc_txs_scenarios =
[create_txs_for_integration_test, create_txs_for_integration_test, fund_new_account];

let test_tx_hashes_scenarios =
[test_tx_hashes_for_integration_test, test_tx_hashes_for_integration_test, test_funding];

assert_eq!(
n_heights,
expected_content_ids.len(),
"Expected the same number of heights and content ids"
);
assert_eq!(
n_heights,
create_rpc_txs_scenarios.len(),
"Expected the same number of heights and scenarios"
);
assert_eq!(
n_heights,
test_tx_hashes_scenarios.len(),
"Expected the same number of heights and scenarios"
);
let test_scenarios = create_test_scenarios();

// Build multiple heights to ensure heights are committed.
for (height, expected_content_id, create_rpc_txs_fn, test_tx_hashes_fn) in itertools::izip!(
heights_to_build,
expected_content_ids,
create_rpc_txs_scenarios.iter(),
test_tx_hashes_scenarios.iter(),
) {
for (height, (create_rpc_txs_fn, test_tx_hashes_fn, expected_content_id)) in
itertools::zip_eq(heights_to_build, test_scenarios)
{
debug!("Starting height {}.", height);
// Create and send transactions.
let expected_batched_tx_hashes = run_integration_test_scenario(
Expand Down Expand Up @@ -144,6 +106,43 @@ async fn end_to_end_flow(mut tx_generator: MultiAccountTransactionGenerator) {
}
}

type CreateRpcTxsFn = fn(&mut MultiAccountTransactionGenerator) -> Vec<RpcTransaction>;
type TestTxHashesFn = fn(&[TransactionHash]) -> Vec<TransactionHash>;
type ExpectedContentId = Felt;

fn create_test_scenarios() -> Vec<(CreateRpcTxsFn, TestTxHashesFn, ExpectedContentId)> {
vec![
(
create_txs_for_integration_test,
test_tx_hashes_for_integration_test,
Felt::from_hex_unchecked(
"0x58ad05a6987a675eda038663d8e7dcc8e1d91c9057dd57f16d9b3b9602fc840",
),
),
(
create_txs_for_integration_test,
test_tx_hashes_for_integration_test,
Felt::from_hex_unchecked(
"0x79b59c5036c9427b5194796ede67bdfffed1f311a77382d715174fcfcc33003",
),
),
(
create_funding_txs,
test_funding,
Felt::from_hex_unchecked(
"0x780d92f41f5d5bb03c2250fdfccd83420fda29844cf104fd760eec2a519516d",
),
),
(
deploy_account,
test_deploy_account,
Felt::from_hex_unchecked(
"0x2724726cd6258fa82bca6bc02c871ad5f2398808b8a9f68106954f98e5cc24b",
),
),
]
}

async fn wait_for_sequencer_node(sequencer: &FlowSequencerSetup) {
sequencer.is_alive_test_client.await_alive(5000, 50).await.expect("Node should be alive.");
}
Expand Down Expand Up @@ -237,19 +236,20 @@ async fn listen_to_broadcasted_messages(
);
}

fn fund_new_account(tx_generator: &mut MultiAccountTransactionGenerator) -> Vec<RpcTransaction> {
let new_account_id = tx_generator.register_undeployed_account(
FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm)),
NEW_ACCOUNT_SALT,
);

let to = tx_generator.account_with_id(new_account_id).account;
fn test_funding(tx_hashes: &[TransactionHash]) -> Vec<TransactionHash> {
assert_eq!(tx_hashes.len(), 1, "Expected a single transaction");
tx_hashes.to_vec()
}

let funding_tx = tx_generator.account_with_id_mut(ACCOUNT_ID_0).generate_transfer(&to);
vec![funding_tx]
fn deploy_account(tx_generator: &mut MultiAccountTransactionGenerator) -> Vec<RpcTransaction> {
assert_eq!(tx_generator.account_tx_generators().len(), UNDEPLOYED_ACCOUNT_ID + 1);
let undeployed_account_tx_generator = tx_generator.account_tx_generators().last_mut().unwrap();
assert!(!undeployed_account_tx_generator.is_deployed());
let deploy_tx = undeployed_account_tx_generator.generate_deploy_account();
vec![deploy_tx]
}

fn test_funding(tx_hashes: &[TransactionHash]) -> Vec<TransactionHash> {
fn test_deploy_account(tx_hashes: &[TransactionHash]) -> Vec<TransactionHash> {
assert_eq!(tx_hashes.len(), 1, "Expected a single transaction");
tx_hashes.to_vec()
}

0 comments on commit be95926

Please sign in to comment.