From b9b707414ecaeadaedb7efe1d22ae940b979fd8c Mon Sep 17 00:00:00 2001 From: Itay Tsabary Date: Thu, 14 Nov 2024 15:14:25 +0200 Subject: [PATCH 1/2] chore(config): add sequencer address as required param commit-id:82d3fb9c --- config/sequencer/default_config.json | 9 +++++++-- crates/starknet_integration_tests/src/config_utils.rs | 2 ++ crates/starknet_integration_tests/src/utils.rs | 1 + crates/starknet_sequencer_node/src/config/node_config.rs | 9 +++++++++ crates/starknet_sequencer_node/src/config/test_utils.rs | 4 ++++ 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/config/sequencer/default_config.json b/config/sequencer/default_config.json index 3f181850f6..b5941df09d 100644 --- a/config/sequencer/default_config.json +++ b/config/sequencer/default_config.json @@ -106,8 +106,8 @@ }, "batcher_config.block_builder_config.sequencer_address": { "description": "The address of the sequencer.", - "privacy": "Public", - "value": "0x0" + "pointer_target": "sequencer_address", + "privacy": "Public" }, "batcher_config.block_builder_config.tx_chunk_size": { "description": "The size of the transaction chunk.", @@ -899,6 +899,11 @@ "privacy": "Public", "value": "" }, + "sequencer_address": { + "description": "A required param! The sequencer address.", + "param_type": "String", + "privacy": "TemporaryValue" + }, "strk_fee_token_address": { "description": "A required param! Address of the STRK fee token.", "param_type": "String", diff --git a/crates/starknet_integration_tests/src/config_utils.rs b/crates/starknet_integration_tests/src/config_utils.rs index 3c2bd6568a..40f3f90434 100644 --- a/crates/starknet_integration_tests/src/config_utils.rs +++ b/crates/starknet_integration_tests/src/config_utils.rs @@ -41,10 +41,12 @@ pub(crate) fn dump_config_file_changes( dir: PathBuf, ) -> PathBuf { // Dump config changes file for the sequencer node. + // TODO(Tsabary): auto dump the entirety of RequiredParams fields. let json_data = config_fields_to_json!( required_params.chain_id, required_params.eth_fee_token_address, required_params.strk_fee_token_address, + required_params.sequencer_address, config.rpc_state_reader_config.json_rpc_version, config.rpc_state_reader_config.url, config.batcher_config.storage.db_config.path_prefix, diff --git a/crates/starknet_integration_tests/src/utils.rs b/crates/starknet_integration_tests/src/utils.rs index a367ac9859..4f85490f19 100644 --- a/crates/starknet_integration_tests/src/utils.rs +++ b/crates/starknet_integration_tests/src/utils.rs @@ -65,6 +65,7 @@ pub async fn create_config( chain_id, eth_fee_token_address: fee_token_addresses.eth_fee_token_address, strk_fee_token_address: fee_token_addresses.strk_fee_token_address, + sequencer_address: ContractAddress::from(1312_u128), // Arbitrary non-zero value. }, consensus_proposals_channels, ) diff --git a/crates/starknet_sequencer_node/src/config/node_config.rs b/crates/starknet_sequencer_node/src/config/node_config.rs index 0459d58980..32dfe68cb6 100644 --- a/crates/starknet_sequencer_node/src/config/node_config.rs +++ b/crates/starknet_sequencer_node/src/config/node_config.rs @@ -75,6 +75,15 @@ pub static CONFIG_POINTERS: LazyLock = LazyLock::new(|| { "gateway_config.chain_info.fee_token_addresses.strk_fee_token_address", ]), ), + // TODO(tsabary): set as a regular required parameter. + ( + ser_pointer_target_required_param( + "sequencer_address", + SerializationType::String, + "The sequencer address.", + ), + set_pointing_param_paths(&["batcher_config.block_builder_config.sequencer_address"]), + ), ]; let mut common_execution_config = generate_struct_pointer( "versioned_constants_overrides".to_owned(), diff --git a/crates/starknet_sequencer_node/src/config/test_utils.rs b/crates/starknet_sequencer_node/src/config/test_utils.rs index 94f0c8e1bb..9434886f09 100644 --- a/crates/starknet_sequencer_node/src/config/test_utils.rs +++ b/crates/starknet_sequencer_node/src/config/test_utils.rs @@ -11,6 +11,7 @@ pub struct RequiredParams { pub chain_id: ChainId, pub eth_fee_token_address: ContractAddress, pub strk_fee_token_address: ContractAddress, + pub sequencer_address: ContractAddress, } impl RequiredParams { @@ -19,6 +20,7 @@ impl RequiredParams { chain_id: ChainId::create_for_testing(), eth_fee_token_address: ContractAddress::from(2_u128), strk_fee_token_address: ContractAddress::from(3_u128), + sequencer_address: ContractAddress::from(17_u128), } } @@ -31,6 +33,8 @@ impl RequiredParams { self.eth_fee_token_address.to_string(), "--strk_fee_token_address".to_string(), self.strk_fee_token_address.to_string(), + "--sequencer_address".to_string(), + self.sequencer_address.to_string(), ]; // Verify all arguments and their values are present. assert!( From 1511a6c2cf3461560c8386def833d357deed8e24 Mon Sep 17 00:00:00 2001 From: Itay Tsabary Date: Thu, 14 Nov 2024 15:41:47 +0200 Subject: [PATCH 2/2] 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 d3b2a62b90..d5a28ceea9 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 0914c91036..945701af17 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..b225022bd2 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,68 @@ 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() + .expect("There should always be a state marker") + .prev() + .expect("There should be a previous block in the storage, set by the test setup") +} + +/// 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, contract_address) + .expect("Should always be Ok(Some(Nonce))") + .expect("Should always be Some(Nonce)") +} + +/// Sample a storage until sufficiently many blocks have been stored. Returns an error if after +/// the given number of attempts the target block number has not been reached. +async fn await_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 +149,34 @@ 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_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!("Verifying 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); }