From 47b50315715bb7a108fee0e727287ab0bb8646bc Mon Sep 17 00:00:00 2001 From: Mohit Dhattarwal <48082542+Mohiiit@users.noreply.github.com> Date: Mon, 23 Dec 2024 15:38:18 +0530 Subject: [PATCH 1/2] fix: minor bug while trimming hash, test added (#435) Co-authored-by: mohiiit --- CHANGELOG.md | 1 + crates/client/eth/src/state_update.rs | 6 ++--- crates/client/eth/src/utils.rs | 16 ----------- crates/client/sync/src/l2.rs | 2 +- crates/client/sync/src/lib.rs | 1 - crates/client/sync/src/utils.rs | 13 --------- crates/primitives/utils/src/hash.rs | 39 +++++++++++++++++++++++++++ crates/primitives/utils/src/lib.rs | 4 ++- 8 files changed, 46 insertions(+), 36 deletions(-) delete mode 100644 crates/client/sync/src/utils.rs create mode 100644 crates/primitives/utils/src/hash.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bec08714..5d2f7463f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- fix: trim hash of eth state was failing with 0x0 - fix: devnet accounts getting deployed in sequencer mode - fix(rpc): fix BroadcastedDeclareTxn V3 in starknet-types-rpc - fix: oracle need condition diff --git a/crates/client/eth/src/state_update.rs b/crates/client/eth/src/state_update.rs index c38bce421..2164f9bf4 100644 --- a/crates/client/eth/src/state_update.rs +++ b/crates/client/eth/src/state_update.rs @@ -1,14 +1,12 @@ use std::sync::Arc; use crate::client::{L1BlockMetrics, StarknetCoreContract}; -use crate::{ - client::EthereumClient, - utils::{convert_log_state_update, trim_hash}, -}; +use crate::{client::EthereumClient, utils::convert_log_state_update}; use anyhow::Context; use futures::StreamExt; use mc_db::MadaraBackend; use mp_utils::service::ServiceContext; +use mp_utils::trim_hash; use serde::Deserialize; use starknet_types_core::felt::Felt; diff --git a/crates/client/eth/src/utils.rs b/crates/client/eth/src/utils.rs index 8fc3bf965..07f0b4b90 100644 --- a/crates/client/eth/src/utils.rs +++ b/crates/client/eth/src/utils.rs @@ -32,14 +32,6 @@ pub fn felt_to_u256(felt: Felt) -> U256 { U256::from_be_bytes(felt.to_bytes_be()) } -pub fn trim_hash(hash: &Felt) -> String { - let hash_str = format!("{:#x}", hash); - let hash_len = hash_str.len(); - let prefix = &hash_str[..6 + 2]; - let suffix = &hash_str[hash_len - 6..]; - format!("{}...{}", prefix, suffix) -} - #[cfg(test)] mod eth_client_conversion_tests { use super::*; @@ -86,12 +78,4 @@ mod eth_client_conversion_tests { assert_eq!(result, expected, "u256_to_felt failed for input: {}", input); } - - #[rstest] - #[case(30000000000000, "0x1b48eb...57e000")] - #[case(12345678123456789, "0x2bdc54...0f5915")] - fn trim_hash_works(#[case] input: u128, #[case] expected: &str) { - let trimmed = trim_hash(&Felt::from(input)); - assert_eq!(trimmed, expected); - } } diff --git a/crates/client/sync/src/l2.rs b/crates/client/sync/src/l2.rs index b4ae85ab7..b2a6041c0 100644 --- a/crates/client/sync/src/l2.rs +++ b/crates/client/sync/src/l2.rs @@ -3,7 +3,6 @@ use crate::fetch::fetchers::fetch_pending_block_and_updates; use crate::fetch::fetchers::WarpUpdateConfig; use crate::fetch::l2_fetch_task; use crate::fetch::L2FetchConfig; -use crate::utils::trim_hash; use anyhow::Context; use futures::{stream, StreamExt}; use mc_block_import::{ @@ -17,6 +16,7 @@ use mp_block::BlockId; use mp_block::BlockTag; use mp_gateway::error::SequencerError; use mp_utils::service::ServiceContext; +use mp_utils::trim_hash; use mp_utils::PerfStopwatch; use starknet_api::core::ChainId; use starknet_types_core::felt::Felt; diff --git a/crates/client/sync/src/lib.rs b/crates/client/sync/src/lib.rs index 588ed353b..2cda8af8c 100644 --- a/crates/client/sync/src/lib.rs +++ b/crates/client/sync/src/lib.rs @@ -15,7 +15,6 @@ pub mod l2; pub mod metrics; #[cfg(test)] pub mod tests; -pub mod utils; pub struct SyncConfig { pub block_importer: Arc, diff --git a/crates/client/sync/src/utils.rs b/crates/client/sync/src/utils.rs deleted file mode 100644 index 04330745a..000000000 --- a/crates/client/sync/src/utils.rs +++ /dev/null @@ -1,13 +0,0 @@ -use starknet_types_core::felt::Felt; - -pub fn trim_hash(hash: &Felt) -> String { - let hash_str = format!("{:#x}", hash); - - if hash_str.len() <= 12 { - hash_str.to_string() - } else { - let prefix = &hash_str[..6]; - let suffix = &hash_str[hash_str.len() - 6..]; - format!("{}...{}", prefix, suffix) - } -} diff --git a/crates/primitives/utils/src/hash.rs b/crates/primitives/utils/src/hash.rs new file mode 100644 index 000000000..d88ddfe11 --- /dev/null +++ b/crates/primitives/utils/src/hash.rs @@ -0,0 +1,39 @@ +use starknet_types_core::felt::Felt; + +/// Formats a hash as a shortened hexadecimal string with prefix and suffix. +/// +/// If the hash string is 12 characters or shorter, returns the full string. +/// Otherwise, returns a string in the format "0xabcd...ef1234" where the middle +/// is replaced with "...". +/// +/// # Arguments +/// * `hash` - The Felt hash to format +/// +/// # Returns +/// A formatted string representation of the hash +pub fn trim_hash(hash: &Felt) -> String { + let hash_str = format!("{:#x}", hash); + + if hash_str.len() <= 12 { + hash_str + } else { + let prefix = &hash_str[..6]; + let suffix = &hash_str[hash_str.len() - 6..]; + format!("{}...{}", prefix, suffix) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rstest::*; + + #[rstest] + #[case(0, "0x0")] + #[case(30000000000000, "0x1b48...57e000")] + #[case(12345678123456789, "0x2bdc...0f5915")] + fn trim_hash_works(#[case] input: u128, #[case] expected: &str) { + let trimmed = trim_hash(&Felt::from(input)); + assert_eq!(trimmed, expected); + } +} diff --git a/crates/primitives/utils/src/lib.rs b/crates/primitives/utils/src/lib.rs index d38d5098c..0e4886a9a 100644 --- a/crates/primitives/utils/src/lib.rs +++ b/crates/primitives/utils/src/lib.rs @@ -1,12 +1,14 @@ #![allow(clippy::new_without_default)] pub mod crypto; +pub mod hash; pub mod parsers; pub mod serde; pub mod service; - use std::time::{Duration, Instant}; +pub use hash::trim_hash; + use tokio::sync::oneshot; /// Prefer this compared to [`tokio::spawn_blocking`], as spawn_blocking creates new OS threads and From 34d629c460a99c731eb71cb4c0603d760dc30a62 Mon Sep 17 00:00:00 2001 From: Mohit Dhattarwal <48082542+Mohiiit@users.noreply.github.com> Date: Mon, 23 Dec 2024 18:24:58 +0530 Subject: [PATCH 2/2] Feat: Replace Class Hash issue resolved, gas fees bug resolved, cap removed for pending tick (#409) Co-authored-by: mohiiit Co-authored-by: Charpa <102919164+jbcaron@users.noreply.github.com> --- CHANGELOG.md | 2 + cairo/README.md | 2 +- .../src/finalize_execution_state.rs | 5 +- crates/client/block_production/src/lib.rs | 234 ++++++++++-------- crates/client/devnet/src/lib.rs | 35 ++- crates/client/mempool/src/l1.rs | 6 + 6 files changed, 168 insertions(+), 116 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d2f7463f..852abc649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Next release +- feat: block resource cap removed from the pending tick +- fix: replace class hash issue resolved + gas fees issue resolved - fix: trim hash of eth state was failing with 0x0 - fix: devnet accounts getting deployed in sequencer mode - fix(rpc): fix BroadcastedDeclareTxn V3 in starknet-types-rpc diff --git a/cairo/README.md b/cairo/README.md index 8f46c5a50..e94190c07 100644 --- a/cairo/README.md +++ b/cairo/README.md @@ -3,5 +3,5 @@ These contracts are used for the genesis block in devnet mode. For real world use, the [madara bootstrapper] is used instead. We use [OpenZeppelin] contracts. -[OpenZeppelin]: https://docs.openzeppelin.com +[openzeppelin]: https://docs.openzeppelin.com [madara bootstrapper]: https://github.com/madara-alliance/madara-bootstrapper diff --git a/crates/client/block_production/src/finalize_execution_state.rs b/crates/client/block_production/src/finalize_execution_state.rs index 50a0b2935..6c4242a10 100644 --- a/crates/client/block_production/src/finalize_execution_state.rs +++ b/crates/client/block_production/src/finalize_execution_state.rs @@ -70,7 +70,10 @@ pub(crate) fn state_map_to_state_diff( let mut replaced_classes = Vec::new(); for (contract_address, new_class_hash) in diff.class_hashes { let replaced = if let Some(on_top_of) = on_top_of { - backend.get_contract_class_hash_at(on_top_of, &contract_address.to_felt())?.is_some() + match backend.get_contract_class_hash_at(on_top_of, &contract_address.to_felt())? { + Some(class_hash) => class_hash != new_class_hash.to_felt(), + None => false, + } } else { // Executing genesis block: nothing being redefined here false diff --git a/crates/client/block_production/src/lib.rs b/crates/client/block_production/src/lib.rs index 688b17826..81e18645c 100644 --- a/crates/client/block_production/src/lib.rs +++ b/crates/client/block_production/src/lib.rs @@ -18,7 +18,7 @@ use crate::close_block::close_block; use crate::metrics::BlockProductionMetrics; use blockifier::blockifier::transaction_executor::{TransactionExecutor, BLOCK_STATE_ACCESS_ERR}; -use blockifier::bouncer::{BouncerWeights, BuiltinCount}; +use blockifier::bouncer::BouncerWeights; use blockifier::transaction::errors::TransactionExecutionError; use finalize_execution_state::StateDiffToStateMapError; use mc_block_import::{BlockImportError, BlockImporter}; @@ -77,6 +77,29 @@ pub enum Error { #[error("State diff error when continuing the pending block: {0:#}")] PendingStateDiff(#[from] StateDiffToStateMapError), } + +/// Result of a block continuation operation, containing the updated state and execution statistics. +/// This is returned by [`BlockProductionTask::continue_block`] when processing a batch of transactions. +struct ContinueBlockResult { + /// The accumulated state changes from executing transactions in this continuation + state_diff: StateDiff, + + /// Tracks which segments of Cairo program code were accessed during transaction execution, + /// organized by class hash. This information is used as input for SNOS (Starknet OS) + /// when generating proofs of execution. + visited_segments: VisitedSegments, + + /// The current state of resource consumption tracked by the bouncer + bouncer_weights: BouncerWeights, + + /// Statistics about transaction processing during this continuation + stats: ContinueBlockStats, + + /// Indicates whether the block reached its resource limits during this continuation. + /// When true, no more transactions can be added to the current block. + block_now_full: bool, +} + /// The block production task consumes transactions from the mempool in batches. /// This is to allow optimistic concurrency. However, the block may get full during batch execution, /// and we need to re-add the transactions back into the mempool. @@ -165,11 +188,9 @@ impl BlockProductionTask { } #[tracing::instrument(skip(self), fields(module = "BlockProductionTask"))] - fn continue_block( - &mut self, - bouncer_cap: BouncerWeights, - ) -> Result<(StateDiff, VisitedSegments, BouncerWeights, ContinueBlockStats), Error> { + fn continue_block(&mut self, bouncer_cap: BouncerWeights) -> Result { let mut stats = ContinueBlockStats::default(); + let mut block_now_full = false; self.executor.bouncer.bouncer_config.block_max_capacity = bouncer_cap; let batch_size = self.backend.chain_config().execution_batch_size; @@ -201,7 +222,7 @@ impl BlockProductionTask { // Execute the transactions. let all_results = self.executor.execute_txs(&txs_to_process_blockifier); // When the bouncer cap is reached, blockifier will return fewer results than what we asked for. - let block_now_full = all_results.len() < txs_to_process_blockifier.len(); + block_now_full = all_results.len() < txs_to_process_blockifier.len(); txs_to_process_blockifier.drain(..all_results.len()); // remove the used txs @@ -273,54 +294,85 @@ impl BlockProductionTask { stats.n_re_added_to_mempool ); - Ok((state_diff, visited_segments, bouncer_weights, stats)) + Ok(ContinueBlockResult { state_diff, visited_segments, bouncer_weights, stats, block_now_full }) + } + + /// Closes the current block and prepares for the next one + #[tracing::instrument(skip(self), fields(module = "BlockProductionTask"))] + async fn close_and_prepare_next_block( + &mut self, + state_diff: StateDiff, + visited_segments: VisitedSegments, + start_time: Instant, + ) -> Result<(), Error> { + let block_n = self.block_n(); + // Convert the pending block to a closed block and save to db + let parent_block_hash = Felt::ZERO; // temp parent block hash + let new_empty_block = MadaraPendingBlock::new_empty(make_pending_header( + parent_block_hash, + self.backend.chain_config(), + self.l1_data_provider.as_ref(), + )); + + let block_to_close = mem::replace(&mut self.block, new_empty_block); + let declared_classes = mem::take(&mut self.declared_classes); + + let n_txs = block_to_close.inner.transactions.len(); + + // Close and import the block + let import_result = close_block( + &self.importer, + block_to_close, + &state_diff, + self.backend.chain_config().chain_id.clone(), + block_n, + declared_classes, + visited_segments, + ) + .await?; + + // Flush changes to disk + self.backend.flush().map_err(|err| BlockImportError::Internal(format!("DB flushing error: {err:#}").into()))?; + + // Update parent hash for new pending block + self.block.info.header.parent_block_hash = import_result.block_hash; + + // Prepare executor for next block + self.executor = + ExecutionContext::new_in_block(Arc::clone(&self.backend), &self.block.info.clone().into())?.tx_executor(); + self.current_pending_tick = 0; + + let end_time = start_time.elapsed(); + tracing::info!("⛏️ Closed block #{} with {} transactions - {:?}", block_n, n_txs, end_time); + + // Record metrics + let attributes = [ + KeyValue::new("transactions_added", n_txs.to_string()), + KeyValue::new("closing_time", end_time.as_secs_f32().to_string()), + ]; + + self.metrics.block_counter.add(1, &[]); + self.metrics.block_gauge.record(block_n, &attributes); + self.metrics.transaction_counter.add(n_txs as u64, &[]); + + Ok(()) } - /// Each "tick" of the block time updates the pending block but only with the appropriate fraction of the total bouncer capacity. #[tracing::instrument(skip(self), fields(module = "BlockProductionTask"))] - pub fn on_pending_time_tick(&mut self) -> Result<(), Error> { + pub async fn on_pending_time_tick(&mut self) -> Result { let current_pending_tick = self.current_pending_tick; - let n_pending_ticks_per_block = self.backend.chain_config().n_pending_ticks_per_block(); - let config_bouncer = self.backend.chain_config().bouncer_config.block_max_capacity; if current_pending_tick == 0 { - return Ok(()); + return Ok(false); } - // Reduced bouncer capacity for the current pending tick - - // reduced_gas = gas * current_pending_tick/n_pending_ticks_per_block - // - we're dealing with integers here so prefer having the division last - // - use u128 here because the multiplication would overflow - // - div by zero: see [`ChainConfig::precheck_block_production`] - let reduced_cap = - |v: usize| (v as u128 * current_pending_tick as u128 / n_pending_ticks_per_block as u128) as usize; - - let gas = reduced_cap(config_bouncer.gas); - let frac = current_pending_tick as f64 / n_pending_ticks_per_block as f64; - tracing::debug!("begin pending tick {current_pending_tick}/{n_pending_ticks_per_block}, proportion for this tick: {frac:.2}, gas limit: {gas}/{}", config_bouncer.gas); - - let bouncer_cap = BouncerWeights { - builtin_count: BuiltinCount { - add_mod: reduced_cap(config_bouncer.builtin_count.add_mod), - bitwise: reduced_cap(config_bouncer.builtin_count.bitwise), - ecdsa: reduced_cap(config_bouncer.builtin_count.ecdsa), - ec_op: reduced_cap(config_bouncer.builtin_count.ec_op), - keccak: reduced_cap(config_bouncer.builtin_count.keccak), - mul_mod: reduced_cap(config_bouncer.builtin_count.mul_mod), - pedersen: reduced_cap(config_bouncer.builtin_count.pedersen), - poseidon: reduced_cap(config_bouncer.builtin_count.poseidon), - range_check: reduced_cap(config_bouncer.builtin_count.range_check), - range_check96: reduced_cap(config_bouncer.builtin_count.range_check96), - }, - gas, - message_segment_length: reduced_cap(config_bouncer.message_segment_length), - n_events: reduced_cap(config_bouncer.n_events), - n_steps: reduced_cap(config_bouncer.n_steps), - state_diff_size: reduced_cap(config_bouncer.state_diff_size), - }; + // Use full bouncer capacity + let bouncer_cap = self.backend.chain_config().bouncer_config.block_max_capacity; let start_time = Instant::now(); - let (state_diff, visited_segments, bouncer_weights, stats) = self.continue_block(bouncer_cap)?; + + let ContinueBlockResult { state_diff, visited_segments, bouncer_weights, stats, block_now_full } = + self.continue_block(bouncer_cap)?; + if stats.n_added_to_block > 0 { tracing::info!( "🧮 Executed and added {} transaction(s) to the pending block at height {} - {:?}", @@ -330,6 +382,13 @@ impl BlockProductionTask { ); } + // Check if block is full + if block_now_full { + tracing::info!("Resource limits reached, closing block early"); + self.close_and_prepare_next_block(state_diff, visited_segments, start_time).await?; + return Ok(true); + } + // Store pending block // todo, prefer using the block import pipeline? self.backend.store_block( @@ -342,7 +401,7 @@ impl BlockProductionTask { // do not forget to flush :) self.backend.flush().map_err(|err| BlockImportError::Internal(format!("DB flushing error: {err:#}").into()))?; - Ok(()) + Ok(false) } /// This creates a block, continuing the current pending block state up to the full bouncer limit. @@ -351,10 +410,15 @@ impl BlockProductionTask { let block_n = self.block_n(); tracing::debug!("closing block #{}", block_n); - // Complete the block with full bouncer capacity. + // Complete the block with full bouncer capacity let start_time = Instant::now(); - let (mut new_state_diff, visited_segments, _weights, _stats) = - self.continue_block(self.backend.chain_config().bouncer_config.block_max_capacity)?; + let ContinueBlockResult { + state_diff: mut new_state_diff, + visited_segments, + bouncer_weights: _weights, + stats: _stats, + block_now_full: _block_now_full, + } = self.continue_block(self.backend.chain_config().bouncer_config.block_max_capacity)?; // SNOS requirement: For blocks >= 10, the hash of the block 10 blocks prior // at address 0x1 with the block number as the key @@ -371,62 +435,14 @@ impl BlockProductionTask { .ok_or_else(|| { Error::Unexpected(format!("No block hash found for block number {prev_block_number}").into()) })?; - let address = Felt::ONE; + new_state_diff.storage_diffs.push(ContractStorageDiffItem { - address, + address: Felt::ONE, storage_entries: vec![StorageEntry { key: Felt::from(prev_block_number), value: prev_block_hash }], }); } - // Convert the pending block to a closed block and save to db. - - let parent_block_hash = Felt::ZERO; // temp parent block hash - let new_empty_block = MadaraPendingBlock::new_empty(make_pending_header( - parent_block_hash, - self.backend.chain_config(), - self.l1_data_provider.as_ref(), - )); - - let block_to_close = mem::replace(&mut self.block, new_empty_block); - let declared_classes = mem::take(&mut self.declared_classes); - - let n_txs = block_to_close.inner.transactions.len(); - - // This is compute heavy as it does the commitments and trie computations. - let import_result = close_block( - &self.importer, - block_to_close, - &new_state_diff, - self.backend.chain_config().chain_id.clone(), - block_n, - declared_classes, - visited_segments, - ) - .await?; - // do not forget to flush :) - self.backend.flush().map_err(|err| BlockImportError::Internal(format!("DB flushing error: {err:#}").into()))?; - - // fix temp parent block hash for new pending :) - self.block.info.header.parent_block_hash = import_result.block_hash; - - // Prepare for next block. - self.executor = - ExecutionContext::new_in_block(Arc::clone(&self.backend), &self.block.info.clone().into())?.tx_executor(); - self.current_pending_tick = 0; - - let end_time = start_time.elapsed(); - tracing::info!("⛏️ Closed block #{} with {} transactions - {:?}", block_n, n_txs, end_time); - - let attributes = [ - KeyValue::new("transactions_added", n_txs.to_string()), - KeyValue::new("closing_time", end_time.as_secs_f32().to_string()), - ]; - - self.metrics.block_counter.add(1, &[]); - self.metrics.block_gauge.record(block_n, &attributes); - self.metrics.transaction_counter.add(n_txs as u64, &[]); - - Ok(()) + self.close_and_prepare_next_block(new_state_diff, visited_segments, start_time).await } #[tracing::instrument(skip(self, ctx), fields(module = "BlockProductionTask"))] @@ -463,7 +479,7 @@ impl BlockProductionTask { // ensure the pending block tick and block time match up interval_pending_block_update.reset_at(instant + interval_pending_block_update.period()); }, - _ = interval_pending_block_update.tick() => { + instant = interval_pending_block_update.tick() => { let n_pending_ticks_per_block = self.backend.chain_config().n_pending_ticks_per_block(); if self.current_pending_tick == 0 || self.current_pending_tick >= n_pending_ticks_per_block { @@ -473,10 +489,20 @@ impl BlockProductionTask { continue } - if let Err(err) = self.on_pending_time_tick() { - tracing::error!("Pending block update task has errored: {err:#}"); + match self.on_pending_time_tick().await { + Ok(block_closed) => { + if block_closed { + interval_pending_block_update.reset_at(instant + interval_pending_block_update.period()); + interval_block_time.reset_at(instant + interval_block_time.period()); + self.current_pending_tick = 0; + } else { + self.current_pending_tick += 1; + } + } + Err(err) => { + tracing::error!("Pending block update task has errored: {err:#}"); + } } - self.current_pending_tick += 1; }, _ = ctx.cancelled() => break, } diff --git a/crates/client/devnet/src/lib.rs b/crates/client/devnet/src/lib.rs index 1be4f1929..f62be8c00 100644 --- a/crates/client/devnet/src/lib.rs +++ b/crates/client/devnet/src/lib.rs @@ -384,8 +384,11 @@ mod tests { assert_eq!(res.class_hash, calculated_class_hash); - chain.block_production.set_current_pending_tick(1); - chain.block_production.on_pending_time_tick().unwrap(); + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + chain.block_production.set_current_pending_tick(1); + chain.block_production.on_pending_time_tick().await.unwrap(); + }); let block = chain.backend.get_block(&BlockId::Tag(BlockTag::Pending)).unwrap().unwrap(); @@ -453,8 +456,11 @@ mod tests { .unwrap(); tracing::debug!("tx hash: {:#x}", transfer_txn.transaction_hash); - chain.block_production.set_current_pending_tick(chain.backend.chain_config().n_pending_ticks_per_block()); - chain.block_production.on_pending_time_tick().unwrap(); + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + chain.block_production.set_current_pending_tick(chain.backend.chain_config().n_pending_ticks_per_block()); + chain.block_production.on_pending_time_tick().await.unwrap(); + }); // ===================================================================================== @@ -485,8 +491,11 @@ mod tests { let res = chain.sign_and_add_deploy_account_tx(deploy_account_txn, &account).unwrap(); - chain.block_production.set_current_pending_tick(chain.backend.chain_config().n_pending_ticks_per_block()); - chain.block_production.on_pending_time_tick().unwrap(); + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + chain.block_production.set_current_pending_tick(chain.backend.chain_config().n_pending_ticks_per_block()); + chain.block_production.on_pending_time_tick().await.unwrap(); + }); assert_eq!(res.contract_address, account.address); @@ -546,8 +555,11 @@ mod tests { tracing::info!("tx hash: {:#x}", result.transaction_hash); - chain.block_production.set_current_pending_tick(1); - chain.block_production.on_pending_time_tick().unwrap(); + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + chain.block_production.set_current_pending_tick(1); + chain.block_production.on_pending_time_tick().await.unwrap(); + }); let block = chain.backend.get_block(&BlockId::Tag(BlockTag::Pending)).unwrap().unwrap(); @@ -752,8 +764,11 @@ mod tests { .unwrap(); std::thread::sleep(max_age); // max age reached - chain.block_production.set_current_pending_tick(1); - chain.block_production.on_pending_time_tick().unwrap(); + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + chain.block_production.set_current_pending_tick(1); + chain.block_production.on_pending_time_tick().await.unwrap(); + }); let block = chain.backend.get_block(&BlockId::Tag(BlockTag::Pending)).unwrap().unwrap(); diff --git a/crates/client/mempool/src/l1.rs b/crates/client/mempool/src/l1.rs index 716cc9cc6..c2ef9c610 100644 --- a/crates/client/mempool/src/l1.rs +++ b/crates/client/mempool/src/l1.rs @@ -7,8 +7,14 @@ use std::time::SystemTime; #[derive(Clone)] pub struct GasPriceProvider { + /// Gas prices protected by a mutex gas_prices: Arc>, last_update: Arc>, + /// Using Relaxed ordering for atomic operations since: + /// 1. Gas prices are updated frequently (every few ms) + /// 2. Slight inconsistencies in gas price visibility between threads are acceptable + /// 3. Operations are independent and don't require synchronization with other memory operations + /// 4. Provides minimal performance overhead compared to stricter ordering options gas_price_sync_enabled: Arc, data_gas_price_sync_enabled: Arc, strk_gas_price_sync_enabled: Arc,