From c4734f6690db58e29b661fcc75e80b1e58393a7d Mon Sep 17 00:00:00 2001 From: Itay Tsabary Date: Thu, 14 Nov 2024 15:41:47 +0200 Subject: [PATCH] chore(tests_integration): add nonce verification commit-id:ab21c59b --- Cargo.lock | 1 + crates/starknet_integration_tests/Cargo.toml | 1 + .../tests/end_to_end_integration_test.rs | 95 ++++++++++++++++++- 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 847f3a4c48..fd13876b4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10296,6 +10296,7 @@ dependencies = [ "mempool_test_utils", "papyrus_common", "papyrus_consensus", + "papyrus_execution", "papyrus_network", "papyrus_protobuf", "papyrus_rpc", diff --git a/crates/starknet_integration_tests/Cargo.toml b/crates/starknet_integration_tests/Cargo.toml index ac1b1a2364..5f96ba01aa 100644 --- a/crates/starknet_integration_tests/Cargo.toml +++ b/crates/starknet_integration_tests/Cargo.toml @@ -19,6 +19,7 @@ indexmap.workspace = true mempool_test_utils.workspace = true papyrus_common.workspace = true papyrus_consensus.workspace = true +papyrus_execution.workspace = true papyrus_network = { workspace = true, features = ["testing"] } papyrus_protobuf.workspace = true papyrus_rpc.workspace = true diff --git a/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs b/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs index c049ba9f6c..3bc66d1423 100644 --- a/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs +++ b/crates/starknet_integration_tests/tests/end_to_end_integration_test.rs @@ -4,16 +4,24 @@ use std::process::Stdio; use std::time::Duration; use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; +use papyrus_execution::execution_utils::get_nonce_at; +use papyrus_storage::state::StateStorageReader; +use papyrus_storage::StorageReader; use rstest::{fixture, rstest}; +use starknet_api::block::BlockNumber; +use starknet_api::core::{ContractAddress, Nonce}; +use starknet_api::state::StateNumber; use starknet_integration_tests::integration_test_setup::IntegrationTestSetup; use starknet_integration_tests::utils::{ create_integration_test_tx_generator, run_transaction_generator_test_scenario, }; use starknet_sequencer_infra::trace_util::configure_tracing; +use starknet_types_core::felt::Felt; use tokio::process::{Child, Command}; use tokio::task::{self, JoinHandle}; -use tracing::info; +use tokio::time::interval; +use tracing::{error, info}; #[fixture] fn tx_generator() -> MultiAccountTransactionGenerator { @@ -25,6 +33,7 @@ async fn spawn_node_child_task(node_config_path: PathBuf) -> Child { // Get the current working directory for the project let project_path = env::current_dir().expect("Failed to get current directory").join("../.."); + // TODO(Tsabary): Capture output to a log file, and present it in case of a failure. // TODO(Tsabary): Change invocation from "cargo run" to separate compilation and invocation // (build, and then invoke the binary). Command::new("cargo") @@ -54,9 +63,63 @@ async fn spawn_run_node(node_config_path: PathBuf) -> JoinHandle<()> { }) } +/// Reads the latest block number from the storage. +fn get_latest_block_number(storage_reader: &StorageReader) -> BlockNumber { + let txn = storage_reader.begin_ro_txn().unwrap(); + txn.get_state_marker().unwrap().prev().unwrap() +} + +/// Reads an account nonce after a block number from storage. +fn get_account_nonce( + storage_reader: &StorageReader, + block_number: BlockNumber, + contract_address: ContractAddress, +) -> Nonce { + let txn = storage_reader.begin_ro_txn().unwrap(); + let state_number = StateNumber::unchecked_right_after_block(block_number); + get_nonce_at(&txn, state_number, None.as_ref(), contract_address).unwrap().unwrap() +} + +/// Sample a storage until sufficiently many blocks have been stored. Returns an error if the after +/// a certain number of attempts the target block number has not been reached. +async fn await_until_storage_contains_block( + interval_duration: Duration, + target_block_number: BlockNumber, + max_attempts: usize, + storage_reader: &StorageReader, +) -> Result<(), ()> { + let mut interval = interval(interval_duration); + let mut count = 0; + loop { + // Read the latest block number. + let latest_block_number = get_latest_block_number(storage_reader); + count += 1; + + // Check if reached the target block number. + if latest_block_number >= target_block_number { + info!("Found block {} after {} queries.", target_block_number, count); + return Ok(()); + } + + // Check if reached the maximum attempts. + if count > max_attempts { + error!( + "Latest block is {}, expected {}, stopping sampling.", + latest_block_number, target_block_number + ); + return Err(()); + } + + // Wait for the next interval. + interval.tick().await; + } +} + #[rstest] #[tokio::test] async fn test_end_to_end_integration(tx_generator: MultiAccountTransactionGenerator) { + const EXPECTED_BLOCK_NUMBER: BlockNumber = BlockNumber(15); + configure_tracing(); info!("Running integration test setup."); @@ -81,13 +144,39 @@ async fn test_end_to_end_integration(tx_generator: MultiAccountTransactionGenera let n_txs = 50; info!("Sending {n_txs} txs."); - run_transaction_generator_test_scenario(tx_generator, n_txs, send_rpc_tx_fn).await; + let (tx_hashes, sender_address) = + run_transaction_generator_test_scenario(tx_generator, n_txs, send_rpc_tx_fn).await; + + info!("Awaiting until {EXPECTED_BLOCK_NUMBER} blocks have been created."); - info!("Shutting down."); + let (batcher_storage_reader, _) = + papyrus_storage::open_storage(integration_test_setup.batcher_storage_config) + .expect("Failed to open batcher's storage"); + + match await_until_storage_contains_block( + Duration::from_secs(5), + EXPECTED_BLOCK_NUMBER, + 15, + &batcher_storage_reader, + ) + .await + { + Ok(_) => {} + Err(_) => panic!("Did not reach expected block number."), + } + + info!("Shutting the node down."); node_run_handle.abort(); let res = node_run_handle.await; assert!( res.expect_err("Node should have been stopped.").is_cancelled(), "Node should have been stopped." ); + + info!("Verify tx sender account nonce."); + let expected_nonce_value = tx_hashes.len() + 1; + let expected_nonce = + Nonce(Felt::from_hex_unchecked(format!("0x{:X}", expected_nonce_value).as_str())); + let nonce = get_account_nonce(&batcher_storage_reader, EXPECTED_BLOCK_NUMBER, sender_address); + assert_eq!(nonce, expected_nonce); }