From 8107c2903ec28840ee0fc8df051b69a6741b1a3e Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:22:29 +0300 Subject: [PATCH 01/53] starknet_api: redact Proof and decode ProofFacts in Debug output (#14598) --- crates/starknet_api/src/transaction/fields.rs | 15 ++++++++++--- .../src/transaction/fields_test.rs | 21 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/crates/starknet_api/src/transaction/fields.rs b/crates/starknet_api/src/transaction/fields.rs index 62ee072d150..e2f1ee98eaf 100644 --- a/crates/starknet_api/src/transaction/fields.rs +++ b/crates/starknet_api/src/transaction/fields.rs @@ -696,11 +696,18 @@ pub const VIRTUAL_OS_OUTPUT_VERSION: Felt = /// Client-provided proof facts used for client-side proving. /// Only needed when the client supplies a proof; otherwise empty. -#[derive( - Clone, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, SizeOf, -)] +#[derive(Clone, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, SizeOf)] pub struct ProofFacts(pub Arc>); +impl fmt::Debug for ProofFacts { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match ProofFactsVariant::try_from(self) { + Ok(variant) => write!(f, "ProofFacts({variant:?})"), + Err(_) => write!(f, "ProofFacts([<{} elements>])", self.0.len()), + } + } +} + impl ProofFacts { pub fn is_empty(&self) -> bool { self.0.is_empty() @@ -716,6 +723,7 @@ impl ProofFacts { /// Currently, only SNOS proof facts are supported. /// The `Empty` variant indicates that the transaction does not utilize the client-side proving /// feature. +#[derive(Debug)] pub enum ProofFactsVariant { Empty, Snos(SnosProofFacts), @@ -795,6 +803,7 @@ impl TryFrom<&ProofFacts> for ProofFactsVariant { /// Contains the required fields for valid SNOS proof facts. /// /// A valid SNOS proof facts structure must include these fields as its first five entries. +#[derive(Debug)] pub struct SnosProofFacts { pub proof_version: ProofVersion, pub program_hash: StarkHash, diff --git a/crates/starknet_api/src/transaction/fields_test.rs b/crates/starknet_api/src/transaction/fields_test.rs index db49c9ef780..072d094b1a2 100644 --- a/crates/starknet_api/src/transaction/fields_test.rs +++ b/crates/starknet_api/src/transaction/fields_test.rs @@ -40,3 +40,24 @@ fn proof_version_str_encodes_to_felt() { assert_eq!(from_short_string, version.as_felt()); } } + +#[test] +fn proof_facts_debug_decodes_snos_without_dumping_felts() { + let debug = format!("{:?}", ProofFacts::snos_proof_facts_for_testing()); + // Decoded via the variant's derived `Debug`, not the raw-felt length fallback. + assert!(debug.starts_with("ProofFacts(Snos(SnosProofFacts {"), "got: {debug}"); + assert!(debug.contains("proof_version: V1"), "got: {debug}"); + assert!(debug.contains("block_number: BlockNumber("), "got: {debug}"); + assert!(!debug.contains("elements"), "should not hit the fallback: {debug}"); +} + +#[test] +fn proof_facts_debug_empty() { + assert_eq!(format!("{:?}", ProofFacts::default()), "ProofFacts(Empty)"); +} + +#[test] +fn proof_facts_debug_falls_back_for_unparseable() { + let facts = ProofFacts(Arc::new(vec![Felt::from_hex_unchecked("0xDEAD")])); + assert_eq!(format!("{:?}", facts), "ProofFacts([<1 elements>])"); +} From 05881e6c56812ba070a64bf9412bd43b2fe7e830 Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Tue, 30 Jun 2026 17:39:23 +0300 Subject: [PATCH 02/53] starknet_transaction_prover: bounded request queue for prove_transaction (#14664) Replace the immediate try_acquire load-shed with a bounded FIFO queue: when all workers are busy, a request waits its turn for a slot instead of being rejected the instant the prover is at capacity. - Two semaphores: admission caps total in-flight (running + waiting) so the queue can't grow without bound; concurrency caps actual provers. - Admission returns -32005 only when the queue is full. - Admitted requests wait FIFO (tokio's Semaphore is fair) for a worker slot, up to a backstop queue_wait_timeout (default 30s, ~the client timeout) so a stuck worker can't pin a waiter's connection; otherwise served in arrival order, or cancelled if the client disconnects. New config max_queued_requests (default 8, the primary shedding knob) and queue_wait_timeout_millis (default 30_000, backstop only); max_queued = 0 reproduces the previous immediate-reject behavior. -32005 still composes with the SDK's retry. Co-authored-by: Claude Opus 4.8 (1M context) --- .../src/server/config.rs | 53 +++++++++++++++++++ .../src/server/config_test.rs | 4 ++ .../src/server/rpc_impl.rs | 50 ++++++++++++++--- .../src/server/rpc_spec_test.rs | 8 ++- 4 files changed, 107 insertions(+), 8 deletions(-) diff --git a/crates/starknet_transaction_prover/src/server/config.rs b/crates/starknet_transaction_prover/src/server/config.rs index 034177e8481..d5db2fcb614 100644 --- a/crates/starknet_transaction_prover/src/server/config.rs +++ b/crates/starknet_transaction_prover/src/server/config.rs @@ -26,6 +26,10 @@ mod config_test; const DEFAULT_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); const DEFAULT_PORT: u16 = 3000; const DEFAULT_MAX_CONCURRENT_REQUESTS: usize = 2; +/// Default 8 so total in-flight (2 + 8) matches the default `max_connections` (10). +const DEFAULT_MAX_QUEUED_REQUESTS: usize = 8; +/// Backstop (≈ the client request timeout), not the primary shed — the queue length is. +const DEFAULT_QUEUE_WAIT_TIMEOUT_MILLIS: u64 = 30_000; const DEFAULT_MAX_CONNECTIONS: u32 = 10; const DEFAULT_COMPILED_CLASS_CACHE_SIZE: usize = 600; /// 5 MiB — matches the convention used elsewhere in the sequencer. @@ -86,6 +90,8 @@ struct RawServiceConfig { ip: IpAddr, port: u16, max_concurrent_requests: usize, + max_queued_requests: usize, + queue_wait_timeout_millis: u64, max_connections: u32, cors_allow_origin: Vec, tls_cert_file: Option, @@ -111,6 +117,8 @@ impl Default for RawServiceConfig { ip: DEFAULT_IP, port: DEFAULT_PORT, max_concurrent_requests: DEFAULT_MAX_CONCURRENT_REQUESTS, + max_queued_requests: DEFAULT_MAX_QUEUED_REQUESTS, + queue_wait_timeout_millis: DEFAULT_QUEUE_WAIT_TIMEOUT_MILLIS, max_connections: DEFAULT_MAX_CONNECTIONS, cors_allow_origin: Vec::new(), tls_cert_file: None, @@ -136,6 +144,12 @@ pub struct ServiceConfig { pub port: u16, /// Maximum number of concurrent proving requests. pub max_concurrent_requests: usize, + /// Requests that may wait FIFO for a worker slot beyond `max_concurrent_requests`. When this + /// buffer is full, requests are rejected with `-32005` (busy); `0` rejects the moment all + /// workers are busy. + pub max_queued_requests: usize, + /// Backstop (ms) a queued request waits for a worker slot before a `-32005` rejection. + pub queue_wait_timeout_millis: u64, /// Maximum number of simultaneous JSON-RPC connections (safety net). pub max_connections: u32, /// List of allowed web origins (domains) that may call this HTTP service from a browser @@ -222,6 +236,24 @@ impl ServiceConfig { config.max_concurrent_requests = max; } } + if let Some(max) = args.max_queued_requests { + if max != config.max_queued_requests { + info!( + "CLI override: max_queued_requests: {} -> {}", + config.max_queued_requests, max + ); + config.max_queued_requests = max; + } + } + if let Some(millis) = args.queue_wait_timeout_millis { + if millis != config.queue_wait_timeout_millis { + info!( + "CLI override: queue_wait_timeout_millis: {} -> {}", + config.queue_wait_timeout_millis, millis + ); + config.queue_wait_timeout_millis = millis; + } + } if let Some(max) = args.max_connections { if max != config.max_connections { info!("CLI override: max_connections: {} -> {}", config.max_connections, max); @@ -397,6 +429,16 @@ impl ServiceConfig { "max_connections must be at least 1".to_string(), )); } + // Waiting requests hold a connection, so queue depth is capped by max_connections. + let max_in_flight = + config.max_concurrent_requests.saturating_add(config.max_queued_requests); + if max_in_flight > usize::try_from(config.max_connections).unwrap_or(usize::MAX) { + info!( + "max_concurrent_requests ({}) + max_queued_requests ({}) exceeds max_connections \ + ({}); queue depth is effectively capped by max_connections", + config.max_concurrent_requests, config.max_queued_requests, config.max_connections, + ); + } if config.max_request_body_size == 0 { return Err(ConfigError::InvalidArgument( "max_request_body_size must be at least 1".to_string(), @@ -458,6 +500,8 @@ impl ServiceConfig { ip: config.ip, port: config.port, max_concurrent_requests: config.max_concurrent_requests, + max_queued_requests: config.max_queued_requests, + queue_wait_timeout_millis: config.queue_wait_timeout_millis, max_connections: config.max_connections, cors_allow_origin, transport, @@ -497,6 +541,15 @@ pub struct CliArgs { #[arg(long, value_name = "N", env = "MAX_CONCURRENT_REQUESTS")] pub max_concurrent_requests: Option, + /// Requests that may wait for a worker slot beyond --max-concurrent-requests (default: 8; 0 = + /// reject immediately). + #[arg(long, value_name = "N", env = "MAX_QUEUED_REQUESTS")] + pub max_queued_requests: Option, + + /// Backstop ms a queued request waits for a slot before a busy rejection (default: 30000). + #[arg(long, value_name = "MILLIS", env = "QUEUE_WAIT_TIMEOUT_MILLIS")] + pub queue_wait_timeout_millis: Option, + /// Maximum number of simultaneous JSON-RPC connections (default: 10). #[arg(long, value_name = "N", env = "MAX_CONNECTIONS")] pub max_connections: Option, diff --git a/crates/starknet_transaction_prover/src/server/config_test.rs b/crates/starknet_transaction_prover/src/server/config_test.rs index c8ccad8a0a0..fc800836e65 100644 --- a/crates/starknet_transaction_prover/src/server/config_test.rs +++ b/crates/starknet_transaction_prover/src/server/config_test.rs @@ -42,6 +42,8 @@ fn base_args() -> CliArgs { port: None, ip: None, max_concurrent_requests: None, + max_queued_requests: None, + queue_wait_timeout_millis: None, max_connections: None, tls_cert_file: None, tls_key_file: None, @@ -131,6 +133,8 @@ fn cors_allow_origin_rejects_non_array_in_config_file() { port: None, ip: None, max_concurrent_requests: None, + max_queued_requests: None, + queue_wait_timeout_millis: None, max_connections: None, tls_cert_file: None, tls_key_file: None, diff --git a/crates/starknet_transaction_prover/src/server/rpc_impl.rs b/crates/starknet_transaction_prover/src/server/rpc_impl.rs index 47e9eedefbf..71eb158b02f 100644 --- a/crates/starknet_transaction_prover/src/server/rpc_impl.rs +++ b/crates/starknet_transaction_prover/src/server/rpc_impl.rs @@ -1,6 +1,7 @@ //! JSON-RPC trait implementation for the proving service. use std::sync::Arc; +use std::time::Duration; use async_trait::async_trait; use blockifier_reexecution::state_reader::rpc_objects::BlockId; @@ -8,11 +9,12 @@ use jsonrpsee::core::RpcResult; use jsonrpsee::types::ErrorObjectOwned; use starknet_api::rpc_transaction::RpcTransaction; use tokio::sync::Semaphore; +use tokio::time::timeout; use tracing::warn; use crate::proving::virtual_snos_prover::{ProveTransactionResult, RpcVirtualSnosProver}; use crate::server::config::ServiceConfig; -use crate::server::errors::service_busy; +use crate::server::errors::{internal_server_error, service_busy}; use crate::server::rpc_api::ProvingRpcServer; /// Starknet RPC specification version (matches the pinned `starknet_specs_rev`). @@ -22,26 +24,44 @@ pub(crate) const SPEC_VERSION: &str = "0.10.3-rc.2"; #[derive(Clone)] pub struct ProvingRpcServerImpl { prover: RpcVirtualSnosProver, - /// Limits how many proving requests can run concurrently. + /// Worker slots: how many requests prove concurrently. concurrency_semaphore: Arc, + /// Total in-flight cap (running + waiting); sized `max_concurrent + max_queued`. + admission_semaphore: Arc, /// Configured max concurrent requests (used in error messages). max_concurrent_requests: usize, + /// Backstop on the FIFO wait so a stuck worker can't pin a waiter's connection indefinitely. + queue_wait_timeout: Duration, } impl ProvingRpcServerImpl { /// Creates a new ProvingRpcServerImpl from a prover. - pub(crate) fn new(prover: RpcVirtualSnosProver, max_concurrent_requests: usize) -> Self { + pub(crate) fn new( + prover: RpcVirtualSnosProver, + max_concurrent_requests: usize, + max_queued_requests: usize, + queue_wait_timeout: Duration, + ) -> Self { Self { prover, concurrency_semaphore: Arc::new(Semaphore::new(max_concurrent_requests)), + admission_semaphore: Arc::new(Semaphore::new( + max_concurrent_requests + max_queued_requests, + )), max_concurrent_requests, + queue_wait_timeout, } } /// Creates a new ProvingRpcServerImpl from configuration. pub fn from_config(config: &ServiceConfig) -> Self { let prover = RpcVirtualSnosProver::new(&config.prover_config); - Self::new(prover, config.max_concurrent_requests) + Self::new( + prover, + config.max_concurrent_requests, + config.max_queued_requests, + Duration::from_millis(config.queue_wait_timeout_millis), + ) } } @@ -56,14 +76,32 @@ impl ProvingRpcServer for ProvingRpcServerImpl { block_id: BlockId, transaction: RpcTransaction, ) -> RpcResult { - let _permit = self.concurrency_semaphore.try_acquire().map_err(|_| { + // Admission: cap queue length (running + waiting). Reject with -32005 only when the queue + // is full; held for the whole request, so a client disconnect frees the slot. + let _admission = self.admission_semaphore.try_acquire().map_err(|_| { warn!( max_concurrent_requests = self.max_concurrent_requests, - "Rejected proving request: service is at capacity" + "Rejected proving request: queue is full" ); service_busy(self.max_concurrent_requests) })?; + // Wait FIFO for a worker slot (tokio's Semaphore is fair), with queue_wait_timeout as a + // backstop. Served in arrival order, or cancelled if the client disconnects. + let _permit = match timeout(self.queue_wait_timeout, self.concurrency_semaphore.acquire()) + .await + { + Ok(Ok(permit)) => permit, + Ok(Err(_)) => return Err(internal_server_error("proving service is shutting down")), + Err(_) => { + warn!( + max_concurrent_requests = self.max_concurrent_requests, + "Rejected proving request: timed out waiting for a worker slot" + ); + return Err(service_busy(self.max_concurrent_requests)); + } + }; + self.prover.prove_transaction(block_id, transaction).await.map_err(|err| { warn!("prove_transaction failed: {:?}", err); ErrorObjectOwned::from(err) diff --git a/crates/starknet_transaction_prover/src/server/rpc_spec_test.rs b/crates/starknet_transaction_prover/src/server/rpc_spec_test.rs index ff0ea244c83..e706bc503e1 100644 --- a/crates/starknet_transaction_prover/src/server/rpc_spec_test.rs +++ b/crates/starknet_transaction_prover/src/server/rpc_spec_test.rs @@ -122,8 +122,12 @@ static SPEC_ERRORS: LazyLock> = LazyLock::new(|| { fn rpc_module() -> RpcModule { let config = ProverConfig { rpc_node_url: DUMMY_RPC_NODE_URL.to_string(), ..Default::default() }; - let rpc_impl = - ProvingRpcServerImpl::new(RpcVirtualSnosProver::new(&config), TEST_MAX_CONCURRENT_REQUESTS); + let rpc_impl = ProvingRpcServerImpl::new( + RpcVirtualSnosProver::new(&config), + TEST_MAX_CONCURRENT_REQUESTS, + 0, + std::time::Duration::from_secs(30), + ); rpc_impl.into_rpc() } From 6172b0fd93a83ab08fd5e7dadf22e4d2a9533696 Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Wed, 1 Jul 2026 10:10:21 +0300 Subject: [PATCH 03/53] starknet_transaction_prover: extract override_field helper for CLI overrides (#14673) Co-authored-by: Claude Opus 4.8 (1M context) --- .../src/server/config.rs | 162 +++++++----------- 1 file changed, 60 insertions(+), 102 deletions(-) diff --git a/crates/starknet_transaction_prover/src/server/config.rs b/crates/starknet_transaction_prover/src/server/config.rs index d5db2fcb614..d196ac4707b 100644 --- a/crates/starknet_transaction_prover/src/server/config.rs +++ b/crates/starknet_transaction_prover/src/server/config.rs @@ -1,5 +1,6 @@ //! Configuration for the proving service. +use std::fmt::Display; use std::net::{IpAddr, Ipv4Addr}; use std::path::PathBuf; use std::str::FromStr; @@ -168,6 +169,17 @@ pub struct ServiceConfig { pub ohttp_key_cache_max_age_secs: u64, } +/// Applies an optional CLI override to a config field, logging `old -> new` when it changes. +/// Centralizes the repeated per-field override pattern used in `ServiceConfig::from_args`. +fn override_field(name: &str, current: &mut T, new: Option) { + if let Some(value) = new { + if value != *current { + info!("CLI override: {}: {} -> {}", name, *current, value); + *current = value; + } + } +} + impl ServiceConfig { /// Creates a ServiceConfig from CLI arguments. pub fn from_args(args: CliArgs) -> Result { @@ -212,12 +224,7 @@ impl ServiceConfig { config.chain_id = new_chain_id; } } - if let Some(port) = args.port { - if port != config.port { - info!("CLI override: port: {} -> {}", config.port, port); - config.port = port; - } - } + override_field("port", &mut config.port, args.port); if let Some(ip) = args.ip { let new_ip: IpAddr = ip .parse() @@ -227,39 +234,22 @@ impl ServiceConfig { config.ip = new_ip; } } - if let Some(max) = args.max_concurrent_requests { - if max != config.max_concurrent_requests { - info!( - "CLI override: max_concurrent_requests: {} -> {}", - config.max_concurrent_requests, max - ); - config.max_concurrent_requests = max; - } - } - if let Some(max) = args.max_queued_requests { - if max != config.max_queued_requests { - info!( - "CLI override: max_queued_requests: {} -> {}", - config.max_queued_requests, max - ); - config.max_queued_requests = max; - } - } - if let Some(millis) = args.queue_wait_timeout_millis { - if millis != config.queue_wait_timeout_millis { - info!( - "CLI override: queue_wait_timeout_millis: {} -> {}", - config.queue_wait_timeout_millis, millis - ); - config.queue_wait_timeout_millis = millis; - } - } - if let Some(max) = args.max_connections { - if max != config.max_connections { - info!("CLI override: max_connections: {} -> {}", config.max_connections, max); - config.max_connections = max; - } - } + override_field( + "max_concurrent_requests", + &mut config.max_concurrent_requests, + args.max_concurrent_requests, + ); + override_field( + "max_queued_requests", + &mut config.max_queued_requests, + args.max_queued_requests, + ); + override_field( + "queue_wait_timeout_millis", + &mut config.queue_wait_timeout_millis, + args.queue_wait_timeout_millis, + ); + override_field("max_connections", &mut config.max_connections, args.max_connections); if let Some(tls_cert_file) = args.tls_cert_file { if Some(&tls_cert_file) != config.tls_cert_file.as_ref() { info!( @@ -321,35 +311,19 @@ impl ServiceConfig { } } - if let Some(prefetch_state) = args.prefetch_state { - if prefetch_state != config.prefetch_state { - info!( - "CLI override: prefetch_state: {} -> {}", - config.prefetch_state, prefetch_state - ); - config.prefetch_state = prefetch_state; - } - } + override_field("prefetch_state", &mut config.prefetch_state, args.prefetch_state); - if let Some(use_latest) = args.use_latest_versioned_constants { - if use_latest != config.use_latest_versioned_constants { - info!( - "CLI override: use_latest_versioned_constants: {} -> {}", - config.use_latest_versioned_constants, use_latest - ); - config.use_latest_versioned_constants = use_latest; - } - } + override_field( + "use_latest_versioned_constants", + &mut config.use_latest_versioned_constants, + args.use_latest_versioned_constants, + ); - if let Some(compiled_class_cache_size) = args.compiled_class_cache_size { - if compiled_class_cache_size != config.compiled_class_cache_size { - info!( - "CLI override: compiled_class_cache_size: {} -> {}", - config.compiled_class_cache_size, compiled_class_cache_size - ); - config.compiled_class_cache_size = compiled_class_cache_size; - } - } + override_field( + "compiled_class_cache_size", + &mut config.compiled_class_cache_size, + args.compiled_class_cache_size, + ); if let Some(url) = args.blocking_check_url { if Some(&url) != config.blocking_check_url.as_ref() { info!( @@ -363,24 +337,16 @@ impl ServiceConfig { config.blocking_check_url = Some(url); } } - if let Some(timeout) = args.blocking_check_timeout_millis { - if timeout != config.blocking_check_timeout_millis { - info!( - "CLI override: blocking_check_timeout_millis: {} -> {}", - config.blocking_check_timeout_millis, timeout - ); - config.blocking_check_timeout_millis = timeout; - } - } - if let Some(fail_open) = args.blocking_check_fail_open { - if fail_open != config.blocking_check_fail_open { - info!( - "CLI override: blocking_check_fail_open: {} -> {}", - config.blocking_check_fail_open, fail_open - ); - config.blocking_check_fail_open = fail_open; - } - } + override_field( + "blocking_check_timeout_millis", + &mut config.blocking_check_timeout_millis, + args.blocking_check_timeout_millis, + ); + override_field( + "blocking_check_fail_open", + &mut config.blocking_check_fail_open, + args.blocking_check_fail_open, + ); // Validate blocking check URL early so an invalid value surfaces as a clean config error // instead of a panic at prover construction time. @@ -389,29 +355,21 @@ impl ServiceConfig { ConfigError::InvalidArgument(format!("Invalid blocking_check_url: {e}")) })?; } - if let Some(max_request_body_size) = args.max_request_body_size { - if max_request_body_size != config.max_request_body_size { - info!( - "CLI override: max_request_body_size: {} -> {}", - config.max_request_body_size, max_request_body_size - ); - config.max_request_body_size = max_request_body_size; - } - } + override_field( + "max_request_body_size", + &mut config.max_request_body_size, + args.max_request_body_size, + ); if args.ohttp_enabled && !config.ohttp_enabled { info!("CLI override: ohttp_enabled: false -> true"); config.ohttp_enabled = true; } - if let Some(secs) = args.ohttp_key_cache_max_age_secs { - if secs != config.ohttp_key_cache_max_age_secs { - info!( - "CLI override: ohttp_key_cache_max_age_secs: {} -> {}", - config.ohttp_key_cache_max_age_secs, secs - ); - config.ohttp_key_cache_max_age_secs = secs; - } - } + override_field( + "ohttp_key_cache_max_age_secs", + &mut config.ohttp_key_cache_max_age_secs, + args.ohttp_key_cache_max_age_secs, + ); // Validate required fields. if config.rpc_node_url.is_empty() { From ee9d183864a058307dfe3db5a40c974fbd8c0785 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:26:41 +0300 Subject: [PATCH 04/53] apollo_http_server: log tx once redacted at ingest, drop raw body from span (#14662) --- crates/apollo_http_server/src/http_server.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/apollo_http_server/src/http_server.rs b/crates/apollo_http_server/src/http_server.rs index 650644dd999..02156d163d3 100644 --- a/crates/apollo_http_server/src/http_server.rs +++ b/crates/apollo_http_server/src/http_server.rs @@ -164,7 +164,7 @@ impl HttpServer { // HttpServer handlers. -#[instrument(skip(app_state))] +#[instrument(skip(app_state, tx))] async fn add_rpc_tx( Extension(app_state): Extension, headers: HeaderMap, @@ -180,7 +180,7 @@ async fn add_rpc_tx( add_tx_inner(app_state, headers, tx).await } -#[instrument(skip(app_state))] +#[instrument(skip(app_state, tx))] #[sequencer_latency_histogram(HTTP_SERVER_ADD_TX_LATENCY, true)] async fn add_tx( Extension(app_state): Extension, @@ -298,6 +298,7 @@ async fn add_tx_inner( headers: HeaderMap, tx: RpcTransaction, ) -> HttpServerResult> { + debug!("Received transaction: {tx:?}"); let gateway_input: GatewayInput = GatewayInput { rpc_tx: tx, message_metadata: None }; // Wrap the gateway client interaction with a tokio::spawn as it is NOT cancel-safe. // Even if the current task is cancelled, e.g., when a request is dropped while still being From e6b6fd2e9932909107833579e5b6efd6c75fa0af Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:30:06 +0300 Subject: [PATCH 05/53] starknet_transaction_prover: default blocking-check to fail-closed (10000ms, fail_open=false) (#14671) * starknet_transaction_prover: bump default blocking_check_timeout_millis to 10000 Co-Authored-By: Claude Opus 4.8 (1M context) * starknet_transaction_prover: default blocking_check_fail_open to false Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- crates/starknet_transaction_prover/src/config.rs | 4 ++-- crates/starknet_transaction_prover/src/server/config.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/starknet_transaction_prover/src/config.rs b/crates/starknet_transaction_prover/src/config.rs index c393248e29b..4ac21acd7fc 100644 --- a/crates/starknet_transaction_prover/src/config.rs +++ b/crates/starknet_transaction_prover/src/config.rs @@ -44,8 +44,8 @@ impl Default for ProverConfig { strk_fee_token_address: None, validate_zero_fee_fields: true, blocking_check_url: None, - blocking_check_timeout_millis: 2000, - blocking_check_fail_open: true, + blocking_check_timeout_millis: 10000, + blocking_check_fail_open: false, } } } diff --git a/crates/starknet_transaction_prover/src/server/config.rs b/crates/starknet_transaction_prover/src/server/config.rs index d196ac4707b..80a0a44daa7 100644 --- a/crates/starknet_transaction_prover/src/server/config.rs +++ b/crates/starknet_transaction_prover/src/server/config.rs @@ -125,8 +125,8 @@ impl Default for RawServiceConfig { tls_cert_file: None, tls_key_file: None, blocking_check_url: None, - blocking_check_timeout_millis: 2000, - blocking_check_fail_open: true, + blocking_check_timeout_millis: 10000, + blocking_check_fail_open: false, max_request_body_size: DEFAULT_MAX_REQUEST_BODY_SIZE, ohttp_enabled: false, ohttp_key_cache_max_age_secs: DEFAULT_OHTTP_KEY_CACHE_MAX_AGE_SECS, @@ -597,11 +597,11 @@ pub struct CliArgs { pub blocking_check_url: Option, /// Milliseconds to wait for the blocking check response before applying the - /// fail-open/fail-close policy (default: 2000). + /// fail-open/fail-close policy (default: 10000). #[arg(long, value_name = "MILLIS", env = "BLOCKING_CHECK_TIMEOUT_MILLIS")] pub blocking_check_timeout_millis: Option, - /// Fail-open when blocking check is inconclusive (default: true). Set to false for + /// Fail-open when blocking check is inconclusive (default: false). Set to false for /// fail-close. #[arg(long, env = "BLOCKING_CHECK_FAIL_OPEN")] pub blocking_check_fail_open: Option, From 750c3bb1a972313f71fa3d9f7a16210684e19a4c Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Thu, 2 Jul 2026 10:55:35 +0300 Subject: [PATCH 06/53] starknet_transaction_prover: unify HTTP middleware stack via macro (#14286) --- .../starknet_transaction_prover/src/server.rs | 59 +++++++++++-------- .../src/server/tls.rs | 17 +----- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/crates/starknet_transaction_prover/src/server.rs b/crates/starknet_transaction_prover/src/server.rs index 8ea87982e18..932378d6d63 100644 --- a/crates/starknet_transaction_prover/src/server.rs +++ b/crates/starknet_transaction_prover/src/server.rs @@ -26,6 +26,38 @@ pub type OhttpJsonrpseeLayer = OhttpLayer) -> HttpBody>; /// Pass this to `OhttpLayer::new` when constructing the layer. pub const OHTTP_JSONRPSEE_BODY_BUILDER: fn(Full) -> HttpBody = HttpBody::new; +/// The production HTTP middleware stack, applied verbatim by both transports: +/// the HTTP path (`start_server`) and the HTTPS path (`tls::start_tls_server`). +/// +/// This is a macro rather than a helper function because the value is a deeply +/// nested `ServiceBuilder>>` whose type cannot be spelled in a +/// signature. Defining the chain once keeps the two transports from drifting. +/// +/// Defined above `pub mod tls;` on purpose: `macro_rules!` scoping is textual, so moving the +/// definition below the module would make it invisible to `tls.rs`. The macro also resolves +/// `ServiceBuilder`, the layer types, and `HttpBody` at each call site (not at the definition), +/// so every caller must have them in scope — adding a layer here adds an import obligation at +/// each call site. +/// +/// Layer order (tower makes the last-added layer innermost): +/// - `HealthLayer` sits outermost so `GET /health` is answered before any other middleware runs. +/// - `OhttpLayer` must sit OUTSIDE `CompressionLayer` so compression applies to the inner JSON-RPC +/// response (the client's inner `Accept-Encoding` travels through BHTTP into jsonrpsee) rather +/// than to the OHTTP ciphertext envelope. `MapRequestBodyLayer`/`MapResponseBodyLayer` keep +/// `HttpBody` on both sides of OHTTP to satisfy its symmetric-body bound; `HttpBody::new` is a +/// zero-cost wrapper, so non-OHTTP requests still stream through unbuffered. +macro_rules! prover_http_middleware { + ($cors_layer:expr, $ohttp_layer:expr $(,)?) => { + ServiceBuilder::new() + .layer(HealthLayer) + .option_layer($cors_layer) + .layer(MapRequestBodyLayer::new(HttpBody::new)) + .option_layer($ohttp_layer) + .layer(MapResponseBodyLayer::new(HttpBody::new)) + .layer(CompressionLayer::new()) + }; +} + pub mod config; pub mod cors; pub mod errors; @@ -67,31 +99,8 @@ pub async fn start_server( .build(); let server = ServerBuilder::default() .set_config(server_config) - // `OhttpLayer` must sit OUTSIDE `CompressionLayer` so compression - // applies to the inner JSON-RPC response (the client's inner - // `Accept-Encoding` travels through BHTTP into jsonrpsee) rather than - // to the OHTTP ciphertext envelope. Because tower's `ServiceBuilder` - // makes the last-added layer innermost, `CompressionLayer` is added - // last here. - // - // `MapRequestBodyLayer` wraps hyper's `Request` into - // `Request` before `OhttpLayer` sees it — `OhttpLayer`'s - // symmetric-body bound requires `B = HttpBody` on both sides. - // `MapResponseBodyLayer` converts `CompressionBody` back to - // `HttpBody` on the response path so `OhttpLayer` receives the body - // type it expects. `HttpBody::new` is a zero-cost wrapper, so - // non-OHTTP requests still stream through unbuffered. - .set_http_middleware( - // `HealthLayer` sits outermost so `GET /health` is answered - // before any other middleware runs. - ServiceBuilder::new() - .layer(HealthLayer) - .option_layer(cors_layer) - .layer(MapRequestBodyLayer::new(HttpBody::new)) - .option_layer(ohttp_layer) - .layer(MapResponseBodyLayer::new(HttpBody::new)) - .layer(CompressionLayer::new()), - ) + // See `prover_http_middleware!` for the full layer-order rationale. + .set_http_middleware(prover_http_middleware!(cors_layer, ohttp_layer)) .build(&addr) .await .context(format!("Failed to bind JSON-RPC server to {addr}"))?; diff --git a/crates/starknet_transaction_prover/src/server/tls.rs b/crates/starknet_transaction_prover/src/server/tls.rs index d03e93650b0..67950a808a5 100644 --- a/crates/starknet_transaction_prover/src/server/tls.rs +++ b/crates/starknet_transaction_prover/src/server/tls.rs @@ -52,23 +52,10 @@ pub async fn start_tls_server( .max_connections(max_connections) .max_request_body_size(max_request_body_size) .build(); - // See `server.rs` for the rationale — `OhttpLayer` sits outside `CompressionLayer` - // so compression acts on the inner JSON-RPC response, not on the OHTTP envelope. - // `MapRequestBodyLayer`/`MapResponseBodyLayer` keep `HttpBody` on both sides of - // OHTTP to satisfy its symmetric-body bound. + // See `prover_http_middleware!` for the full layer-order rationale. let svc_builder = ServerBuilder::default() .set_config(server_config) - .set_http_middleware( - // `HealthLayer` sits outermost so `GET /health` is answered before - // any other middleware runs. - ServiceBuilder::new() - .layer(HealthLayer) - .option_layer(cors_layer) - .layer(MapRequestBodyLayer::new(HttpBody::new)) - .option_layer(ohttp_layer) - .layer(MapResponseBodyLayer::new(HttpBody::new)) - .layer(CompressionLayer::new()), - ) + .set_http_middleware(prover_http_middleware!(cors_layer, ohttp_layer)) .to_service_builder(); let listener = TcpListener::bind(addr) From be10c7c2e1bccc888fae1686dd7d36ceda59f31e Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Sun, 5 Jul 2026 09:47:18 +0300 Subject: [PATCH 07/53] starknet_transaction_prover: reject zero queue_wait_timeout when a queue is configured (#14681) A zero queue_wait_timeout_millis makes an admitted request time out immediately instead of waiting for a worker slot, silently defeating the queue. Reject it in from_args when max_queued_requests > 0; a zero timeout remains valid when no queue is configured (a request never waits). Co-authored-by: Claude Opus 4.8 (1M context) --- .../src/server/config.rs | 8 +++++++ .../src/server/config_test.rs | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/crates/starknet_transaction_prover/src/server/config.rs b/crates/starknet_transaction_prover/src/server/config.rs index 80a0a44daa7..b23d3e155ad 100644 --- a/crates/starknet_transaction_prover/src/server/config.rs +++ b/crates/starknet_transaction_prover/src/server/config.rs @@ -402,6 +402,14 @@ impl ServiceConfig { "max_request_body_size must be at least 1".to_string(), )); } + // A zero backstop makes an admitted request time out immediately instead of waiting for a + // worker slot, silently defeating the queue. Reject it when a queue is configured. + if config.queue_wait_timeout_millis == 0 && config.max_queued_requests > 0 { + return Err(ConfigError::InvalidArgument( + "queue_wait_timeout_millis must be at least 1 when max_queued_requests > 0" + .to_string(), + )); + } let transport = TransportMode::new(config.tls_cert_file, config.tls_key_file)?; let cors_allow_origin = normalize_cors_allow_origins(config.cors_allow_origin)?; if cors_allow_origin == ["*"] { diff --git a/crates/starknet_transaction_prover/src/server/config_test.rs b/crates/starknet_transaction_prover/src/server/config_test.rs index fc800836e65..e88aedbe5fe 100644 --- a/crates/starknet_transaction_prover/src/server/config_test.rs +++ b/crates/starknet_transaction_prover/src/server/config_test.rs @@ -160,6 +160,27 @@ fn cors_allow_origin_rejects_non_array_in_config_file() { assert!(matches!(error, ConfigError::ConfigFileError(_))); } +#[test] +fn rejects_zero_queue_wait_timeout_with_a_queue() { + let mut args = base_args(); + args.max_queued_requests = Some(1); + args.queue_wait_timeout_millis = Some(0); + + let error = ServiceConfig::from_args(args).unwrap_err(); + + assert!(matches!(error, ConfigError::InvalidArgument(_))); +} + +#[test] +fn allows_zero_queue_wait_timeout_without_a_queue() { + // With no queue, a request never waits, so a zero backstop is harmless. + let mut args = base_args(); + args.max_queued_requests = Some(0); + args.queue_wait_timeout_millis = Some(0); + + ServiceConfig::from_args(args).unwrap(); +} + /// TLS configuration validation: partial TLS config is rejected, complete config is accepted. #[rstest] #[case::cert_without_key( From f5aacb38889ef361f3d56f08f34ebe6940e96f82 Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Sun, 5 Jul 2026 09:47:41 +0300 Subject: [PATCH 08/53] starknet_transaction_prover: reject request limits exceeding semaphore capacity (#14679) max_concurrent_requests + max_queued_requests sizes the admission semaphore, and tokio's Semaphore panics when constructed with more than MAX_PERMITS. Validate the sum in from_args (via checked_add + MAX_PERMITS bound) and return a clean ConfigError instead of crashing at startup on an oversized or overflowing config. Co-authored-by: Claude Opus 4.8 (1M context) --- .../src/server/config.rs | 18 ++++++++++++++++-- .../src/server/config_test.rs | 12 ++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/starknet_transaction_prover/src/server/config.rs b/crates/starknet_transaction_prover/src/server/config.rs index b23d3e155ad..8cb23166b07 100644 --- a/crates/starknet_transaction_prover/src/server/config.rs +++ b/crates/starknet_transaction_prover/src/server/config.rs @@ -10,6 +10,7 @@ use blockifier::bouncer::BouncerConfig; use clap::{Parser, ValueEnum}; use serde::{Deserialize, Serialize}; use starknet_api::core::{ChainId, ContractAddress}; +use tokio::sync::Semaphore; use tracing::info; use crate::config::ProverConfig; @@ -387,9 +388,22 @@ impl ServiceConfig { "max_connections must be at least 1".to_string(), )); } + // max_concurrent_requests + max_queued_requests sizes the admission semaphore, which + // panics if built with more than `Semaphore::MAX_PERMITS`. Reject an oversized or + // overflowing sum with a clean error instead of crashing at startup. + let max_in_flight = config + .max_concurrent_requests + .checked_add(config.max_queued_requests) + .filter(|&total| total <= Semaphore::MAX_PERMITS) + .ok_or_else(|| { + ConfigError::InvalidArgument(format!( + "max_concurrent_requests ({}) + max_queued_requests ({}) must not exceed {}", + config.max_concurrent_requests, + config.max_queued_requests, + Semaphore::MAX_PERMITS, + )) + })?; // Waiting requests hold a connection, so queue depth is capped by max_connections. - let max_in_flight = - config.max_concurrent_requests.saturating_add(config.max_queued_requests); if max_in_flight > usize::try_from(config.max_connections).unwrap_or(usize::MAX) { info!( "max_concurrent_requests ({}) + max_queued_requests ({}) exceeds max_connections \ diff --git a/crates/starknet_transaction_prover/src/server/config_test.rs b/crates/starknet_transaction_prover/src/server/config_test.rs index e88aedbe5fe..288d1dbfdb8 100644 --- a/crates/starknet_transaction_prover/src/server/config_test.rs +++ b/crates/starknet_transaction_prover/src/server/config_test.rs @@ -65,6 +65,18 @@ fn base_args() -> CliArgs { } } +#[test] +fn rejects_request_limits_exceeding_semaphore_capacity() { + // The sum sizes the admission semaphore; tokio's Semaphore panics above MAX_PERMITS, so an + // oversized config must surface as a clean error rather than a startup crash. + let mut args = base_args(); + args.max_queued_requests = Some(tokio::sync::Semaphore::MAX_PERMITS); + + let error = ServiceConfig::from_args(args).unwrap_err(); + + assert!(matches!(error, ConfigError::InvalidArgument(_))); +} + /// Happy-path cases: input origins -> expected normalized output. #[rstest] #[case::disabled(vec![], vec![])] From 454b787d0e6f16e6a5840a53eedb4e8344ae1e78 Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Wed, 8 Jul 2026 21:21:58 +0300 Subject: [PATCH 09/53] deployment: upgrade jsii to 1.138.0 in lockfiles (#14690) (#14738) jsii-pacmak/codemaker 1.138.0 (resolved unpinned at CI time via cdk8s-cli) generate bindings that import jsii._type_checking.cached_type_hints, which requires the jsii 1.138.0 Python runtime. The locked 1.134.0 runtime fails with an ImportError during cdk8s synth in every system test run. (cherry picked from commit 0e43ee6f56b1eb526c9fd5e199f6a86afb306b7f) Co-authored-by: Matan Lior Co-authored-by: Claude Fable 5 --- deployments/anvil/Pipfile.lock | 6 +++--- deployments/dummy_eth2strk_oracle/Pipfile.lock | 6 +++--- deployments/dummy_recorder/Pipfile.lock | 6 +++--- deployments/sequencer/Pipfile.lock | 6 +++--- deployments/sequencer_simulator/Pipfile.lock | 8 ++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/deployments/anvil/Pipfile.lock b/deployments/anvil/Pipfile.lock index 44c19aff000..8536254c814 100644 --- a/deployments/anvil/Pipfile.lock +++ b/deployments/anvil/Pipfile.lock @@ -77,11 +77,11 @@ }, "jsii": { "hashes": [ - "sha256:22aa450dc9538952453dcd4e51de0b9e92e3c94a6b4e468832acbcbd7b124b57", - "sha256:c2288ce3568222883e1620dc9c2f2477331d36a4925a84711cf48297ee13cb50" + "sha256:575a389c56e4651f33fad0e0dafdc61d001a499d3cc0630cee734fc5e0b525ae", + "sha256:efc66b5831c8c41e343b644f03221d71480b69c3c39dc41df15659a01ce28fbb" ], "markers": "python_version >= '3.10'", - "version": "==1.134.0" + "version": "==1.138.0" }, "publication": { "hashes": [ diff --git a/deployments/dummy_eth2strk_oracle/Pipfile.lock b/deployments/dummy_eth2strk_oracle/Pipfile.lock index 44c19aff000..8536254c814 100644 --- a/deployments/dummy_eth2strk_oracle/Pipfile.lock +++ b/deployments/dummy_eth2strk_oracle/Pipfile.lock @@ -77,11 +77,11 @@ }, "jsii": { "hashes": [ - "sha256:22aa450dc9538952453dcd4e51de0b9e92e3c94a6b4e468832acbcbd7b124b57", - "sha256:c2288ce3568222883e1620dc9c2f2477331d36a4925a84711cf48297ee13cb50" + "sha256:575a389c56e4651f33fad0e0dafdc61d001a499d3cc0630cee734fc5e0b525ae", + "sha256:efc66b5831c8c41e343b644f03221d71480b69c3c39dc41df15659a01ce28fbb" ], "markers": "python_version >= '3.10'", - "version": "==1.134.0" + "version": "==1.138.0" }, "publication": { "hashes": [ diff --git a/deployments/dummy_recorder/Pipfile.lock b/deployments/dummy_recorder/Pipfile.lock index 44c19aff000..8536254c814 100644 --- a/deployments/dummy_recorder/Pipfile.lock +++ b/deployments/dummy_recorder/Pipfile.lock @@ -77,11 +77,11 @@ }, "jsii": { "hashes": [ - "sha256:22aa450dc9538952453dcd4e51de0b9e92e3c94a6b4e468832acbcbd7b124b57", - "sha256:c2288ce3568222883e1620dc9c2f2477331d36a4925a84711cf48297ee13cb50" + "sha256:575a389c56e4651f33fad0e0dafdc61d001a499d3cc0630cee734fc5e0b525ae", + "sha256:efc66b5831c8c41e343b644f03221d71480b69c3c39dc41df15659a01ce28fbb" ], "markers": "python_version >= '3.10'", - "version": "==1.134.0" + "version": "==1.138.0" }, "publication": { "hashes": [ diff --git a/deployments/sequencer/Pipfile.lock b/deployments/sequencer/Pipfile.lock index 1bf579e4652..ea6f5ee04ff 100644 --- a/deployments/sequencer/Pipfile.lock +++ b/deployments/sequencer/Pipfile.lock @@ -167,11 +167,11 @@ }, "jsii": { "hashes": [ - "sha256:22aa450dc9538952453dcd4e51de0b9e92e3c94a6b4e468832acbcbd7b124b57", - "sha256:c2288ce3568222883e1620dc9c2f2477331d36a4925a84711cf48297ee13cb50" + "sha256:575a389c56e4651f33fad0e0dafdc61d001a499d3cc0630cee734fc5e0b525ae", + "sha256:efc66b5831c8c41e343b644f03221d71480b69c3c39dc41df15659a01ce28fbb" ], "markers": "python_version >= '3.10'", - "version": "==1.134.0" + "version": "==1.138.0" }, "jsonschema": { "hashes": [ diff --git a/deployments/sequencer_simulator/Pipfile.lock b/deployments/sequencer_simulator/Pipfile.lock index 3fb326707d7..3d581a2cfe7 100644 --- a/deployments/sequencer_simulator/Pipfile.lock +++ b/deployments/sequencer_simulator/Pipfile.lock @@ -60,11 +60,11 @@ }, "jsii": { "hashes": [ - "sha256:5a44d7c3a5a326fa3d9befdb3770b380057e0a61e3804e7c4907f70d76afaaa2", - "sha256:c79c47899f53a7c3c4b20f80d3cd306628fe9ed1852eee970324c71eba1d974e" + "sha256:575a389c56e4651f33fad0e0dafdc61d001a499d3cc0630cee734fc5e0b525ae", + "sha256:efc66b5831c8c41e343b644f03221d71480b69c3c39dc41df15659a01ce28fbb" ], - "markers": "python_version ~= '3.8'", - "version": "==1.106.0" + "markers": "python_version >= '3.10'", + "version": "==1.138.0" }, "publication": { "hashes": [ From b091937c362d658f570a063a122e478c6668368c Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Thu, 9 Jul 2026 10:24:08 +0300 Subject: [PATCH 10/53] workspace: upgrade cairo compiler to v2.19.2 (#14736) * workspace: upgrade cairo compiler to v2.19.2 Co-Authored-By: Claude Opus 4.8 (1M context) * starknet_api,starknet_os_flow_tests: bump SierraVersion::LATEST to 1.9.1 and regen fixtures for cairo 2.19.2 Co-Authored-By: Claude Opus 4.8 (1M context) * central_systest_blobs: update cende operator/fee-token addresses and blob fixtures for cairo 2.19.2 Co-Authored-By: Claude Opus 4.8 (1M context) * central_systest_blobs: bump cende blob generation to 49 (re-uploaded blob for cairo 2.19.2) Co-Authored-By: Claude Opus 4.8 (1M context) * apollo_integration_tests: regenerate proof-flow fixtures for cairo 2.19.2 (sierra 1.9.1) Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- Cargo.lock | 177 ++++++++---------- Cargo.toml | 12 +- .../src/cairo_compiler_version.txt | 2 +- .../resources/proof_flow/proof.bin | Bin 236345 -> 231405 bytes .../resources/proof_flow/proof_facts.json | 4 +- .../src/state_reader.rs | 2 +- .../src/fee_token_addresses.rs | 2 +- .../resources/blob_file_generation | 2 +- .../resources/chain_info.json | 2 +- .../resources/preconfirmed_block.json | 24 +-- .../src/cende_blob_regression_test.rs | 4 +- .../src/contract_class/structs.rs | 2 +- .../hint_coverage/test_deploy_syscall.json | 3 - ...est_deprecated_call_contract_variants.json | 3 - .../test_direct_execute_call.json | 3 - ...se_full_output_false_private_keys_3_1.json | 3 - ..._full_output_false_private_keys_empty.json | 3 - ...e_full_output_false_private_keys_none.json | 3 - ...lse_full_output_true_private_keys_3_1.json | 3 - ...e_full_output_true_private_keys_empty.json | 3 - ...se_full_output_true_private_keys_none.json | 3 - ...ue_full_output_false_private_keys_3_1.json | 3 - ..._full_output_false_private_keys_empty.json | 3 - ...e_full_output_false_private_keys_none.json | 3 - ...rue_full_output_true_private_keys_3_1.json | 3 - ...e_full_output_true_private_keys_empty.json | 3 - ...ue_full_output_true_private_keys_none.json | 3 - ...class_execution_info_use_kzg_da_false.json | 3 - ..._class_execution_info_use_kzg_da_true.json | 3 - .../hint_coverage/test_resources_type.json | 3 - .../hint_coverage/test_reverted_call.json | 3 - .../test_reverted_invoke_tx_cairo0.json | 3 - .../test_reverted_invoke_tx_cairo1.json | 3 - ...lse_full_output_false_contract_cairo0.json | 3 - ...lse_full_output_false_contract_cairo1.json | 3 - ...alse_full_output_true_contract_cairo0.json | 3 - ...alse_full_output_true_contract_cairo1.json | 3 - ...rue_full_output_false_contract_cairo0.json | 3 - ...rue_full_output_false_contract_cairo1.json | 3 - ...true_full_output_true_contract_cairo0.json | 3 - ...true_full_output_true_contract_cairo1.json | 3 - .../starknet_os_flow_tests/src/fuzz_tests.rs | 10 +- crates/starknet_os_flow_tests/src/tests.rs | 4 +- 43 files changed, 117 insertions(+), 217 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd459f4ca6c..c161756050e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,17 +96,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.16", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.12" @@ -2952,7 +2941,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" dependencies = [ - "ahash 0.8.12", + "ahash", "ark-ff 0.5.0", "ark-poly 0.5.0", "ark-serialize 0.5.0", @@ -2973,7 +2962,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8352a2b2aedf6ba2cc38f7520fc51191d518dde96175c729af19f2d059f191c4" dependencies = [ - "ahash 0.8.12", + "ahash", "ark-ff 0.6.0", "ark-poly 0.6.0", "ark-serialize 0.6.0", @@ -3160,7 +3149,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" dependencies = [ - "ahash 0.8.12", + "ahash", "ark-ff 0.5.0", "ark-serialize 0.5.0", "ark-std 0.5.0", @@ -3175,7 +3164,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75f55af10b672002b8d953e230282c51206842e20e5791a94432219b4201de5c" dependencies = [ - "ahash 0.8.12", + "ahash", "ark-ff 0.6.0", "ark-serialize 0.6.0", "ark-std 0.6.0", @@ -4286,9 +4275,9 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c13d355783b9ff4b54a995a49a639707e32502cac2d886b7ec62b367694c05" +checksum = "c4ec715a91e425ffc27a20b78ca9b5e0f63479af2277f99402fd329ef6c30d12" dependencies = [ "cairo-lang-utils", "indoc 2.0.7", @@ -4301,9 +4290,9 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4332bf28b1ccc82f064ed6ed4f287828391d4c5629f8f49ef6ddc3915b56e381" +checksum = "ceae4e541648118405b7c9012abaa3ddeec5ed5712f5443eb6f1fa823297c342" dependencies = [ "anyhow", "cairo-lang-defs", @@ -4328,9 +4317,9 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e58a589f842fd8ae1191530c04b5df490f94fb803bb5ccd96adbfcaba9b3ab1f" +checksum = "55819e6796708cd4fc0713a98f3e4c1b1474371d400244f3a5a67986a7c7849f" dependencies = [ "cairo-lang-utils", "id-arena", @@ -4339,9 +4328,9 @@ dependencies = [ [[package]] name = "cairo-lang-defs" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97ef9dc4dfb938a2585100e452e2b6184662bb9bba7042226411fa6bc07cb91" +checksum = "986247de31f01b2d97edb841d13cd63486b57a2a642275ec9c2d12144a7015b7" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -4360,9 +4349,9 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0045ae336e51dc4112e1c678591262184ca22e6bda4c759619a6a817a60d967d" +checksum = "79af76a3d672eb6264e27cb822da41f7db317ee57dddf2aac9cc82301e244e5c" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -4374,9 +4363,9 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f93abccc09808fc4f2b611d8c20a390fa03984eddc907f3ad8ce5b58d8a721" +checksum = "32b1402e0d1ba3d3520503b7167c1d6a67d1130a60cd3d97a4a47a153bd01d24" dependencies = [ "cairo-lang-utils", "good_lp", @@ -4384,9 +4373,9 @@ dependencies = [ [[package]] name = "cairo-lang-executable" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad52bbd3796e534fe874a9818c39263327af3faf1a64a7c31e7a5b1bfe551210" +checksum = "76081cb2ee71e4f17851d6a8ce676b24dc6cee84e2f8b931a9411f7f3776c6c2" dependencies = [ "anyhow", "cairo-lang-casm", @@ -4409,9 +4398,9 @@ dependencies = [ [[package]] name = "cairo-lang-executable-plugin" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b0071c920122fa6735d67f549758f5c255c9035261f30a53889ada2c89bd94" +checksum = "cf365491e69985e1956f68170484ad696e5189a987c32b6c179756667dd17c67" dependencies = [ "cairo-lang-defs", "cairo-lang-filesystem", @@ -4424,9 +4413,9 @@ dependencies = [ [[package]] name = "cairo-lang-execute-utils" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "998065f028c5a5a8b4a857327b608c8bbf5228709f3ca9db9ed224b2fb840676" +checksum = "fda43c673bde6774cd83b967cc5c92236fcf623f5daa30425e344e963305c0cb" dependencies = [ "anyhow", "cairo-lang-casm", @@ -4440,9 +4429,9 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d1e89da58481852b273a455986a035abd7127452f8275fe2bc022783b7f89" +checksum = "a00b4ccd5c0c503ba0fddcb8e6e69b00cedb6eb4e65b56ebac367c4689ef40bb" dependencies = [ "cairo-lang-debug", "cairo-lang-proc-macros", @@ -4458,9 +4447,9 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a80dc0ba2632faf759a25ecda755aaf0cb4324fce392b1feb652e259135081c6" +checksum = "065d39de3cfe2e78d1a17cc604a4e10eb182ba737bb365671ad5855f895d6b42" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -4478,9 +4467,9 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422cef0633dcd65a7b7d48a6e8a582830da289441df5bb566d38a7b74e1c51fa" +checksum = "5290e70e800d886429bfc00bae1be9e3312e5bf22cbce302e1b3dc34e0d2c9b4" dependencies = [ "assert_matches", "cairo-lang-debug", @@ -4508,9 +4497,9 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e89b7b250bf93661f3c57b09428b0feb7e47f69e04636f860b24938e5a9a7c" +checksum = "16348bdf8ada212c0590a23a08c28ae57cd9db25497fc388a9651d444ab17497" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -4528,9 +4517,9 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4354cb3fe34bf0e1eebcbe3fff5953dcc5389f991caf7cd959086250b54ab55f" +checksum = "d9791844a410181910f864fdf1a7c64ac84fbe9d7addbcb4d65ecb51dda0aac1" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", @@ -4552,9 +4541,9 @@ checksum = "123ac0ecadf31bacae77436d72b88fa9caef2b8e92c89ce63a125ae911a12fae" [[package]] name = "cairo-lang-proc-macros" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c692bbc37b074f9e1c3f7fdcb5bddfa0c31768e0c052fbad882adf2c039aa1" +checksum = "30618f3bc4463ea192be68dfe416f0b02268c986235aad3599b18564875ec035" dependencies = [ "cairo-lang-debug", "proc-macro2", @@ -4565,9 +4554,9 @@ dependencies = [ [[package]] name = "cairo-lang-project" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006338f1186ecd5da3b52b4bb86fd4c69f9f2a0f32b5d1055efa0c28c160a004" +checksum = "cde78a3b75962ebf39a2b1cd3a7f9e5b67d058a00cad60120dfcd9df7df991a4" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", @@ -4578,9 +4567,9 @@ dependencies = [ [[package]] name = "cairo-lang-runnable-utils" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5003a11d12e7b299960ab94d7f1da03bfb8f85c2d4858ee5f2d88f0d007676f6" +checksum = "ed383329002e7e4998ac7c76db319a1a8ab36b0a931871ca8f58900dd112dc71" dependencies = [ "cairo-lang-casm", "cairo-lang-sierra", @@ -4595,9 +4584,9 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6a5b109faa35f59a1ef1c2fc04cd0c9086778f41857cec8e0bcd7dc513517f" +checksum = "8674fd79d56dee8ffa915089c491ec2d06670016e4dcb6e627196c85a9cad6f2" dependencies = [ "ark-ff 0.6.0", "ark-secp256k1 0.6.0", @@ -4627,9 +4616,9 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a2fb4eed7bfc001f7fe028927bb4abeafa513764472e0f8b80cfd6ec19e07d" +checksum = "636e004ad0f8ae193243fb6105302223c7e2b548a8c42726e54660f003b8e1d4" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -4657,9 +4646,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c07bb85ab735c71630540736044bc5f771b1a336dd0636a1f4708186746f40e" +checksum = "dcaa94cf8bf1867ba3923fb11d8f998fe63712e19fd50be133bebb179cd0bce2" dependencies = [ "anyhow", "cairo-lang-utils", @@ -4683,9 +4672,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c291f44590a7c8e7e00b5b8adfa5ff7d4afab9e9b8cbd427c5757035e19b45" +checksum = "4f561f526cfdbb6b1400246c92fea77bfd3e9fa34a79e88a9a15c6917931a473" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -4699,9 +4688,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c967cbee6e5e5a5c69fba183bb85e8906dba79cf12673c79b535e89b99fbd683" +checksum = "0c13c715b678f2a9d2f7dc54ce53bb4068fb2d6ddbb21c758c4c7538ab12eca4" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -4715,9 +4704,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8081833a3e5b483b7faff351b9606fb2d486be55c8fff467efaf383c193b0890" +checksum = "0513f22a42f3d785fca47c533d6f199aa590c2b9e06bcd41ab564de611edd55c" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -4740,9 +4729,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b09e28e8a8a702516a898e48a933cf3136b92019c4bd3ccae00707e883b9367" +checksum = "47a741da915eea1822cde8cf27814066ae98aab994e52f34ad162954c3b53fbd" dependencies = [ "assert_matches", "cairo-lang-casm", @@ -4761,9 +4750,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-type-size" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c2b692133e92cf42ffc493fd8f6957a3a35b75b908fc53f287edb35f06aac9" +checksum = "4d4b565cc9e67da5cab8543034353c1f8b1fc3f7ccf2e4dad16d1fc8509d038f" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -4771,9 +4760,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c27166eada9c2c812a2ff4db8f20ca4d6fead8a63390c02b93ea7f27da205120" +checksum = "727381cd2b30bd84d071e797eb3ad777b9c64e072506d2271a1c08d9724010ab" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -4804,9 +4793,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet-classes" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10faa91e4be6065bd08f2da8d923721e25615ca94f50fd870faf5e52691b55b3" +checksum = "178980f5a61eba08802b045aa1ba067e4ad716123547b32f13bccdf821b5c8bb" dependencies = [ "cairo-lang-casm", "cairo-lang-sierra", @@ -4828,9 +4817,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0a90a23f458132951b20c267e2410d4eaf307e214bbcb5dabfd7ae0739b903" +checksum = "cf61a7a6b1edb22ee6c52a198f450372e9f2541d60a99f130ee68539b35adb06" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -4847,9 +4836,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63421b7a7204b8c57f15d488a09520959cd6e6fef48dbbd3a37071577873d15" +checksum = "8aa0048c370bdd67a6144a363f08cffc3cee3bf72ea5b125e8e67ef678132079" dependencies = [ "genco", "xshell", @@ -4857,9 +4846,9 @@ dependencies = [ [[package]] name = "cairo-lang-test-utils" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6e37ea508d269cfa17331db6395f445ca3a5c9cbf8565990edcb2a17d9d466" +checksum = "3345dea097afbd49d145a4a3325d2ceefb399f389d40cd6d05d6316a7cbf5108" dependencies = [ "cairo-lang-formatter", "cairo-lang-proc-macros", @@ -4871,9 +4860,9 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.19.0-rc.3" +version = "2.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a994da2cbd8f7be81e9951d20b1f98e220e03c61e18e6cbde0bb4cc911b90c8d" +checksum = "41afc716def9a9f1a160d38a1626064363f8d64d225acc3b00c1f877718ec666" dependencies = [ "hashbrown 0.17.1", "indexmap 2.14.0", @@ -5368,7 +5357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -5377,7 +5366,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -6381,7 +6370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -7050,9 +7039,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] [[package]] name = "hashbrown" @@ -7066,7 +7052,8 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.12", + "ahash", + "allocator-api2", ] [[package]] @@ -7896,7 +7883,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -8141,7 +8128,7 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978" dependencies = [ - "ahash 0.8.12", + "ahash", "anyhow", "base64 0.21.7", "bytecount", @@ -9038,7 +9025,7 @@ version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25dea7ac8057892855ec285c440160265225438c3c45072613c25a4b26e98ef5" dependencies = [ - "ahash 0.8.12", + "ahash", "portable-atomic", ] @@ -9177,7 +9164,7 @@ checksum = "7760e0e418d9b7e5777c0374009ca4c93861b9066f18cb334a20ce50ab63aa48" dependencies = [ "assert-json-diff", "bytes", - "colored 2.2.0", + "colored 3.0.0", "futures-util", "http 1.3.1", "http-body 1.0.1", @@ -10728,12 +10715,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown 0.14.5", "indoc 1.0.9", "libc", "memoffset 0.9.1", "num-bigint", - "parking_lot 0.11.2", + "parking_lot 0.12.5", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", @@ -10890,7 +10877,7 @@ dependencies = [ "once_cell", "socket2 0.6.1", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -11634,7 +11621,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -11693,7 +11680,7 @@ dependencies = [ "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs 0.26.11", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -13552,7 +13539,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -14780,7 +14767,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8e92f4bf1f9..b666d4ddc79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -253,12 +253,12 @@ c-kzg = "2.1.5" cached = "0.44.0" cairo-air = "1.1.0" cairo-felt = "0.9.1" -cairo-lang-casm = "2.19.0-rc.3" -cairo-lang-runner = "2.19.0-rc.3" -cairo-lang-sierra = "2.19.0-rc.3" -cairo-lang-sierra-to-casm = "2.19.0-rc.3" -cairo-lang-starknet-classes = "2.19.0-rc.3" -cairo-lang-utils = "2.19.0-rc.3" +cairo-lang-casm = "2.19.2" +cairo-lang-runner = "2.19.2" +cairo-lang-sierra = "2.19.2" +cairo-lang-sierra-to-casm = "2.19.2" +cairo-lang-starknet-classes = "2.19.2" +cairo-lang-utils = "2.19.2" cairo-native = "0.9.0-rc.7" cairo-program-runner-lib = "1.1.0" cairo-vm = "3.2.0" diff --git a/crates/apollo_infra_utils/src/cairo_compiler_version.txt b/crates/apollo_infra_utils/src/cairo_compiler_version.txt index 4f0f5613341..b87b08b5b01 100644 --- a/crates/apollo_infra_utils/src/cairo_compiler_version.txt +++ b/crates/apollo_infra_utils/src/cairo_compiler_version.txt @@ -1 +1 @@ -2.19.0-rc.3 \ No newline at end of file +2.19.2 \ No newline at end of file diff --git a/crates/apollo_integration_tests/resources/proof_flow/proof.bin b/crates/apollo_integration_tests/resources/proof_flow/proof.bin index c21f350b690eb2a372a3a0484d6a9b2913320a31..a49914c9124bc200c6b15cc24f303ed09029d452 100644 GIT binary patch literal 231405 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ɨ+p|?A}4v; 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

$f9jUzvzj%CKf(iQqb|ZUSi8zCl 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
%C8SD0gK6Lnxy0IM0 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 literal 236345 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 hgCKl*QsS&DE@y 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

Hg^omejo_-PDEcACrVVD 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� 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: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 GlobalRoot { GlobalRoot(Felt::from_hex_unchecked(EXPECTED_PROOF_FLOW_GENESIS_GLOBAL_ROOT.data())) diff --git a/crates/blockifier_test_utils/src/fee_token_addresses.rs b/crates/blockifier_test_utils/src/fee_token_addresses.rs index e19cbaa6c6e..bdbc24078f0 100644 --- a/crates/blockifier_test_utils/src/fee_token_addresses.rs +++ b/crates/blockifier_test_utils/src/fee_token_addresses.rs @@ -8,4 +8,4 @@ use expect_test::{expect, Expect}; /// `cargo +nightly-2025-07-14 test -p starknet_os_flow_tests --features /// starknet_transaction_prover/stwo_proving --release generate_proof_fixtures -- --ignored`. pub const EXPECTED_STRK_FEE_TOKEN_ADDRESS: Expect = - expect!["0x216e06f4761eb833ec9fbc9d08ae554427a2e6f23539d669a26d7e9997222b3"]; + expect!["0x55c0f8041b34244db9305768d49a75fb604db74fa19357894a55d3cf8bfe0c"]; diff --git a/crates/central_systest_blobs/resources/blob_file_generation b/crates/central_systest_blobs/resources/blob_file_generation index 72f523f36ed..2e66562e270 100644 --- a/crates/central_systest_blobs/resources/blob_file_generation +++ b/crates/central_systest_blobs/resources/blob_file_generation @@ -1 +1 @@ -39 \ No newline at end of file +49 \ No newline at end of file diff --git a/crates/central_systest_blobs/resources/chain_info.json b/crates/central_systest_blobs/resources/chain_info.json index f2b1c655827..0469b08ef22 100644 --- a/crates/central_systest_blobs/resources/chain_info.json +++ b/crates/central_systest_blobs/resources/chain_info.json @@ -1,4 +1,4 @@ { "chain_id": "0x534e5f505245494e544547524154494f4e5f5345504f4c4941", - "strk_fee_token_address": "0x05945fa70ed44e5f6e5b56c59763dd3d6a8725ebce6f7448b0452f7cd6085056" + "strk_fee_token_address": "0x07f979b7d556abb6cca53681c87f55941883759c59c9c25c4119bbf614ee5696" } \ No newline at end of file diff --git a/crates/central_systest_blobs/resources/preconfirmed_block.json b/crates/central_systest_blobs/resources/preconfirmed_block.json index 8f60686723c..54b57e8afc9 100644 --- a/crates/central_systest_blobs/resources/preconfirmed_block.json +++ b/crates/central_systest_blobs/resources/preconfirmed_block.json @@ -24,12 +24,12 @@ "events": [ { "data": [ - "0x59bbf19eb197eb2e5685d4340720ddd7c1124795c736d6c7f2dcf78cd17690a", + "0x22f8068fca53c6cf86fc325870b42433c4b234b07a42b49f7a93b5187b56b2f", "0x1000", "0x1089a9", "0x0" ], - "from_address": "0x5945fa70ed44e5f6e5b56c59763dd3d6a8725ebce6f7448b0452f7cd6085056", + "from_address": "0x7f979b7d556abb6cca53681c87f55941883759c59c9c25c4119bbf614ee5696", "keys": [ "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" ] @@ -56,7 +56,7 @@ }, "execution_status": "SUCCEEDED", "l2_to_l1_messages": [], - "transaction_hash": "0x611ab60b0582398c8ee4ef4d862602f900ac9082bfb0b71f41dca48382a3dbb", + "transaction_hash": "0x34f2b7f34e0759ee741e7fc6123105edae6f6fa0f760648381bdbf59691634e", "transaction_index": 0 } ], @@ -66,14 +66,14 @@ "deployed_contracts": [], "migrated_compiled_classes": [], "nonces": { - "0x59bbf19eb197eb2e5685d4340720ddd7c1124795c736d6c7f2dcf78cd17690a": "0xc" + "0x22f8068fca53c6cf86fc325870b42433c4b234b07a42b49f7a93b5187b56b2f": "0xc" }, "old_declared_contracts": [], "replaced_classes": [], "storage_diffs": { - "0x5945fa70ed44e5f6e5b56c59763dd3d6a8725ebce6f7448b0452f7cd6085056": [ + "0x7f979b7d556abb6cca53681c87f55941883759c59c9c25c4119bbf614ee5696": [ { - "key": "0x262297cdc07010b3a84c11fb5224bbd39d5ea01fcdf82a261e6d6d5536cbede", + "key": "0x6b7d48bd102b81b6d7a4002c057441b7e707699c04ebcdbaf50ebf0e2bd9928", "value": "0xfffffffffffffffffffffffff98f3243" }, { @@ -89,10 +89,10 @@ "account_deployment_data": [], "calldata": [ "0x1", - "0x2319dee700ef7fbad10a4693696826ce0084d9c46d0a35b42d83fa126dd7034", + "0x31b0799910c85deca86463f587e0b8e33dc19dcaa177af1d4f0b87bcb5d72fd", "0x4ea6d2b84c4aea3baab8c031143fcd1fdf95debad5f888784f8db17e1c17f4", "0x2", - "0x591245e614a1827a1986d00e76411f7119ee2f8544ed0a33097a919cb832bbd", + "0x49c8659b95950e792298154b41a72dc7c843f784e6bbac93f1bb899e5773e17", "0x2000" ], "fee_data_availability_mode": 0, @@ -114,13 +114,13 @@ "max_price_per_unit": "0x3b9aca00" } }, - "sender_address": "0x59bbf19eb197eb2e5685d4340720ddd7c1124795c736d6c7f2dcf78cd17690a", + "sender_address": "0x22f8068fca53c6cf86fc325870b42433c4b234b07a42b49f7a93b5187b56b2f", "signature": [ - "0x18d49490b894540bbd5e79c8d22301e25179be3630dfb0d31f666f2a2c6600", - "0x18e4f5381c4cc4ef1e1348a728e6f851ff203e3e700a6def426f15f274b2617" + "0x65c00f2a628685ab00243132bc62b5acb1a9dfffcece5448a8febb477103013", + "0x5cd3cfad979a977423b298ddd43c77d9f0ddde5ed07ab09d6d69b32eb4aea00" ], "tip": "0x0", - "transaction_hash": "0x611ab60b0582398c8ee4ef4d862602f900ac9082bfb0b71f41dca48382a3dbb", + "transaction_hash": "0x34f2b7f34e0759ee741e7fc6123105edae6f6fa0f760648381bdbf59691634e", "type": "INVOKE_FUNCTION", "version": "0x3" } diff --git a/crates/central_systest_blobs/src/cende_blob_regression_test.rs b/crates/central_systest_blobs/src/cende_blob_regression_test.rs index 761c76c0a90..12371554ac8 100644 --- a/crates/central_systest_blobs/src/cende_blob_regression_test.rs +++ b/crates/central_systest_blobs/src/cende_blob_regression_test.rs @@ -136,9 +136,9 @@ const CHAIN_INFO_PATH: &str = "../resources/chain_info.json"; const PRECONFIRMED_BLOCK_PATH: &str = "../resources/preconfirmed_block.json"; const EXPECTED_OPERATOR_ADDRESS: Expect = - expect!["0x059bbf19eb197eb2e5685d4340720ddd7c1124795c736d6c7f2dcf78cd17690a"]; + expect!["0x022f8068fca53c6cf86fc325870b42433c4b234b07a42b49f7a93b5187b56b2f"]; const EXPECTED_FEE_TOKEN_ADDRESS: Expect = - expect!["0x05945fa70ed44e5f6e5b56c59763dd3d6a8725ebce6f7448b0452f7cd6085056"]; + expect!["0x07f979b7d556abb6cca53681c87f55941883759c59c9c25c4119bbf614ee5696"]; static OPERATOR_ADDRESS: LazyLock = LazyLock::new(|| contract_address!(EXPECTED_OPERATOR_ADDRESS.data)); static FEE_TOKEN_ADDRESS: LazyLock = diff --git a/crates/starknet_api/src/contract_class/structs.rs b/crates/starknet_api/src/contract_class/structs.rs index 1a591d78bb6..70517079964 100644 --- a/crates/starknet_api/src/contract_class/structs.rs +++ b/crates/starknet_api/src/contract_class/structs.rs @@ -78,7 +78,7 @@ impl SierraVersion { /// Version of deprecated contract class (Cairo 0). pub const DEPRECATED: Self = Self(Version::new(0, 0, 0)); - pub const LATEST: Self = Self(Version::new(1, 9, 0)); + pub const LATEST: Self = Self(Version::new(1, 9, 1)); pub fn new(major: u64, minor: u64, patch: u64) -> Self { Self(Version::new(major, minor, patch)) diff --git a/crates/starknet_os/resources/hint_coverage/test_deploy_syscall.json b/crates/starknet_os/resources/hint_coverage/test_deploy_syscall.json index 17c5d78b02b..5030a7c32bf 100644 --- a/crates/starknet_os/resources/hint_coverage/test_deploy_syscall.json +++ b/crates/starknet_os/resources/hint_coverage/test_deploy_syscall.json @@ -86,9 +86,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_deprecated_call_contract_variants.json b/crates/starknet_os/resources/hint_coverage/test_deprecated_call_contract_variants.json index fc2fcedfa0f..fee4a49e0f5 100644 --- a/crates/starknet_os/resources/hint_coverage/test_deprecated_call_contract_variants.json +++ b/crates/starknet_os/resources/hint_coverage/test_deprecated_call_contract_variants.json @@ -86,9 +86,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_direct_execute_call.json b/crates/starknet_os/resources/hint_coverage/test_direct_execute_call.json index 03b0697ed58..38d2837c88c 100644 --- a/crates/starknet_os/resources/hint_coverage/test_direct_execute_call.json +++ b/crates/starknet_os/resources/hint_coverage/test_direct_execute_call.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_3_1.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_3_1.json index 798b993d36a..d704d278e05 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_3_1.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_3_1.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_empty.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_empty.json index 3e8cd6281fa..8f7fb7ba5cb 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_empty.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_empty.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_none.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_none.json index 3e8cd6281fa..8f7fb7ba5cb 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_none.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_false_private_keys_none.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_3_1.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_3_1.json index f134e598dc7..cfe285f2267 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_3_1.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_3_1.json @@ -71,9 +71,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_empty.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_empty.json index f134e598dc7..cfe285f2267 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_empty.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_empty.json @@ -71,9 +71,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_none.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_none.json index f134e598dc7..cfe285f2267 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_none.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_false_full_output_true_private_keys_none.json @@ -71,9 +71,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_3_1.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_3_1.json index bb76b09402e..ee2cc228b08 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_3_1.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_3_1.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_empty.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_empty.json index 03b0697ed58..38d2837c88c 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_empty.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_empty.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_none.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_none.json index 03b0697ed58..38d2837c88c 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_none.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_false_private_keys_none.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_3_1.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_3_1.json index f134e598dc7..cfe285f2267 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_3_1.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_3_1.json @@ -71,9 +71,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_empty.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_empty.json index f134e598dc7..cfe285f2267 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_empty.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_empty.json @@ -71,9 +71,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_none.json b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_none.json index f134e598dc7..cfe285f2267 100644 --- a/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_none.json +++ b/crates/starknet_os/resources/hint_coverage/test_encrypted_state_diff_use_kzg_da_true_full_output_true_private_keys_none.json @@ -71,9 +71,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_new_class_execution_info_use_kzg_da_false.json b/crates/starknet_os/resources/hint_coverage/test_new_class_execution_info_use_kzg_da_false.json index 179476d4b55..158cdf6afdc 100644 --- a/crates/starknet_os/resources/hint_coverage/test_new_class_execution_info_use_kzg_da_false.json +++ b/crates/starknet_os/resources/hint_coverage/test_new_class_execution_info_use_kzg_da_false.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_new_class_execution_info_use_kzg_da_true.json b/crates/starknet_os/resources/hint_coverage/test_new_class_execution_info_use_kzg_da_true.json index df9c0afb45c..11180d45703 100644 --- a/crates/starknet_os/resources/hint_coverage/test_new_class_execution_info_use_kzg_da_true.json +++ b/crates/starknet_os/resources/hint_coverage/test_new_class_execution_info_use_kzg_da_true.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_resources_type.json b/crates/starknet_os/resources/hint_coverage/test_resources_type.json index d34cef8b4a5..4dca8c8b7a8 100644 --- a/crates/starknet_os/resources/hint_coverage/test_resources_type.json +++ b/crates/starknet_os/resources/hint_coverage/test_resources_type.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_reverted_call.json b/crates/starknet_os/resources/hint_coverage/test_reverted_call.json index 59c232b2765..0dac2055603 100644 --- a/crates/starknet_os/resources/hint_coverage/test_reverted_call.json +++ b/crates/starknet_os/resources/hint_coverage/test_reverted_call.json @@ -89,9 +89,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_reverted_invoke_tx_cairo0.json b/crates/starknet_os/resources/hint_coverage/test_reverted_invoke_tx_cairo0.json index 8a42fca3a1f..6547e2b2bd5 100644 --- a/crates/starknet_os/resources/hint_coverage/test_reverted_invoke_tx_cairo0.json +++ b/crates/starknet_os/resources/hint_coverage/test_reverted_invoke_tx_cairo0.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/test_reverted_invoke_tx_cairo1.json b/crates/starknet_os/resources/hint_coverage/test_reverted_invoke_tx_cairo1.json index 1c50f26f699..2d0026f86e7 100644 --- a/crates/starknet_os/resources/hint_coverage/test_reverted_invoke_tx_cairo1.json +++ b/crates/starknet_os/resources/hint_coverage/test_reverted_invoke_tx_cairo1.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_false_contract_cairo0.json b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_false_contract_cairo0.json index 0e5b5035d37..82122f1caa0 100644 --- a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_false_contract_cairo0.json +++ b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_false_contract_cairo0.json @@ -86,9 +86,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_false_contract_cairo1.json b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_false_contract_cairo1.json index 3e8cd6281fa..8f7fb7ba5cb 100644 --- a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_false_contract_cairo1.json +++ b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_false_contract_cairo1.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_true_contract_cairo0.json b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_true_contract_cairo0.json index e913e52bca5..d060acd530d 100644 --- a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_true_contract_cairo0.json +++ b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_true_contract_cairo0.json @@ -74,9 +74,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_true_contract_cairo1.json b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_true_contract_cairo1.json index f134e598dc7..cfe285f2267 100644 --- a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_true_contract_cairo1.json +++ b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_false_full_output_true_contract_cairo1.json @@ -71,9 +71,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_false_contract_cairo0.json b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_false_contract_cairo0.json index aa6bc5fcf14..1ab9a927460 100644 --- a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_false_contract_cairo0.json +++ b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_false_contract_cairo0.json @@ -86,9 +86,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_false_contract_cairo1.json b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_false_contract_cairo1.json index 03b0697ed58..38d2837c88c 100644 --- a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_false_contract_cairo1.json +++ b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_false_contract_cairo1.json @@ -83,9 +83,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_true_contract_cairo0.json b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_true_contract_cairo0.json index e913e52bca5..d060acd530d 100644 --- a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_true_contract_cairo0.json +++ b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_true_contract_cairo0.json @@ -74,9 +74,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_true_contract_cairo1.json b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_true_contract_cairo1.json index f134e598dc7..cfe285f2267 100644 --- a/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_true_contract_cairo1.json +++ b/crates/starknet_os/resources/hint_coverage/trivial_diff_scenario_use_kzg_da_true_full_output_true_contract_cairo1.json @@ -71,9 +71,6 @@ { "StatelessHint": "EnterScopeNode" }, - { - "StatelessHint": "EnterScopeNewNode" - }, { "StatelessHint": "EnterScopeNextNodeBit0" }, diff --git a/crates/starknet_os_flow_tests/src/fuzz_tests.rs b/crates/starknet_os_flow_tests/src/fuzz_tests.rs index 19eb9cb2d12..65dd2a213ec 100644 --- a/crates/starknet_os_flow_tests/src/fuzz_tests.rs +++ b/crates/starknet_os_flow_tests/src/fuzz_tests.rs @@ -88,15 +88,15 @@ static IS_CAIRO1: LazyLock> = LazyLock::new(|| { /// Initial fuzz contract addresses. static FUZZ_ADDRESS_ORCHESTRATOR_EXPECT: Expect = - expect!["0x6902bd047addeb79a37c4df4f3c02121e50efdec2f82e0edcb6c1692c6f5bd5"]; + expect!["0x19801f71411de58e58ead29b3baa957724bf7058c279b1a1f9e60236970e7b8"]; static FUZZ_ADDRESS_CAIRO1_A_EXPECT: Expect = - expect!["0xa963aa41926edcf7ebac871fcabde16fa583a93e67722569998ccff7985abd"]; + expect!["0x3fa985a92378c2f96c9121184e94c50b10a0e49e8bfef2814c3548cae74102e"]; static FUZZ_ADDRESS_CAIRO1_B_EXPECT: Expect = - expect!["0x79fb0afff1d3ac8f1076015e464abb3464bc5866de21c372411d0e8eede92e6"]; + expect!["0x221529257ab337bfc729cdf2c13a470210fdeb6afa51f27f93e3ec18f5e25c"]; static FUZZ_ADDRESS_CAIRO0_A_EXPECT: Expect = - expect!["0x72d7470f205d9956c6b2211acefd00be64116bfe453fc533f5138e0501f1ca7"]; + expect!["0x3629015d1820715c590b9b26e2a1dffaf7a36ec0761438c8c6836f0d7a7c9df"]; static FUZZ_ADDRESS_CAIRO0_B_EXPECT: Expect = - expect!["0x3bf01869bbb5a4cab6631d78e73388e9f7100d75ab9dcc3de4a4d6a84ba24ea"]; + expect!["0x27afaa7befa610d5200489329ac3131317c20379d50e6e4f664c4befaf81ea3"]; static FUZZ_ADDRESS_ORCHESTRATOR: LazyLock = LazyLock::new(|| { ContractAddress::try_from(felt!(FUZZ_ADDRESS_ORCHESTRATOR_EXPECT.data())).unwrap() }); diff --git a/crates/starknet_os_flow_tests/src/tests.rs b/crates/starknet_os_flow_tests/src/tests.rs index a1852d0dece..e4004c16151 100644 --- a/crates/starknet_os_flow_tests/src/tests.rs +++ b/crates/starknet_os_flow_tests/src/tests.rs @@ -1268,12 +1268,12 @@ async fn test_experimental_libfuncs_contract(#[values(true, false)] use_kzg_da: let poseidons = test_output.get_builtin_usage(&BuiltinName::poseidon); if use_kzg_da { expect![[r#" - 67 + 66 "#]] .assert_debug_eq(&poseidons); } else { expect![[r#" - 58 + 57 "#]] .assert_debug_eq(&poseidons); } From 59b1e1fc3d0b2ef417fb03332b1218c7d13b0657 Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Thu, 9 Jul 2026 13:17:12 +0300 Subject: [PATCH 11/53] starknet_transaction_prover: per-request structured log with request-id (#14165) * starknet_transaction_prover: per-request structured log with request-id Adds `RequestLogLayer`, the outermost middleware that emits one `event="http_request"` log line per request (request_id, method, path, status, latency_ms) and echoes the id on the response. The id is accepted from `x-request-id` when it is a short printable-ASCII token, otherwise a UUID v4 is generated; hostile inputs are dropped to prevent header smuggling and log-field explosion. No request body bytes are inspected (transaction calldata is private user data). Co-Authored-By: Claude Opus 4.7 (1M context) * starknet_transaction_prover: skip health-probe request logs, tighten request-id plumbing Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Claude Opus 4.7 (1M context) --- Cargo.lock | 2 + Cargo.toml | 1 + crates/starknet_transaction_prover/Cargo.toml | 2 + .../starknet_transaction_prover/src/server.rs | 8 +- .../src/server/middleware_test_utils.rs | 37 ++++ .../src/server/request_log.rs | 181 ++++++++++++++++++ .../src/server/request_log_test.rs | 125 ++++++++++++ .../src/server/tls.rs | 2 +- 8 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 crates/starknet_transaction_prover/src/server/middleware_test_utils.rs create mode 100644 crates/starknet_transaction_prover/src/server/request_log.rs create mode 100644 crates/starknet_transaction_prover/src/server/request_log_test.rs diff --git a/Cargo.lock b/Cargo.lock index c161756050e..a1d73e549a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13169,7 +13169,9 @@ dependencies = [ "tower_ohttp", "tracing", "tracing-subscriber", + "tracing-test", "url", + "uuid 1.18.1", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b666d4ddc79..be988a18b2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -414,6 +414,7 @@ tracing-test = "0.2" trybuild = "1.0.105" unsigned-varint = "0.8.0" url = "2.5.0" +uuid = "1" validator = "0.20" void = "1.0.2" waker-fn = "1.2.0" diff --git a/crates/starknet_transaction_prover/Cargo.toml b/crates/starknet_transaction_prover/Cargo.toml index 1447e9db25d..4de5f83ca1f 100644 --- a/crates/starknet_transaction_prover/Cargo.toml +++ b/crates/starknet_transaction_prover/Cargo.toml @@ -57,6 +57,7 @@ tower_ohttp.workspace = true tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } url.workspace = true +uuid = { workspace = true, features = ["v4"] } [dev-dependencies] apollo_starknet_os_program.workspace = true @@ -73,6 +74,7 @@ rstest.workspace = true serde = { workspace = true, features = ["derive"] } starknet-types-core.workspace = true tower_ohttp = { workspace = true, features = ["testing"] } +tracing-test.workspace = true [lints] workspace = true diff --git a/crates/starknet_transaction_prover/src/server.rs b/crates/starknet_transaction_prover/src/server.rs index 932378d6d63..38e0f9abda3 100644 --- a/crates/starknet_transaction_prover/src/server.rs +++ b/crates/starknet_transaction_prover/src/server.rs @@ -40,7 +40,8 @@ pub const OHTTP_JSONRPSEE_BODY_BUILDER: fn(Full) -> HttpBody = HttpBody:: /// each call site. /// /// Layer order (tower makes the last-added layer innermost): -/// - `HealthLayer` sits outermost so `GET /health` is answered before any other middleware runs. +/// - `RequestLogLayer` is outermost so the latency it measures covers every other layer. +/// - `HealthLayer` sits inside it so probes complete before CORS/OHTTP. /// - `OhttpLayer` must sit OUTSIDE `CompressionLayer` so compression applies to the inner JSON-RPC /// response (the client's inner `Accept-Encoding` travels through BHTTP into jsonrpsee) rather /// than to the OHTTP ciphertext envelope. `MapRequestBodyLayer`/`MapResponseBodyLayer` keep @@ -49,6 +50,7 @@ pub const OHTTP_JSONRPSEE_BODY_BUILDER: fn(Full) -> HttpBody = HttpBody:: macro_rules! prover_http_middleware { ($cors_layer:expr, $ohttp_layer:expr $(,)?) => { ServiceBuilder::new() + .layer(RequestLogLayer) .layer(HealthLayer) .option_layer($cors_layer) .layer(MapRequestBodyLayer::new(HttpBody::new)) @@ -64,12 +66,16 @@ pub mod errors; pub mod health; pub mod log_redact; #[cfg(test)] +pub mod middleware_test_utils; +#[cfg(test)] pub mod mock_rpc; +pub mod request_log; pub mod rpc_api; pub mod rpc_impl; pub mod tls; pub use health::{HealthLayer, HEALTH_PATH}; +pub use request_log::{RequestLogLayer, REQUEST_ID_HEADER}; #[cfg(test)] mod rpc_spec_test; diff --git a/crates/starknet_transaction_prover/src/server/middleware_test_utils.rs b/crates/starknet_transaction_prover/src/server/middleware_test_utils.rs new file mode 100644 index 00000000000..bfa48208dd5 --- /dev/null +++ b/crates/starknet_transaction_prover/src/server/middleware_test_utils.rs @@ -0,0 +1,37 @@ +//! Shared fixtures for middleware-layer tests. + +use bytes::Bytes; +use http::{HeaderMap, Request, Response, StatusCode}; +use http_body_util::{BodyExt, Full}; +use jsonrpsee::server::HttpBody; + +use crate::server::request_log::REQUEST_ID_HEADER; + +/// Inner service that echoes the request's `x-request-id` into the response +/// body, so tests can observe the id downstream layers saw. +pub fn echo_request_id_service() -> impl tower::Service< + Request, + Response = Response, + Error = std::convert::Infallible, + Future = futures::future::Ready, std::convert::Infallible>>, +> + Clone { + tower::service_fn(|request: Request| { + let id = request + .headers() + .get(REQUEST_ID_HEADER) + .map(|value| value.to_str().expect("test ids are ASCII").to_string()) + .unwrap_or_default(); + let response = Response::builder() + .status(StatusCode::OK) + .body(HttpBody::new(Full::new(Bytes::from(id)))) + .expect("static body is infallible"); + futures::future::ready(Ok::<_, std::convert::Infallible>(response)) + }) +} + +/// Collects the response into its UTF-8 body string and headers. +pub async fn read_body_and_headers(response: Response) -> (String, HeaderMap) { + let (parts, body) = response.into_parts(); + let bytes = body.collect().await.expect("body collect").to_bytes(); + (String::from_utf8(bytes.to_vec()).expect("utf8 body"), parts.headers) +} diff --git a/crates/starknet_transaction_prover/src/server/request_log.rs b/crates/starknet_transaction_prover/src/server/request_log.rs new file mode 100644 index 00000000000..079dc32cdbb --- /dev/null +++ b/crates/starknet_transaction_prover/src/server/request_log.rs @@ -0,0 +1,181 @@ +//! tower middleware that logs one structured line per HTTP request and +//! propagates a request id. +//! +//! This is the outermost, envelope-level layer: it emits one log line with +//! `event="http_request"`, `request_id`, `method`, `path`, `status`, and +//! `latency_ms` per HTTP request, and echoes `request_id` on the response so +//! callers can quote it. The id is accepted from the incoming `x-request-id` +//! header or generated as a UUID v4. `GET /health` probes still get the id +//! echo but are exempt from logging — at typical probe periods they would +//! drown real traffic. +//! +//! It deliberately does NOT bind the id to a span covering the downstream +//! dispatch. For OHTTP traffic this layer runs on the *outer* envelope, whose +//! id is visible to the relay (echoed on the ciphertext response). Propagating +//! that id into the logs describing the *decapsulated* contents would create a +//! join key linking the relay's view (who) to the gateway's view (what), +//! defeating OHTTP unlinkability. Content-level correlation requires a +//! separate, envelope-unlinkable id bound below the OHTTP layer. +//! +//! For OHTTP traffic `status` and `path` also describe the outer envelope: the +//! outer status is 200 whenever decapsulation succeeds (RFC 9458), so inner +//! JSON-RPC failures never appear in this line. +//! +//! Body bytes are never inspected — transaction calldata is private user data +//! per the privacy-pool threat model. + +use std::pin::Pin; +use std::task::{Context, Poll}; +use std::time::Instant; + +use http::{HeaderValue, Method, Request, Response}; +use tower::{Layer, Service}; +use tracing::{info, warn}; + +use crate::server::health::HEALTH_PATH; + +#[cfg(test)] +#[path = "request_log_test.rs"] +mod request_log_test; + +/// HTTP header carrying the request id. +pub const REQUEST_ID_HEADER: &str = "x-request-id"; + +/// tower [`Layer`] producing [`RequestLogService`]. +#[derive(Clone, Copy, Default)] +pub struct RequestLogLayer; + +impl Layer for RequestLogLayer { + type Service = RequestLogService; + + fn layer(&self, inner: S) -> Self::Service { + RequestLogService { inner } + } +} + +#[derive(Clone)] +pub struct RequestLogService { + inner: S, +} + +impl Service> for RequestLogService +where + S: Service, Response = Response>, + S::Future: Send + 'static, + S::Error: Send + 'static, + RespB: Send + 'static, +{ + type Response = Response; + type Error = S::Error; + type Future = + Pin> + Send>>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, mut request: Request) -> Self::Future { + let request_id = extract_or_generate_request_id(&request); + let id_header_value = request_id_header_value(&request_id); + request.headers_mut().insert(REQUEST_ID_HEADER, id_header_value.clone()); + let is_health_probe = + request.method() == Method::GET && request.uri().path() == HEALTH_PATH; + let method = request.method().clone(); + let path = truncated_log_path(request.uri().path()); + let start = Instant::now(); + + let future = self.inner.call(request); + + Box::pin(async move { + let result = future.await; + let latency_ms = u64::try_from(start.elapsed().as_millis()).unwrap_or(u64::MAX); + match result { + Ok(mut response) => { + response.headers_mut().insert(REQUEST_ID_HEADER, id_header_value); + if !is_health_probe { + info!( + event = "http_request", + request_id = %request_id, + method = %method, + path = %path, + status = response.status().as_u16(), + latency_ms = latency_ms, + "HTTP request handled." + ); + } + Ok(response) + } + Err(err) => { + // The only per-request observation point before hyper + // aborts the connection without a response. + warn!( + event = "http_request", + request_id = %request_id, + method = %method, + path = %path, + latency_ms = latency_ms, + outcome = "service_error", + "HTTP request failed in tower stack." + ); + Err(err) + } + } + }) + } +} + +/// Cap on accepted incoming request-id length. Anything longer is dropped +/// in favour of a freshly generated id so the value never balloons into +/// tracing fields and log aggregators don't have to parse megabyte-scale ids. +const MAX_REQUEST_ID_LEN: usize = 128; + +/// Cap on the logged request path. The URI is attacker-controlled and this +/// layer is outermost, so an over-long path would bloat every log line; it is +/// truncated for logging only (the request itself is untouched). +const MAX_LOG_PATH_LEN: usize = 256; + +pub(crate) fn new_request_id() -> String { + uuid::Uuid::new_v4().to_string() +} + +/// Header value for an id produced by [`extract_or_generate_request_id`] or +/// [`new_request_id`] — always printable ASCII, so the conversion is +/// infallible. +pub(crate) fn request_id_header_value(request_id: &str) -> HeaderValue { + HeaderValue::from_str(request_id) + .expect("request id is printable ASCII by construction: fresh UUID or filtered header") +} + +/// Accepts the incoming `x-request-id` only when it's a short printable +/// ASCII token. CR/LF would let a client smuggle headers into the +/// response; arbitrary bytes (including unicode) make the value unsafe +/// to round-trip through `HeaderValue::from_str`. Any reject falls back +/// to a freshly generated UUID v4. +pub(crate) fn extract_or_generate_request_id(request: &Request) -> String { + request + .headers() + .get(REQUEST_ID_HEADER) + .and_then(|value| value.to_str().ok()) + .filter(|value| !value.is_empty() && value.len() <= MAX_REQUEST_ID_LEN) + .filter(|value| value.bytes().all(is_safe_request_id_byte)) + .map(|value| value.to_string()) + .unwrap_or_else(new_request_id) +} + +fn is_safe_request_id_byte(byte: u8) -> bool { + // Reject whitespace/CR/LF/NUL/control bytes so the id can't smuggle headers + // into the response or break structured-log parsers. + byte.is_ascii_graphic() +} + +/// Truncates an over-long path on a char boundary for safe logging. +fn truncated_log_path(path: &str) -> String { + if path.len() <= MAX_LOG_PATH_LEN { + return path.to_string(); + } + let mut end = MAX_LOG_PATH_LEN; + while !path.is_char_boundary(end) { + end -= 1; + } + format!("{}…(truncated)", &path[..end]) +} diff --git a/crates/starknet_transaction_prover/src/server/request_log_test.rs b/crates/starknet_transaction_prover/src/server/request_log_test.rs new file mode 100644 index 00000000000..87a0d22f78d --- /dev/null +++ b/crates/starknet_transaction_prover/src/server/request_log_test.rs @@ -0,0 +1,125 @@ +use bytes::Bytes; +use http::{Method, Request}; +use http_body_util::Full; +use jsonrpsee::server::HttpBody; +use tower::{Layer, ServiceExt}; +use tracing_test::traced_test; + +use crate::server::health::HEALTH_PATH; +use crate::server::middleware_test_utils::{echo_request_id_service, read_body_and_headers}; +use crate::server::request_log::{RequestLogLayer, REQUEST_ID_HEADER}; + +fn request_with_header(value: Option<&str>) -> Request { + let mut builder = Request::builder().method(Method::POST).uri("/"); + if let Some(value) = value { + builder = builder.header(REQUEST_ID_HEADER, value); + } + builder.body(HttpBody::new(Full::new(Bytes::new()))).expect("static body is infallible") +} + +#[tokio::test] +async fn echoes_supplied_request_id_on_response() { + let svc = RequestLogLayer.layer(echo_request_id_service()); + + let response = svc.oneshot(request_with_header(Some("client-supplied-id"))).await.unwrap(); + + let (body, headers) = read_body_and_headers(response).await; + assert_eq!(headers.get(REQUEST_ID_HEADER).unwrap(), "client-supplied-id"); + assert_eq!(body, "client-supplied-id"); +} + +#[tokio::test] +async fn generates_request_id_when_absent_and_echoes_it() { + let svc = RequestLogLayer.layer(echo_request_id_service()); + + let response = svc.oneshot(request_with_header(None)).await.unwrap(); + + let (body, headers) = read_body_and_headers(response).await; + let header_id = headers.get(REQUEST_ID_HEADER).unwrap().to_str().unwrap(); + // Body is what the inner service saw — they must match (the layer + // rewrote the request header before forwarding). + assert_eq!(header_id, body); + // Canonical UUID v4: 8-4-4-4-12 hex with hyphens. + assert!(uuid::Uuid::parse_str(header_id).is_ok(), "expected a UUID, got {header_id:?}"); + assert_eq!(uuid::Uuid::parse_str(header_id).unwrap().get_version_num(), 4); +} + +#[tokio::test] +async fn drops_non_ascii_incoming_id_and_generates_a_fresh_one() { + let mut request = request_with_header(None); + request + .headers_mut() + .insert(REQUEST_ID_HEADER, http::HeaderValue::from_bytes(b"\xff\xfe").unwrap()); + + let svc = RequestLogLayer.layer(echo_request_id_service()); + let response = svc.oneshot(request).await.unwrap(); + + let (_body, headers) = read_body_and_headers(response).await; + let header_id = headers.get(REQUEST_ID_HEADER).unwrap().to_str().unwrap(); + assert!(uuid::Uuid::parse_str(header_id).is_ok(), "should have generated a fresh UUID"); +} + +#[tokio::test] +async fn drops_request_id_containing_whitespace() { + // CRLF in header values is rejected by the http crate itself at parse + // time, so the residual concern is whitespace and other ASCII bytes + // that would confuse log parsers if echoed verbatim into structured + // fields. + for hostile_id in ["with space", "tab\there", "leading space "] { + let mut request = request_with_header(None); + request.headers_mut().insert( + REQUEST_ID_HEADER, + http::HeaderValue::from_bytes(hostile_id.as_bytes()).unwrap(), + ); + let svc = RequestLogLayer.layer(echo_request_id_service()); + let response = svc.oneshot(request).await.unwrap(); + let (_body, headers) = read_body_and_headers(response).await; + let header_id = headers.get(REQUEST_ID_HEADER).unwrap().to_str().unwrap(); + assert!( + uuid::Uuid::parse_str(header_id).is_ok(), + "expected fresh UUID for hostile input {hostile_id:?}, got {header_id:?}", + ); + } +} + +#[tokio::test] +async fn drops_oversize_request_id() { + let oversize_id = "a".repeat(2048); + let mut request = request_with_header(None); + request + .headers_mut() + .insert(REQUEST_ID_HEADER, http::HeaderValue::from_bytes(oversize_id.as_bytes()).unwrap()); + let svc = RequestLogLayer.layer(echo_request_id_service()); + let response = svc.oneshot(request).await.unwrap(); + let (_body, headers) = read_body_and_headers(response).await; + let header_id = headers.get(REQUEST_ID_HEADER).unwrap().to_str().unwrap(); + assert!(uuid::Uuid::parse_str(header_id).is_ok()); +} + +#[tokio::test] +#[traced_test] +async fn health_probe_is_not_logged_but_still_gets_id_echo() { + let svc = RequestLogLayer.layer(echo_request_id_service()); + let request = Request::builder() + .method(Method::GET) + .uri(HEALTH_PATH) + .body(HttpBody::new(Full::new(Bytes::new()))) + .expect("static body is infallible"); + + let response = svc.oneshot(request).await.unwrap(); + + let (_body, headers) = read_body_and_headers(response).await; + assert!(headers.contains_key(REQUEST_ID_HEADER), "id echo must still apply to probes"); + assert!(!logs_contain("http_request"), "health probes must not emit request log lines"); +} + +#[tokio::test] +#[traced_test] +async fn non_health_request_is_logged() { + let svc = RequestLogLayer.layer(echo_request_id_service()); + + svc.oneshot(request_with_header(Some("logged-id"))).await.unwrap(); + + assert!(logs_contain("http_request")); + assert!(logs_contain("logged-id")); +} diff --git a/crates/starknet_transaction_prover/src/server/tls.rs b/crates/starknet_transaction_prover/src/server/tls.rs index 67950a808a5..67c737ec9ac 100644 --- a/crates/starknet_transaction_prover/src/server/tls.rs +++ b/crates/starknet_transaction_prover/src/server/tls.rs @@ -27,7 +27,7 @@ use tower_http::map_request_body::MapRequestBodyLayer; use tower_http::map_response_body::MapResponseBodyLayer; use tracing::warn; -use crate::server::{HealthLayer, OhttpJsonrpseeLayer}; +use crate::server::{HealthLayer, OhttpJsonrpseeLayer, RequestLogLayer}; /// Maximum time allowed for a TLS handshake before the connection is dropped. const TLS_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(10); From d98bcb2cebd323ce37f1c7b47a6bd59e59b31315 Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Thu, 9 Jul 2026 16:36:28 +0300 Subject: [PATCH 12/53] starknet_transaction_prover: add committer utils unit tests (#14046) Covers state_maps_to_committer_state_diff (empty / nonces / storage / compiled class hashes) and validate_virtual_os_state_diff (valid storage, valid nonce, and rejection of storage deletion / contract deployment / contract declaration). --- .../src/running.rs | 2 + .../src/running/committer_utils_test.rs | 137 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 crates/starknet_transaction_prover/src/running/committer_utils_test.rs diff --git a/crates/starknet_transaction_prover/src/running.rs b/crates/starknet_transaction_prover/src/running.rs index 3df63aca76d..9383d0238e0 100644 --- a/crates/starknet_transaction_prover/src/running.rs +++ b/crates/starknet_transaction_prover/src/running.rs @@ -15,6 +15,8 @@ pub mod virtual_block_executor; #[cfg(test)] mod classes_provider_test; #[cfg(test)] +mod committer_utils_test; +#[cfg(test)] pub mod rpc_records; #[cfg(test)] mod rpc_records_test; diff --git a/crates/starknet_transaction_prover/src/running/committer_utils_test.rs b/crates/starknet_transaction_prover/src/running/committer_utils_test.rs new file mode 100644 index 00000000000..45c782156ee --- /dev/null +++ b/crates/starknet_transaction_prover/src/running/committer_utils_test.rs @@ -0,0 +1,137 @@ +use assert_matches::assert_matches; +use blockifier::state::cached_state::StateMaps; +use rstest::rstest; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::state::StorageKey; +use starknet_committer::block_committer::input::{ + StarknetStorageKey, + StarknetStorageValue, + StateDiff, +}; +use starknet_committer::patricia_merkle_tree::types::CompiledClassHash as CommitterCompiledClassHash; +use starknet_types_core::felt::Felt; + +use crate::errors::ProofProviderError; +use crate::running::committer_utils::{ + state_maps_to_committer_state_diff, + validate_virtual_os_state_diff, +}; + +fn address(value: u64) -> ContractAddress { + ContractAddress::try_from(Felt::from(value)).unwrap() +} + +fn state_diff_with_storage_value(value: Felt) -> StateDiff { + StateDiff { + storage_updates: [( + address(1), + [(StarknetStorageKey(StorageKey::from(1u32)), StarknetStorageValue(value))].into(), + )] + .into(), + ..Default::default() + } +} + +#[rstest] +#[case::empty(StateDiff::default())] +#[case::nonzero_storage(state_diff_with_storage_value(Felt::from(42u64)))] +#[case::nonce_update(StateDiff { + address_to_nonce: [(address(1), Nonce(Felt::from(1u64)))].into(), + ..Default::default() +})] +fn test_validate_accepts_valid_state_diff(#[case] state_diff: StateDiff) { + validate_virtual_os_state_diff(&state_diff).unwrap(); +} + +#[rstest] +#[case::storage_deletion("Storage deletion", state_diff_with_storage_value(Felt::ZERO))] +#[case::contract_deployment("Contract deployments", StateDiff { + address_to_class_hash: [(address(1), ClassHash(Felt::from(0x42u64)))].into(), + ..Default::default() +})] +#[case::contract_declaration("Contract declarations", StateDiff { + class_hash_to_compiled_class_hash: [( + ClassHash(Felt::from(0x42u64)), + CommitterCompiledClassHash(Felt::from(0x99u64)), + )] + .into(), + ..Default::default() +})] +fn test_validate_rejects_invalid_state_diff( + #[case] expected_error_substring: &str, + #[case] state_diff: StateDiff, +) { + assert_matches!( + validate_virtual_os_state_diff(&state_diff).unwrap_err(), + ProofProviderError::InvalidStateDiff(message) if message.contains(expected_error_substring) + ); +} + +#[rstest] +#[case::empty(StateMaps::default(), StateDiff::default())] +#[case::nonces( + { + let mut state_maps = StateMaps::default(); + state_maps.nonces.insert(address(1), Nonce(Felt::from(7u64))); + state_maps + }, + StateDiff { + address_to_nonce: [(address(1), Nonce(Felt::from(7u64)))].into(), + ..Default::default() + } +)] +#[case::storage( + { + let mut state_maps = StateMaps::default(); + state_maps.storage.insert((address(1), StorageKey::from(5u32)), Felt::from(100u64)); + state_maps + }, + StateDiff { + storage_updates: [( + address(1), + [(StarknetStorageKey(StorageKey::from(5u32)), StarknetStorageValue(Felt::from(100u64)))] + .into(), + )] + .into(), + ..Default::default() + } +)] +#[case::compiled_class_hashes( + { + let mut state_maps = StateMaps::default(); + state_maps + .compiled_class_hashes + .insert(ClassHash(Felt::from(0x42u64)), CompiledClassHash(Felt::from(0x99u64))); + state_maps + }, + StateDiff { + class_hash_to_compiled_class_hash: [( + ClassHash(Felt::from(0x42u64)), + CommitterCompiledClassHash(Felt::from(0x99u64)), + )] + .into(), + ..Default::default() + } +)] +#[case::class_hashes( + { + let mut state_maps = StateMaps::default(); + state_maps.class_hashes.insert(address(1), ClassHash(Felt::from(0x42u64))); + state_maps + }, + StateDiff { + address_to_class_hash: [(address(1), ClassHash(Felt::from(0x42u64)))].into(), + ..Default::default() + } +)] +#[case::declared_contracts_dropped( + { + let mut state_maps = StateMaps::default(); + state_maps.declared_contracts.insert(ClassHash(Felt::from(0x42u64)), true); + state_maps + }, + StateDiff::default() +)] +fn test_convert_state_maps(#[case] state_maps: StateMaps, #[case] expected_state_diff: StateDiff) { + assert_eq!(state_maps_to_committer_state_diff(state_maps), expected_state_diff); +} From f7dd6e1d7e174f43357e3f5b55ab86632f538362 Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Thu, 9 Jul 2026 16:53:49 +0300 Subject: [PATCH 13/53] starknet_transaction_prover,tower_ohttp: OHTTP-unlinkable request-id for decapsulated content (#14222) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * starknet_transaction_prover,tower_ohttp: OHTTP-unlinkable request-id for decapsulated content Tags downstream content logs with a request-id via a new `RequestSpanLayer` placed below the OHTTP layer. For plaintext it reuses the envelope id from `RequestLogLayer`; for an OHTTP-decapsulated request (marked with a new `tower_ohttp::Decapsulated` extension) it mints a FRESH UUID and discards any client-supplied inner id. The fresh inner id is never echoed back, so the relay-visible envelope id and the gateway's content-log id cannot be joined — preserving OHTTP unlinkability while still giving every request's downstream logs a correlatable id. Co-Authored-By: Claude Opus 4.7 (1M context) * starknet_transaction_prover,tower_ohttp: strip inner x-request-id at decapsulation Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Claude Opus 4.7 (1M context) --- .../starknet_transaction_prover/src/server.rs | 5 + .../src/server/ohttp_integration_test.rs | 132 ++++++++++++++---- .../src/server/request_span.rs | 80 +++++++++++ .../src/server/request_span_test.rs | 70 ++++++++++ .../src/server/tls.rs | 2 +- crates/tower_ohttp/src/bhttp_codec.rs | 14 +- crates/tower_ohttp/src/layer.rs | 40 +++++- crates/tower_ohttp/src/lib.rs | 14 ++ 8 files changed, 322 insertions(+), 35 deletions(-) create mode 100644 crates/starknet_transaction_prover/src/server/request_span.rs create mode 100644 crates/starknet_transaction_prover/src/server/request_span_test.rs diff --git a/crates/starknet_transaction_prover/src/server.rs b/crates/starknet_transaction_prover/src/server.rs index 38e0f9abda3..32d36e18826 100644 --- a/crates/starknet_transaction_prover/src/server.rs +++ b/crates/starknet_transaction_prover/src/server.rs @@ -47,6 +47,8 @@ pub const OHTTP_JSONRPSEE_BODY_BUILDER: fn(Full) -> HttpBody = HttpBody:: /// than to the OHTTP ciphertext envelope. `MapRequestBodyLayer`/`MapResponseBodyLayer` keep /// `HttpBody` on both sides of OHTTP to satisfy its symmetric-body bound; `HttpBody::new` is a /// zero-cost wrapper, so non-OHTTP requests still stream through unbuffered. +/// - `RequestSpanLayer` sits BELOW `OhttpLayer` so it spans the decapsulated inner request with a +/// fresh, envelope-unlinkable id (see `request_span`). macro_rules! prover_http_middleware { ($cors_layer:expr, $ohttp_layer:expr $(,)?) => { ServiceBuilder::new() @@ -55,6 +57,7 @@ macro_rules! prover_http_middleware { .option_layer($cors_layer) .layer(MapRequestBodyLayer::new(HttpBody::new)) .option_layer($ohttp_layer) + .layer(RequestSpanLayer) .layer(MapResponseBodyLayer::new(HttpBody::new)) .layer(CompressionLayer::new()) }; @@ -70,12 +73,14 @@ pub mod middleware_test_utils; #[cfg(test)] pub mod mock_rpc; pub mod request_log; +pub mod request_span; pub mod rpc_api; pub mod rpc_impl; pub mod tls; pub use health::{HealthLayer, HEALTH_PATH}; pub use request_log::{RequestLogLayer, REQUEST_ID_HEADER}; +pub use request_span::RequestSpanLayer; #[cfg(test)] mod rpc_spec_test; diff --git a/crates/starknet_transaction_prover/src/server/ohttp_integration_test.rs b/crates/starknet_transaction_prover/src/server/ohttp_integration_test.rs index d09e5080dc5..ebe2f5582f0 100644 --- a/crates/starknet_transaction_prover/src/server/ohttp_integration_test.rs +++ b/crates/starknet_transaction_prover/src/server/ohttp_integration_test.rs @@ -1,8 +1,7 @@ //! Integration tests for the sequencer's OHTTP wiring. These tests exercise //! the `tower_ohttp::OhttpLayer` with `jsonrpsee::server::HttpBody` as the -//! response body type and the same middleware stack used in production -//! (`OhttpLayer` outermost, `CompressionLayer` between OHTTP and the inner -//! service). +//! response body type, and — where the layer order matters — the production +//! middleware chain itself via `prover_http_middleware!`. //! //! The body-type-agnostic layer behavior (method/path/status/content-type //! preservation, error paths, body size limits, passthrough) is covered by @@ -16,9 +15,9 @@ use std::io::Read; use flate2::read::GzDecoder; use http::header; -use http_body_util::{BodyExt, Full}; +use http_body_util::BodyExt; use jsonrpsee::server::HttpBody; -use tower::{BoxError, Layer, Service}; +use tower::{BoxError, Layer, Service, ServiceBuilder}; use tower_http::compression::CompressionLayer; use tower_http::cors::CorsLayer; use tower_http::map_request_body::MapRequestBodyLayer; @@ -30,15 +29,13 @@ use tower_ohttp::test_utils::{ }; use tower_ohttp::OhttpLayer; +use crate::server::request_log::{RequestLogLayer, REQUEST_ID_HEADER}; +use crate::server::request_span::RequestSpanLayer; +use crate::server::{HealthLayer, OHTTP_JSONRPSEE_BODY_BUILDER}; + const DEFAULT_BODY_LIMIT: usize = 102_400; const KEY_CACHE_SECS: u64 = 3600; -/// Body builder for jsonrpsee's `HttpBody`. Returned as a `fn` pointer to -/// give `OhttpLayer` a sized, `Copy` closure type without an `as` cast. -fn body_builder() -> fn(Full) -> HttpBody { - HttpBody::new -} - /// Echo service with jsonrpsee's `HttpBody` on both sides — matches the /// layer's new symmetric-body inner service bound. async fn jsonrpsee_echo_service( @@ -67,8 +64,12 @@ fn ohttp_http_request(encapsulated: Vec) -> http::Request { #[tokio::test] async fn ohttp_round_trip_with_jsonrpsee_body() { let gateway = test_gateway(); - let layer = - OhttpLayer::new(gateway.clone(), DEFAULT_BODY_LIMIT, KEY_CACHE_SECS, body_builder()); + let layer = OhttpLayer::new( + gateway.clone(), + DEFAULT_BODY_LIMIT, + KEY_CACHE_SECS, + OHTTP_JSONRPSEE_BODY_BUILDER, + ); let mut svc = layer.layer(tower::service_fn(jsonrpsee_echo_service)); let json_body = br#"{"jsonrpc":"2.0","method":"starknet_specVersion","id":1}"#; @@ -85,24 +86,21 @@ async fn ohttp_round_trip_with_jsonrpsee_body() { assert_eq!(decapsulated.body, json_body); } -/// Verify the full production `ServiceBuilder` chain compresses the *inner* -/// JSON-RPC response and leaves the *outer* OHTTP envelope uncompressed. -/// Mirrors the exact chain in `server.rs`/`tls.rs`, so any drift in layer -/// order or a missing `MapResponseBodyLayer` will break this test. +/// Verify the production middleware chain compresses the *inner* JSON-RPC +/// response and leaves the *outer* OHTTP envelope uncompressed. Runs the +/// actual `prover_http_middleware!` chain, so any layer reorder that breaks +/// compress-then-encrypt fails here. #[tokio::test] async fn production_chain_compresses_inner_not_outer() { let gateway = test_gateway(); - let ohttp_layer = - OhttpLayer::new(gateway.clone(), DEFAULT_BODY_LIMIT, KEY_CACHE_SECS, body_builder()); - - // Replicates the production ServiceBuilder chain from `server.rs`/`tls.rs`. - // Must be kept in sync with those files. - let mut svc = tower::ServiceBuilder::new() - .option_layer(None::) - .layer(MapRequestBodyLayer::new(HttpBody::new)) - .option_layer(Some(ohttp_layer)) - .layer(MapResponseBodyLayer::new(HttpBody::new)) - .layer(CompressionLayer::new()) + let ohttp_layer = OhttpLayer::new( + gateway.clone(), + DEFAULT_BODY_LIMIT, + KEY_CACHE_SECS, + OHTTP_JSONRPSEE_BODY_BUILDER, + ); + + let mut svc = prover_http_middleware!(None::, Some(ohttp_layer)) .service(tower::service_fn(jsonrpsee_echo_service)); // Body must be large enough for gzip to actually compress. @@ -158,8 +156,12 @@ async fn production_chain_compresses_inner_not_outer() { #[tokio::test] async fn non_ohttp_request_passes_through_jsonrpsee() { let gateway = test_gateway(); - let layer = - OhttpLayer::new(gateway.clone(), DEFAULT_BODY_LIMIT, KEY_CACHE_SECS, body_builder()); + let layer = OhttpLayer::new( + gateway.clone(), + DEFAULT_BODY_LIMIT, + KEY_CACHE_SECS, + OHTTP_JSONRPSEE_BODY_BUILDER, + ); let mut svc = layer.layer(tower::service_fn(jsonrpsee_echo_service)); let json_body = br#"{"jsonrpc":"2.0","method":"starknet_specVersion","id":1}"#; @@ -176,3 +178,73 @@ async fn non_ohttp_request_passes_through_jsonrpsee() { let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(body.as_ref(), json_body); } + +/// End-to-end OHTTP unlinkability: the request-id echoed on the OUTER +/// (relay-visible) response must differ from the fresh id bound to the +/// decapsulated inner dispatch, and the client-supplied inner id must be +/// discarded — so no shared key links the relay's view to the gateway's. +/// Runs the actual `prover_http_middleware!` chain, so a layer reorder that +/// reverts either property fails here. +#[tokio::test] +async fn ohttp_inner_request_id_unlinkable_from_envelope() { + let gateway = test_gateway(); + let ohttp_layer = OhttpLayer::new( + gateway.clone(), + DEFAULT_BODY_LIMIT, + KEY_CACHE_SECS, + OHTTP_JSONRPSEE_BODY_BUILDER, + ); + + // Inner service echoes the request-id it observes into the response body. + let echo_id = tower::service_fn(|req: http::Request| async move { + let id = req.headers().get(REQUEST_ID_HEADER).map_or("", |v| v.to_str().unwrap()); + Ok::<_, BoxError>( + http::Response::builder() + .status(http::StatusCode::OK) + .body(HttpBody::from(id.as_bytes().to_vec())) + .unwrap(), + ) + }); + + let mut svc = prover_http_middleware!(None::, Some(ohttp_layer)).service(echo_id); + + // The envelope carries a client-chosen inner id that must be discarded. + let (encapsulated, client_response) = encapsulate_bhttp_request( + &gateway, + "POST", + "/", + b"", + &[("x-request-id", b"inner-client-id")], + ); + + // The outer envelope request carries the relay-visible id. + let mut outer_request = ohttp_http_request(encapsulated); + outer_request + .headers_mut() + .insert(REQUEST_ID_HEADER, http::HeaderValue::from_static("envelope-relay-id")); + + let response = svc.call(outer_request).await.unwrap(); + + // The outer (relay-visible) response echoes the envelope id. + let envelope_id = + response.headers().get(REQUEST_ID_HEADER).unwrap().to_str().unwrap().to_owned(); + assert_eq!(envelope_id, "envelope-relay-id"); + + let encrypted_body = response.into_body().collect().await.unwrap().to_bytes(); + let decapsulated = decapsulate_bhttp_response(client_response, &encrypted_body); + assert_eq!(decapsulated.status, 200); + let inner_id = String::from_utf8(decapsulated.body).expect("utf8 inner id"); + + assert_ne!(inner_id, envelope_id, "inner id must not equal the relay-visible envelope id"); + assert_ne!(inner_id, "inner-client-id", "client-supplied inner id must be discarded"); + assert!( + uuid::Uuid::parse_str(&inner_id).is_ok(), + "inner id must be a fresh UUID, got {inner_id:?}" + ); + // No id is set on the inner *response*, so nothing — neither the envelope + // id nor the fresh content id — leaks into the encrypted reply's headers. + assert!( + decapsulated.bhttp_message.header().get(b"x-request-id").is_none(), + "inner OHTTP response must not carry an x-request-id header" + ); +} diff --git a/crates/starknet_transaction_prover/src/server/request_span.rs b/crates/starknet_transaction_prover/src/server/request_span.rs new file mode 100644 index 00000000000..413a1d205bf --- /dev/null +++ b/crates/starknet_transaction_prover/src/server/request_span.rs @@ -0,0 +1,80 @@ +//! tower middleware that binds an `http_request` tracing span over the +//! downstream dispatch. It sits BELOW the OHTTP layer, so it sees the +//! decapsulated inner request (or a plaintext pass-through), and picks the id: +//! +//! - **plaintext** — reuse the `x-request-id` the outer layer already assigned; +//! - **OHTTP-decapsulated** ([`tower_ohttp::Decapsulated`]) — mint a fresh id (any client-supplied +//! inner id was already stripped at decapsulation). The relay never observes it, so the +//! relay-visible envelope id and this content-log id share no join key. Note the residual: at low +//! traffic volume, timestamp proximity in persisted logs still permits probabilistic correlation +//! — an OHTTP traffic-analysis property id separation cannot eliminate. +//! +//! See [`super::request_log`] for why the envelope and content ids are kept +//! separate (OHTTP unlinkability). + +use std::task::{Context, Poll}; + +use http::{Request, Response}; +use tower::{Layer, Service}; +use tower_ohttp::Decapsulated; +use tracing::instrument::Instrumented; +use tracing::{info_span, Instrument}; + +use crate::server::request_log::{ + extract_or_generate_request_id, + new_request_id, + request_id_header_value, + REQUEST_ID_HEADER, +}; + +#[cfg(test)] +#[path = "request_span_test.rs"] +mod request_span_test; + +/// tower [`Layer`] producing [`RequestSpanService`]. +#[derive(Clone, Copy, Default)] +pub struct RequestSpanLayer; + +impl Layer for RequestSpanLayer { + type Service = RequestSpanService; + + fn layer(&self, inner: S) -> Self::Service { + RequestSpanService { inner } + } +} + +#[derive(Clone)] +pub struct RequestSpanService { + inner: S, +} + +impl Service> for RequestSpanService +where + S: Service, Response = Response>, +{ + type Response = Response; + type Error = S::Error; + type Future = Instrumented; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, mut request: Request) -> Self::Future { + let request_id = if request.extensions().get::().is_some() { + // Fresh id, distinct from the relay-visible envelope id (OHTTP + // unlinkability). Inserted so downstream readers see the id the + // span carries. + let fresh_id = new_request_id(); + request.headers_mut().insert(REQUEST_ID_HEADER, request_id_header_value(&fresh_id)); + fresh_id + } else { + // Re-derives, via the shared validator, the exact id + // `RequestLogLayer` already assigned — the header is left + // untouched. This also keeps the layer correct standalone, + // e.g. in unit tests without `RequestLogLayer` upstream. + extract_or_generate_request_id(&request) + }; + self.inner.call(request).instrument(info_span!("http_request", request_id = %request_id)) + } +} diff --git a/crates/starknet_transaction_prover/src/server/request_span_test.rs b/crates/starknet_transaction_prover/src/server/request_span_test.rs new file mode 100644 index 00000000000..f800cde5d5c --- /dev/null +++ b/crates/starknet_transaction_prover/src/server/request_span_test.rs @@ -0,0 +1,70 @@ +use bytes::Bytes; +use http::{Method, Request}; +use http_body_util::Full; +use jsonrpsee::server::HttpBody; +use tower::{Layer, ServiceExt}; +use tower_ohttp::Decapsulated; + +use crate::server::middleware_test_utils::{echo_request_id_service, read_body_and_headers}; +use crate::server::request_log::{RequestLogLayer, REQUEST_ID_HEADER}; +use crate::server::request_span::RequestSpanLayer; + +#[tokio::test] +async fn plaintext_reuses_inbound_request_id() { + let request = Request::builder() + .method(Method::POST) + .uri("/") + .header(REQUEST_ID_HEADER, "reused-xyz") + .body(HttpBody::new(Full::new(Bytes::new()))) + .expect("static body is infallible"); + + let response = + RequestSpanLayer.layer(echo_request_id_service()).oneshot(request).await.unwrap(); + + let (body, _headers) = read_body_and_headers(response).await; + assert_eq!(body, "reused-xyz"); +} + +#[tokio::test] +async fn decapsulated_gets_fresh_id_discarding_inbound() { + let mut request = Request::builder() + .method(Method::POST) + .uri("/") + .header(REQUEST_ID_HEADER, "envelope-abc") + .body(HttpBody::new(Full::new(Bytes::new()))) + .expect("static body is infallible"); + request.extensions_mut().insert(Decapsulated); + + let response = + RequestSpanLayer.layer(echo_request_id_service()).oneshot(request).await.unwrap(); + + let (id, _headers) = read_body_and_headers(response).await; + assert_ne!(id, "envelope-abc", "must discard the client-supplied inner id"); + assert!(uuid::Uuid::parse_str(&id).is_ok(), "must mint a fresh UUID, got {id:?}"); +} + +/// The cross-layer plaintext contract: with `RequestLogLayer` (outer) stacked +/// over `RequestSpanLayer` (inner) and no inbound id, the id the outer layer +/// generates and echoes on the response must be the same id the inner layer +/// binds for the handler — one shared id end-to-end. +#[tokio::test] +async fn plaintext_log_and_span_layers_share_generated_id() { + let request = Request::builder() + .method(Method::POST) + .uri("/") + .body(HttpBody::new(Full::new(Bytes::new()))) + .expect("static body is infallible"); + + let svc = RequestLogLayer.layer(RequestSpanLayer.layer(echo_request_id_service())); + let response = svc.oneshot(request).await.unwrap(); + + let (handler_id, headers) = read_body_and_headers(response).await; + let echoed_id = + headers.get(REQUEST_ID_HEADER).expect("response carries the id").to_str().unwrap(); + + assert_eq!(echoed_id, handler_id, "echoed response id must equal the id the handler saw"); + assert!( + uuid::Uuid::parse_str(&handler_id).is_ok(), + "generated id must be a UUID, got {handler_id:?}" + ); +} diff --git a/crates/starknet_transaction_prover/src/server/tls.rs b/crates/starknet_transaction_prover/src/server/tls.rs index 67c737ec9ac..c28f597c390 100644 --- a/crates/starknet_transaction_prover/src/server/tls.rs +++ b/crates/starknet_transaction_prover/src/server/tls.rs @@ -27,7 +27,7 @@ use tower_http::map_request_body::MapRequestBodyLayer; use tower_http::map_response_body::MapResponseBodyLayer; use tracing::warn; -use crate::server::{HealthLayer, OhttpJsonrpseeLayer, RequestLogLayer}; +use crate::server::{HealthLayer, OhttpJsonrpseeLayer, RequestLogLayer, RequestSpanLayer}; /// Maximum time allowed for a TLS handshake before the connection is dropped. const TLS_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(10); diff --git a/crates/tower_ohttp/src/bhttp_codec.rs b/crates/tower_ohttp/src/bhttp_codec.rs index 8261e158761..851eeb0bbb6 100644 --- a/crates/tower_ohttp/src/bhttp_codec.rs +++ b/crates/tower_ohttp/src/bhttp_codec.rs @@ -11,6 +11,12 @@ use tracing::debug; use crate::errors::OhttpError; use crate::OHTTP_RESPONSE_CONTENT_TYPE; +/// Correlation-id header stripped from decapsulated inner requests. A +/// client-chosen id inside the encrypted envelope would otherwise reach +/// gateway logs as a stable, attacker-chosen join key, undermining OHTTP +/// unlinkability; downstream layers mint their own id instead. +const REQUEST_ID_HEADER: &[u8] = b"x-request-id"; + /// Rebuild a standard `http::Request>` from a parsed Binary HTTP /// message. /// @@ -18,7 +24,9 @@ use crate::OHTTP_RESPONSE_CONTENT_TYPE; /// missing either is rejected with `OhttpError::InvalidFormat` rather than /// silently defaulted. All BHTTP header fields are forwarded to the inner /// request — this includes `content-type`, `accept-encoding`, and anything -/// else the client specified inside the encrypted envelope. +/// else the client specified inside the encrypted envelope — except +/// `content-length` (recomputed from the body) and `x-request-id` (stripped; +/// see `REQUEST_ID_HEADER`). pub fn rebuild_request( bhttp_message: &bhttp::Message, ) -> Result>, OhttpError> { @@ -50,7 +58,9 @@ pub fn rebuild_request( // CompressionLayer to compress the response before OHTTP encryption. // Skip Content-Length — we set it from the body length above. for field in bhttp_message.header().fields() { - if field.name().eq_ignore_ascii_case(b"content-length") { + if field.name().eq_ignore_ascii_case(b"content-length") + || field.name().eq_ignore_ascii_case(REQUEST_ID_HEADER) + { continue; } builder = builder.header(field.name(), field.value()); diff --git a/crates/tower_ohttp/src/layer.rs b/crates/tower_ohttp/src/layer.rs index 762066a62fe..15e9deee6bc 100644 --- a/crates/tower_ohttp/src/layer.rs +++ b/crates/tower_ohttp/src/layer.rs @@ -34,7 +34,7 @@ use tracing::debug; use crate::bhttp_codec::{encapsulate_response, rebuild_request}; use crate::errors::OhttpError; use crate::gateway::OhttpGateway; -use crate::{OHTTP_KEYS_PATH, OHTTP_REQUEST_CONTENT_TYPE}; +use crate::{Decapsulated, OHTTP_KEYS_PATH, OHTTP_REQUEST_CONTENT_TYPE}; /// Shared runtime state for the OHTTP gateway. struct OhttpState { @@ -194,7 +194,11 @@ where OhttpError::InvalidFormat("Invalid Binary HTTP message") })?; - let inner_request = rebuild_request(&bhttp_message)?.map(build_body); + let mut inner_request = rebuild_request(&bhttp_message)?.map(build_body); + // Mark the request so downstream layers can tell decapsulated + // traffic apart from plaintext pass-through (e.g. to assign a + // fresh, envelope-unlinkable request id). + inner_request.extensions_mut().insert(Decapsulated); inner.oneshot(inner_request).await.map_err(|error| { debug!("Inner service error after successful OHTTP decapsulation: {error:?}"); @@ -267,6 +271,38 @@ mod tests { assert_eq!(response.body, body); } + #[tokio::test] + async fn decapsulation_strips_client_supplied_request_id() { + // A client-chosen x-request-id inside the encrypted envelope must never + // reach the inner service — it would land in gateway logs as a stable, + // attacker-chosen join key (see `Decapsulated` in lib.rs). + let layer = test_layer(); + let svc = layer.layer(tower::service_fn( + |request: http::Request>| async move { + let saw_request_id = + if request.headers().contains_key("x-request-id") { "true" } else { "false" }; + Ok::<_, tower::BoxError>( + http::Response::builder() + .status(http::StatusCode::OK) + .header("x-echo-saw-request-id", saw_request_id) + .body(http_body_util::Full::new(bytes::Bytes::new())) + .unwrap(), + ) + }, + )); + let mut harness = TestHarness { gateway: test_gateway(), svc }; + + let response = harness + .ohttp_round_trip("POST", "/", b"", &[("x-request-id", b"client-inner-id")]) + .await; + + assert_eq!(response.status, 200); + assert_eq!( + response.bhttp_message.header().get(b"x-echo-saw-request-id").unwrap(), + b"false" + ); + } + #[tokio::test] async fn non_post_method_round_trip() { // GET /health encapsulated in OHTTP must reach the inner service as GET. diff --git a/crates/tower_ohttp/src/lib.rs b/crates/tower_ohttp/src/lib.rs index ce67590edde..31069ca33f0 100644 --- a/crates/tower_ohttp/src/lib.rs +++ b/crates/tower_ohttp/src/lib.rs @@ -34,6 +34,20 @@ pub use errors::OhttpError; pub use gateway::OhttpGateway; pub use layer::{OhttpLayer, OhttpService}; +/// Marker inserted into the extensions of a request rebuilt from a decapsulated +/// OHTTP envelope, before it is forwarded to the inner service. Downstream +/// layers can check for it (`request.extensions().get::()`) to +/// distinguish envelope-decapsulated traffic from plaintext pass-through — +/// the two are otherwise indistinguishable once the inner request is rebuilt. +/// +/// Layers may key privacy decisions on this marker (e.g. minting a request id +/// unlinkable to the envelope). Extensions are silently dropped by any +/// intermediate layer that rebuilds the request, so the marker is not the last +/// line of defense: `x-request-id` is already stripped at decapsulation, so a +/// lost marker costs log ergonomics, never unlinkability. +#[derive(Clone, Copy, Debug)] +pub struct Decapsulated; + pub(crate) const OHTTP_REQUEST_CONTENT_TYPE: &str = "message/ohttp-req"; pub(crate) const OHTTP_RESPONSE_CONTENT_TYPE: &str = "message/ohttp-res"; pub(crate) const OHTTP_KEYS_PATH: &str = "/ohttp-keys"; From 976582fce52f71c713b12e08a90320c1166fe469 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Thu, 9 Jul 2026 18:13:00 +0300 Subject: [PATCH 14/53] apollo_config_manager_config: default config sampling interval to 20s (#14742) Co-authored-by: Claude Opus 4.8 (1M context) --- crates/apollo_config_manager_config/src/config.rs | 2 +- .../resources/app_configs/config_manager_config.json | 2 +- .../resources/app_configs/replacer_config_manager_config.json | 2 +- crates/apollo_node/resources/config_schema.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/apollo_config_manager_config/src/config.rs b/crates/apollo_config_manager_config/src/config.rs index 2204ef2aca9..8be29d2fd2e 100644 --- a/crates/apollo_config_manager_config/src/config.rs +++ b/crates/apollo_config_manager_config/src/config.rs @@ -32,7 +32,7 @@ impl SerializeConfig for ConfigManagerConfig { impl Default for ConfigManagerConfig { fn default() -> Self { - Self { enable_config_updates: false, config_update_interval_secs: 60.0 } + Self { enable_config_updates: false, config_update_interval_secs: 20.0 } } } diff --git a/crates/apollo_deployments/resources/app_configs/config_manager_config.json b/crates/apollo_deployments/resources/app_configs/config_manager_config.json index 801fd5c1f8d..742e1ea3a43 100644 --- a/crates/apollo_deployments/resources/app_configs/config_manager_config.json +++ b/crates/apollo_deployments/resources/app_configs/config_manager_config.json @@ -1,4 +1,4 @@ { - "config_manager_config.config_update_interval_secs": 60.0, + "config_manager_config.config_update_interval_secs": 20.0, "config_manager_config.enable_config_updates": true } diff --git a/crates/apollo_deployments/resources/app_configs/replacer_config_manager_config.json b/crates/apollo_deployments/resources/app_configs/replacer_config_manager_config.json index 29c25c995b3..b20a4bc995a 100644 --- a/crates/apollo_deployments/resources/app_configs/replacer_config_manager_config.json +++ b/crates/apollo_deployments/resources/app_configs/replacer_config_manager_config.json @@ -1,4 +1,4 @@ { - "config_manager_config.config_update_interval_secs": 60.0, + "config_manager_config.config_update_interval_secs": 20.0, "config_manager_config.enable_config_updates": true } diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 9001ce6515c..70000431765 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -2457,7 +2457,7 @@ "config_manager_config.config_update_interval_secs": { "description": "Update interval in seconds for config updates", "privacy": "Public", - "value": 60.0 + "value": 20.0 }, "config_manager_config.enable_config_updates": { "description": "Enables the resampling of the config every `config_update_interval_secs` seconds", From 505b20aaf4e6612c23f0784336076460abfac9ce Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 09:32:35 +0300 Subject: [PATCH 15/53] apollo_cairo_utils,apollo_staking: bound retdata array length to remaining felts (#14526) (#14747) (cherry picked from commit 72b1549ec46d9b972c9eaeefe4df46665b0d2ded) Co-authored-by: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> --- commitlint.config.js | 1 + crates/apollo_cairo_utils/src/lib.rs | 13 +++++++++++++ crates/apollo_staking/src/contract_types_test.rs | 1 + 3 files changed, 15 insertions(+) diff --git a/commitlint.config.js b/commitlint.config.js index 4bbc1035e0e..58976131bed 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -14,6 +14,7 @@ const AllowedScopes = ['apollo_base_layer_tests', 'apollo_compile_to_casm', 'apollo_compile_to_casm_types', 'apollo_sierra_compilation_config', + 'apollo_cairo_utils', 'apollo_compile_to_native', 'apollo_compile_to_native_types', 'apollo_config', diff --git a/crates/apollo_cairo_utils/src/lib.rs b/crates/apollo_cairo_utils/src/lib.rs index df18aa73011..635c12a0efe 100644 --- a/crates/apollo_cairo_utils/src/lib.rs +++ b/crates/apollo_cairo_utils/src/lib.rs @@ -91,6 +91,19 @@ where RetdataDeserializationError::USizeConversionError { felt: raw_num_items } })?; + // Each array element consumes at least one Felt, so a declared count larger than the + // number of remaining Felts cannot be valid. Validate before allocating to prevent a + // contract-controlled length felt from triggering an unbounded `Vec::with_capacity`. + let num_remaining_felts = iter.len(); + if num_items > num_remaining_felts { + return Err(RetdataDeserializationError::InvalidObjectLength { + message: format!( + "declared array length {num_items} exceeds {num_remaining_felts} remaining \ + retdata felts" + ), + }); + } + let mut result = Vec::with_capacity(num_items); for _ in 0..num_items { let item = T::try_from_iter(&mut iter)?; diff --git a/crates/apollo_staking/src/contract_types_test.rs b/crates/apollo_staking/src/contract_types_test.rs index ea9acad701f..74f45e7fe04 100644 --- a/crates/apollo_staking/src/contract_types_test.rs +++ b/crates/apollo_staking/src/contract_types_test.rs @@ -105,6 +105,7 @@ fn staker_array_retdata_try_from_valid() { #[case::empty_retdata(vec![])] #[case::invalid_length_1(vec![Felt::ONE; 3])] #[case::invalid_length_2(vec![Felt::ONE; 10])] +#[case::declared_length_exceeds_retdata(vec![Felt::from(u64::MAX)])] fn staker_array_retdata_try_from_invalid_length(#[case] raw_felts: Vec) { let err = ContractStaker::from_retdata_many(Retdata(raw_felts)).unwrap_err(); assert_matches!(err, RetdataDeserializationError::InvalidObjectLength { .. }); From e85226a0bc544fbd05708c243deaa347ff40a4d0 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 09:32:49 +0300 Subject: [PATCH 16/53] apollo_protobuf: guard Felt252 conversion against malformed length (#14525) (#14746) (cherry picked from commit 29280322f6fa58394104c99684d1714f22b1c4b1) Co-authored-by: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> --- .../apollo_protobuf/src/converters/common.rs | 11 +++++++ .../src/converters/common_test.rs | 32 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 crates/apollo_protobuf/src/converters/common_test.rs diff --git a/crates/apollo_protobuf/src/converters/common.rs b/crates/apollo_protobuf/src/converters/common.rs index 01ad262e013..16b95d51b51 100644 --- a/crates/apollo_protobuf/src/converters/common.rs +++ b/crates/apollo_protobuf/src/converters/common.rs @@ -6,10 +6,21 @@ use super::ProtobufConversionError; use crate::protobuf; use crate::sync::{BlockHashOrNumber, Direction, Query}; +#[cfg(test)] +#[path = "common_test.rs"] +mod common_test; + impl TryFrom for starknet_types_core::felt::Felt { type Error = ProtobufConversionError; fn try_from(value: protobuf::Felt252) -> Result { let mut felt = [0; 32]; + if value.elements.len() != 32 { + return Err(ProtobufConversionError::BytesDataLengthMismatch { + type_description: "Felt252", + num_expected: 32, + value: value.elements, + }); + } felt.copy_from_slice(&value.elements); // TODO(Shahak): use from_bytes_checked once it's available. Ok(Self::from_bytes_be(&felt)) diff --git a/crates/apollo_protobuf/src/converters/common_test.rs b/crates/apollo_protobuf/src/converters/common_test.rs new file mode 100644 index 00000000000..88056c8dc07 --- /dev/null +++ b/crates/apollo_protobuf/src/converters/common_test.rs @@ -0,0 +1,32 @@ +use rstest::rstest; +use starknet_types_core::felt::Felt; + +use crate::converters::ProtobufConversionError; +use crate::protobuf; + +#[test] +fn felt252_round_trip() { + let felt = Felt::from(0x1234_5678_u64); + let protobuf_felt = protobuf::Felt252::from(felt); + let result = Felt::try_from(protobuf_felt).unwrap(); + assert_eq!(felt, result); +} + +#[rstest] +#[case::too_few_bytes(vec![0; 31])] +#[case::too_many_bytes(vec![0; 33])] +#[case::empty(vec![])] +fn felt252_too_few_bytes_returns_error(#[case] elements: Vec) { + let result = Felt::try_from(protobuf::Felt252 { elements }); + assert!( + matches!( + result, + Err(ProtobufConversionError::BytesDataLengthMismatch { + type_description: "Felt252", + num_expected: 32, + .. + }) + ), + "expected BytesDataLengthMismatch for Felt252, got {result:?}", + ); +} From 61df170f08dfe087aa42c2de5f2a2e5e5f767161 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 09:34:40 +0300 Subject: [PATCH 17/53] apollo_staking: validate staker set from staking contract response (#14528) (#14759) (cherry picked from commit 2397e6adea65eb71750f6aa74d46250b49804df6) Co-authored-by: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> --- .../apollo_staking/src/committee_provider.rs | 4 + crates/apollo_staking/src/staking_manager.rs | 31 +++++++ .../src/staking_manager_test.rs | 91 ++++++++++++++++++- 3 files changed, 124 insertions(+), 2 deletions(-) diff --git a/crates/apollo_staking/src/committee_provider.rs b/crates/apollo_staking/src/committee_provider.rs index b196ae4e06e..3d08cf89edc 100644 --- a/crates/apollo_staking/src/committee_provider.rs +++ b/crates/apollo_staking/src/committee_provider.rs @@ -34,6 +34,10 @@ pub enum CommitteeProviderError { InvalidHeight { height: BlockNumber }, #[error("Missing epoch information for epoch {epoch_id}.")] MissingInformation { epoch_id: u64 }, + #[error("Staking contract returned a duplicate staker address: {address}.")] + DuplicateStakerAddress { address: ContractAddress }, + #[error("Staking contract returned no usable stakers (empty or all zero-weight).")] + EmptyStakerSet, #[error(transparent)] StakingContractError(#[from] StakingContractError), #[error( diff --git a/crates/apollo_staking/src/staking_manager.rs b/crates/apollo_staking/src/staking_manager.rs index 49e4be86a02..2826bd88661 100644 --- a/crates/apollo_staking/src/staking_manager.rs +++ b/crates/apollo_staking/src/staking_manager.rs @@ -298,6 +298,9 @@ impl StakingManager { let contract_stakers = self.staking_contract.get_stakers_with_config(epoch, &dynamic_config).await?; + // Validate the staker set returned by the contract before building the committee. + let contract_stakers = validate_stakers(contract_stakers)?; + // Get the active committee config for this epoch (includes size and stakers). let active_config = get_config_for_epoch( &dynamic_config.default_committee, @@ -471,6 +474,34 @@ impl StakingManager { } } +// Validates the staker set returned by the staking contract before committee construction. +// Rejects the whole response on a duplicate address (a corruption signal), drops zero-weight +// stakers (they occupy a committee seat and count for voting membership but contribute nothing +// to weighted thresholds), and rejects an empty result (an all-zero-weight or empty response +// would make total_weight == 0 and panic proposer selection). +fn validate_stakers(stakers: StakerSet) -> CommitteeProviderResult { + let mut seen_addresses = HashSet::with_capacity(stakers.len()); + for staker in &stakers { + let new_address = seen_addresses.insert(staker.address); + if !new_address { + return Err(CommitteeProviderError::DuplicateStakerAddress { address: staker.address }); + } + } + + let (valid_stakers, filtered): (StakerSet, StakerSet) = + stakers.into_iter().partition(|staker| staker.weight.0 > 0); + + for staker in &filtered { + warn!("Filtered out zero-weight staker {:?} from the staking response.", staker.address); + } + + if valid_stakers.is_empty() { + return Err(CommitteeProviderError::EmptyStakerSet); + } + + Ok(valid_stakers) +} + impl CommitteeTrait for Committee { fn get_proposer(&self, height: BlockNumber, round: Round) -> CommitteeResult { if self.use_only_actual_proposer_selection { diff --git a/crates/apollo_staking/src/staking_manager_test.rs b/crates/apollo_staking/src/staking_manager_test.rs index 59446e68220..4f428f326d5 100644 --- a/crates/apollo_staking/src/staking_manager_test.rs +++ b/crates/apollo_staking/src/staking_manager_test.rs @@ -57,6 +57,16 @@ const STAKER_4: Staker = Staker { weight: StakingWeight(4000), public_key: Felt::from_raw([0, 0, 0, 4]), }; +const ZERO_WEIGHT_STAKER_5: Staker = Staker { + address: ContractAddress(PatriciaKey::from_hex_unchecked("0x5")), + weight: StakingWeight(0), + public_key: Felt::from_raw([0, 0, 0, 5]), +}; +const ZERO_WEIGHT_STAKER_6: Staker = Staker { + address: ContractAddress(PatriciaKey::from_hex_unchecked("0x6")), + weight: StakingWeight(0), + public_key: Felt::from_raw([0, 0, 0, 6]), +}; const EPOCH_0: Epoch = Epoch { epoch_id: 0, start_block: BlockNumber(0), epoch_length: 100 }; const EPOCH_1: Epoch = Epoch { epoch_id: 1, start_block: BlockNumber(1), epoch_length: 1000 }; @@ -152,7 +162,6 @@ fn make_generator_factory(value: u128) -> MockBlockRandomGeneratorFactory { } #[rstest] -#[case::no_stakers(vec![], vec![])] #[case::single_staker(vec![STAKER_1], vec![STAKER_1])] #[case::multiple_stakers_less_than_committee_size(vec![STAKER_1, STAKER_2], vec![STAKER_2, STAKER_1])] #[case::multiple_stakers_equal_to_committee_size(vec![STAKER_1, STAKER_2, STAKER_3], vec![STAKER_3, STAKER_2, STAKER_1])] @@ -186,6 +195,82 @@ async fn get_committee_success( assert_eq!(*committee.members(), expected_committee); } +// Builds a StakingManager whose contract returns `stakers` for EPOCH_1, with all surrounding +// epoch/block-hash mocks satisfied. Used by the staker-validation tests below. +fn manager_returning_stakers( + default_config: StakingManagerConfig, + mut contract: MockStakingContract, + stakers: StakerSet, +) -> StakingManager { + set_current_epoch(&mut contract, EPOCH_1); + set_previous_epoch(&mut contract, Some(EPOCH_0)); + set_stakers(&mut contract, EPOCH_1, stakers); + + StakingManager::new( + Arc::new(contract), + Arc::new(create_batcher_client_with_block_hash()), + Arc::new(create_state_sync_client_with_block_hash()), + Arc::new(make_generator_factory(0)), + StakingManagerConfig { + dynamic_config: test_config_with_committee_size(3), + ..default_config + }, + None, + ) +} + +#[rstest] +#[tokio::test] +async fn duplicate_staker_address_is_rejected( + default_config: StakingManagerConfig, + contract: MockStakingContract, +) { + let committee_manager = + manager_returning_stakers(default_config, contract, vec![STAKER_1, STAKER_2, STAKER_1]); + + let error = committee_manager.get_committee(E1_H1).await.err().unwrap(); + + assert_matches!( + error, + CommitteeProviderError::DuplicateStakerAddress { address } if address == STAKER_1.address + ); +} + +#[rstest] +#[case::all_zero_weight_stakers(vec![ZERO_WEIGHT_STAKER_5, ZERO_WEIGHT_STAKER_6])] +#[case::empty_staker_set_rejected(vec![])] +#[tokio::test] +async fn empty_staker_set_rejected( + #[case] stakers: StakerSet, + default_config: StakingManagerConfig, + contract: MockStakingContract, +) { + let committee_manager = manager_returning_stakers(default_config, contract, stakers); + + let error = committee_manager.get_committee(E1_H1).await.err().unwrap(); + + assert_matches!(error, CommitteeProviderError::EmptyStakerSet); +} + +#[rstest] +#[tokio::test] +async fn zero_weight_stakers_are_filtered_out( + default_config: StakingManagerConfig, + contract: MockStakingContract, +) { + // ZERO_WEIGHT_STAKER_5 must be dropped; the remaining stakers form the committee. + let committee_manager = manager_returning_stakers( + default_config, + contract, + vec![STAKER_2, ZERO_WEIGHT_STAKER_5, STAKER_1], + ); + + let committee = committee_manager.get_committee(E1_H1).await.unwrap(); + + // Sorted by weight descending: STAKER_2 (2000), STAKER_1 (1000). Zero-weight staker excluded. + assert_eq!(*committee.members(), vec![STAKER_2, STAKER_1]); +} + #[rstest] #[tokio::test] async fn get_committee_equal_weights_address_ordering( @@ -492,7 +577,9 @@ async fn get_proposer_empty_committee( ) { set_current_epoch(&mut contract, EPOCH_1); set_previous_epoch(&mut contract, Some(EPOCH_0)); - set_stakers(&mut contract, EPOCH_1, vec![]); + // Provide a valid staker set; the empty committee arises from a zero committee_size truncating + // it away (an empty staker response is rejected by validate_stakers before this point). + set_stakers(&mut contract, EPOCH_1, vec![STAKER_1]); let committee_manager = StakingManager::new( Arc::new(contract), From 92828fb68821b80b7950724393115776d32dd3bd Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:07:24 +0300 Subject: [PATCH 18/53] apollo_staking: bound next-epoch resolution window by the epoch length (#14689) (#14760) Heights were resolved to "current epoch + 1" for up to MIN_EPOCH_LENGTH blocks past the current epoch's end. When epochs are shorter than MIN_EPOCH_LENGTH, this attributed heights of later epochs to a stale epoch ID, so epoch-gated committee changes took effect at a different height on each node. Bound the window by min(MIN_EPOCH_LENGTH, epoch_length) so the resolved epoch is always exact; behavior is unchanged for epochs of at least MIN_EPOCH_LENGTH. (cherry picked from commit 86e00e8151cc92ae12747d616efb4c33f6cda9e1) Co-authored-by: Claude Fable 5 --- crates/apollo_staking/src/staking_manager.rs | 6 +- .../src/staking_manager_test.rs | 79 ++++++++++++++++++- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/crates/apollo_staking/src/staking_manager.rs b/crates/apollo_staking/src/staking_manager.rs index 2826bd88661..0961c1111b3 100644 --- a/crates/apollo_staking/src/staking_manager.rs +++ b/crates/apollo_staking/src/staking_manager.rs @@ -96,7 +96,11 @@ impl Epoch { fn within_next_epoch_min_bounds(&self, height: BlockNumber) -> bool { let next_epoch_start_block = BlockNumber(self.start_block.0 + self.epoch_length); - range_contains(height, next_epoch_start_block, MIN_EPOCH_LENGTH) + // Only heights guaranteed to fall within the next epoch may resolve to `epoch_id + 1`. + // The next epoch's length is unknown until it starts, so bound the window by the + // smallest known lower bound on epoch length. + let next_epoch_min_length = MIN_EPOCH_LENGTH.min(self.epoch_length); + range_contains(height, next_epoch_start_block, next_epoch_min_length) } } diff --git a/crates/apollo_staking/src/staking_manager_test.rs b/crates/apollo_staking/src/staking_manager_test.rs index 4f428f326d5..c1e91e405b1 100644 --- a/crates/apollo_staking/src/staking_manager_test.rs +++ b/crates/apollo_staking/src/staking_manager_test.rs @@ -73,10 +73,24 @@ const EPOCH_1: Epoch = Epoch { epoch_id: 1, start_block: BlockNumber(1), epoch_l const EPOCH_2: Epoch = Epoch { epoch_id: 2, start_block: BlockNumber(1001), epoch_length: 1000 }; const EPOCH_3: Epoch = Epoch { epoch_id: 3, start_block: BlockNumber(2001), epoch_length: 1000 }; +// Epochs shorter than MIN_EPOCH_LENGTH, matching the config-backed mock contract's epochs. +const SHORT_EPOCH_LENGTH: u64 = 30; +const SHORT_EPOCH_4: Epoch = + Epoch { epoch_id: 4, start_block: BlockNumber(120), epoch_length: SHORT_EPOCH_LENGTH }; +const SHORT_EPOCH_5: Epoch = + Epoch { epoch_id: 5, start_block: BlockNumber(150), epoch_length: SHORT_EPOCH_LENGTH }; +const SHORT_EPOCH_6: Epoch = + Epoch { epoch_id: 6, start_block: BlockNumber(180), epoch_length: SHORT_EPOCH_LENGTH }; +const SHORT_EPOCH_7: Epoch = + Epoch { epoch_id: 7, start_block: BlockNumber(210), epoch_length: SHORT_EPOCH_LENGTH }; + const E1_H1: BlockNumber = EPOCH_1.start_block; const E1_H2: BlockNumber = BlockNumber(EPOCH_1.start_block.0 + EPOCH_1.epoch_length - 1); const E2_H1: BlockNumber = EPOCH_2.start_block; -const E2_H2: BlockNumber = BlockNumber(EPOCH_2.start_block.0 + MIN_EPOCH_LENGTH + 1); +// The last height within the next epoch's min bounds, and the first height past them. +const E2_H_LAST_WITHIN_MIN_BOUNDS: BlockNumber = + BlockNumber(EPOCH_2.start_block.0 + MIN_EPOCH_LENGTH - 1); +const E2_H2: BlockNumber = BlockNumber(EPOCH_2.start_block.0 + MIN_EPOCH_LENGTH); const E3_H1: BlockNumber = EPOCH_3.start_block; fn test_config_with_committee_size(committee_size: usize) -> StakingManagerDynamicConfig { @@ -362,7 +376,10 @@ async fn get_committee_for_next_epoch( let committee = committee_manager.get_committee(E2_H1).await.unwrap().members().clone(); assert_eq!(committee.into_iter().collect::>(), HashSet::from([STAKER_1, STAKER_2])); - // 2. Invalid Query: E2_H2 exceeds the min bounds of the next epoch. + // 2. Valid Query: the last height within the next epoch's min bounds. + assert!(committee_manager.get_committee(E2_H_LAST_WITHIN_MIN_BOUNDS).await.is_ok()); + + // 3. Invalid Query: E2_H2 exceeds the min bounds of the next epoch. // Since the next epoch's length is not known at this point, we cannot know if this height // belongs to Epoch 2 or a future Epoch > 2. let err = committee_manager.get_committee(E2_H2).await.err().unwrap(); @@ -936,3 +953,61 @@ async fn get_actual_proposer_invalid_height( let err = committee_manager.get_committee(E2_H2).await.err().unwrap(); assert_matches!(err, CommitteeProviderError::InvalidHeight { .. }); } + +#[rstest] +#[tokio::test] +async fn get_committee_short_epochs_override_activates_at_start_epoch( + default_config: StakingManagerConfig, + mut contract: MockStakingContract, +) { + // Regression test: with epochs shorter than MIN_EPOCH_LENGTH, a node whose epoch cache + // was synced a few epochs before an override's start_epoch must still apply the override + // exactly from the override's first height, rather than serving the default committee + // under a stale epoch ID. + set_current_epoch(&mut contract, SHORT_EPOCH_5); + set_current_epoch(&mut contract, SHORT_EPOCH_6); + set_previous_epoch(&mut contract, Some(SHORT_EPOCH_4)); + set_stakers(&mut contract, SHORT_EPOCH_6, vec![STAKER_1, STAKER_2, STAKER_3]); + set_stakers(&mut contract, SHORT_EPOCH_7, vec![STAKER_1, STAKER_2, STAKER_3]); + + let default_committee = CommitteeConfig { + start_epoch: 0, + committee_size: 3, + stakers: vec![ + create_configured_staker(&STAKER_1, true), + create_configured_staker(&STAKER_2, true), + create_configured_staker(&STAKER_3, true), + ], + }; + // Shrink the committee to 2 members starting at epoch 7. + let override_committee = Some(CommitteeConfig { + start_epoch: SHORT_EPOCH_7.epoch_id, + committee_size: 2, + stakers: vec![ + create_configured_staker(&STAKER_2, true), + create_configured_staker(&STAKER_3, true), + ], + }); + + let committee_manager = StakingManager::new( + Arc::new(contract), + Arc::new(create_batcher_client_with_block_hash()), + Arc::new(create_state_sync_client_with_block_hash()), + Arc::new(make_generator_factory(0)), + StakingManagerConfig { + dynamic_config: StakingManagerDynamicConfig { default_committee, override_committee }, + ..default_config + }, + None, + ); + + // The last height of epoch 6 primes the epoch cache at epoch 5 and still gets the + // default committee. + let last_height_before_override = BlockNumber(SHORT_EPOCH_7.start_block.0 - 1); + let committee = committee_manager.get_committee(last_height_before_override).await.unwrap(); + assert_eq!(*committee.members(), vec![STAKER_3, STAKER_2, STAKER_1]); + + // The first height of epoch 7 must already get the override committee. + let committee = committee_manager.get_committee(SHORT_EPOCH_7.start_block).await.unwrap(); + assert_eq!(*committee.members(), vec![STAKER_3, STAKER_2]); +} From af08608512ece232ea2febea44ef8151f8cdbd5b Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:20:51 +0300 Subject: [PATCH 19/53] apollo_node_config: enforce config_manager runs locally (no remote client) (#14519) (#14748) The mempool fetches dynamic config from the config manager on every request and `.expect()`s the result. If the config manager client were remote, a transient network failure would panic and crash the mempool (security report H-5). The config manager is a local infrastructure component co-located with its consumers, so reject any execution mode that would build a remote client (`Remote` / `LocalExecutionWithRemoteEnabled`) at config validation time, turning a deep startup panic into an early, descriptive error and guaranteeing the client is always an in-process channel. (cherry picked from commit 3c4beae67822d51c8073adf675c151e0cfe2825e) Co-authored-by: Claude Opus 4.8 (1M context) --- crates/apollo_node_config/src/config_test.rs | 45 ++++++++++++++++++++ crates/apollo_node_config/src/node_config.rs | 24 ++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/crates/apollo_node_config/src/config_test.rs b/crates/apollo_node_config/src/config_test.rs index 05d347a936a..7d9c7493afe 100644 --- a/crates/apollo_node_config/src/config_test.rs +++ b/crates/apollo_node_config/src/config_test.rs @@ -209,6 +209,51 @@ fn validation_only_with_mempool_p2p_enabled_fails() { assert!(format!("{err:?}").contains("mempool_p2p"), "Unexpected error: {err:?}"); } +// The config manager is a local infrastructure component; running it remotely would make its +// consumers (e.g. the mempool) reach it over a network RPC that can fail mid-request. Both +// remote-capable execution modes must be rejected at validation time so the client is always local. +#[test] +fn config_manager_remote_is_rejected() { + // `config_manager_config` is None so the per-component "set iff running locally" check passes + // (remote is not running locally) and we reach the config_manager-specific validation. + let config = SequencerNodeConfig { + components: ComponentConfig { + config_manager: ReactiveComponentExecutionConfig::remote(VALID_URL.into(), VALID_PORT), + ..Default::default() + }, + config_manager_config: None, + state_sync_config: Some(state_sync_config_with_full_archive()), + ..Default::default() + }; + let err = config.validate_node_config().unwrap_err(); + assert!( + format!("{err:?}").contains("config_manager must run locally"), + "Unexpected error: {err:?}" + ); +} + +#[test] +fn config_manager_local_with_remote_enabled_is_rejected() { + // This mode runs locally, so the default (Some) config_manager_config satisfies the + // per-component check and we reach the config_manager-specific validation. + let config = SequencerNodeConfig { + components: ComponentConfig { + config_manager: ReactiveComponentExecutionConfig::local_with_remote_enabled( + VALID_URL.into(), + VALID_PORT, + ), + ..Default::default() + }, + state_sync_config: Some(state_sync_config_with_full_archive()), + ..Default::default() + }; + let err = config.validate_node_config().unwrap_err(); + assert!( + format!("{err:?}").contains("config_manager must run locally"), + "Unexpected error: {err:?}" + ); +} + #[test] fn validation_only_with_tx_ingestion_disabled_succeeds() { let config = SequencerNodeConfig { diff --git a/crates/apollo_node_config/src/node_config.rs b/crates/apollo_node_config/src/node_config.rs index 29adb72861e..4b02228af57 100644 --- a/crates/apollo_node_config/src/node_config.rs +++ b/crates/apollo_node_config/src/node_config.rs @@ -47,7 +47,7 @@ use serde::{Deserialize, Serialize}; use validator::{Validate, ValidationError}; use crate::component_config::{ComponentConfig, ValidateTxIngestionComponentsDisabled}; -use crate::component_execution_config::ExpectedComponentConfig; +use crate::component_execution_config::{ExpectedComponentConfig, ReactiveComponentExecutionMode}; use crate::monitoring::MonitoringConfig; use crate::version::VERSION_FULL; @@ -555,6 +555,28 @@ impl SequencerNodeConfig { ); validate_component_config_is_set_iff_running_locally!(state_sync, state_sync_config); + // The config manager is a local infrastructure component: every node runs its own instance + // and its consumers (e.g. the mempool) reach it over an in-process channel. Allowing it to + // run remotely would turn the per-request `get_*_dynamic_config` calls into network RPCs, + // where a transient failure would crash the consuming component. Enforce here that it is + // never exposed over (or reached over) the network so that client is always local. + match self.components.config_manager.execution_mode { + ReactiveComponentExecutionMode::Remote + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + return Err(ConfigError::ComponentConfigMismatch { + component_config_mismatch: format!( + "config_manager must run locally without a remote server (execution mode \ + must be Disabled or LocalExecutionWithRemoteDisabled), but is {:?}. It \ + is a local infrastructure component and must be co-located with its \ + consumers.", + self.components.config_manager.execution_mode + ), + }); + } + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::Disabled => {} + } + // Validate proposer_idle_detection_delay < batcher_deadline. // The batcher_deadline = proposal_timeout - build_proposal_margin. // If idle_delay >= batcher_deadline, idle detection never triggers (hard deadline fires From 2e80dff5c87918fd11f3d36fc56e96ce8081ae87 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:21:03 +0300 Subject: [PATCH 20/53] apollo_class_manager: recover orphaned class dir to avoid ENOTEMPTY sync deadlock (#14666) (#14750) A crash between renaming the staged class directory into place and committing the existence marker leaves an orphaned, non-empty persistent directory. On the next attempt std::fs::rename fails with ENOTEMPTY, which permanently wedges sync on that class. Remove a pre-existing persistent directory before the rename so the write self-heals; the directory is content-addressed by class hash, so it holds the same class. Covers both the regular and deprecated class write paths. (cherry picked from commit 7b2c35ed5a5aadd9f4128aa2266a71a9ac8242f7) Co-authored-by: Claude Opus 4.8 (1M context) --- .../apollo_class_manager/src/class_storage.rs | 31 +++++++--- .../src/class_storage_test.rs | 58 +++++++++++++++++++ 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/crates/apollo_class_manager/src/class_storage.rs b/crates/apollo_class_manager/src/class_storage.rs index 9a0a2ef1784..8342b689b32 100644 --- a/crates/apollo_class_manager/src/class_storage.rs +++ b/crates/apollo_class_manager/src/class_storage.rs @@ -24,7 +24,7 @@ use apollo_storage::StorageConfig; use starknet_api::class_cache::GlobalContractCache; use thiserror::Error; use tokio::task::AbortHandle; -use tracing::instrument; +use tracing::{instrument, warn}; use crate::metrics::{increment_n_classes, record_class_size, CairoClassType, ClassObjectType}; @@ -459,11 +459,7 @@ impl FsClassStorage { class.write_to_file(concat_sierra_filename(&tmp_dir))?; executable_class.write_to_file(concat_executable_filename(&tmp_dir))?; - // Atomically rename directory to persistent one. - let persistent_dir = self.get_persistent_dir_with_create(class_id)?; - std::fs::rename(tmp_dir, persistent_dir)?; - - Ok(()) + self.rename_to_persistent_dir(tmp_dir, class_id) } fn write_deprecated_class_atomically( @@ -475,8 +471,29 @@ impl FsClassStorage { let (_tmp_root, tmp_dir) = self.create_tmp_dir(class_id)?; class.write_to_file(concat_deprecated_executable_filename(&tmp_dir))?; - // Atomically rename directory to persistent one. + self.rename_to_persistent_dir(tmp_dir, class_id) + } + + /// Atomically moves the staged class directory `tmp_dir` into its content-addressed persistent + /// directory. + /// + /// Recovers from a previous partial write: a crash between this rename and committing the + /// existence marker (see `FsClassStorage::set_class`) can leave an orphaned, non-empty + /// persistent directory. `std::fs::rename` refuses to replace a non-empty directory and fails + /// with `ENOTEMPTY`, which permanently wedges sync on the class. Callers reach this only when + /// the existence marker is absent, and the directory is named by the class hash, so an existing + /// directory holds the same class; removing it lets the rename proceed and the marker get + /// written, restoring filesystem/marker consistency. + fn rename_to_persistent_dir( + &self, + tmp_dir: PathBuf, + class_id: ClassId, + ) -> FsClassStorageResult<()> { let persistent_dir = self.get_persistent_dir_with_create(class_id)?; + if persistent_dir.exists() { + warn!("Recovering orphaned class dir from a prior partial write: {persistent_dir:?}"); + std::fs::remove_dir_all(&persistent_dir)?; + } std::fs::rename(tmp_dir, persistent_dir)?; Ok(()) diff --git a/crates/apollo_class_manager/src/class_storage_test.rs b/crates/apollo_class_manager/src/class_storage_test.rs index 6a38ebbef08..0ad2329dcb7 100644 --- a/crates/apollo_class_manager/src/class_storage_test.rs +++ b/crates/apollo_class_manager/src/class_storage_test.rs @@ -189,6 +189,64 @@ async fn fs_storage_partial_write_no_atomic_marker() { assert_eq!(storage.get_executable(class_id), Ok(None)); } +/// Reproduces the production sync deadlock: a crash between writing the class files and committing +/// the existence marker leaves an orphaned, non-empty persistent directory. Re-running `set_class` +/// must recover and complete the write; previously `std::fs::rename` failed with ENOTEMPTY and +/// wedged sync on the class forever. +#[tokio::test] +async fn set_class_recovers_from_orphaned_class_dir() { + let persistent_root = tempfile::tempdir().unwrap(); + let class_hash_storage_path_prefix = tempfile::tempdir().unwrap(); + let mut storage = + FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); + + let class_id = ClassHash(felt!("0x1234")); + let class = RawClass::try_from(SierraContractClass::default()).unwrap(); + let executable_class = RawExecutableClass::test_casm_contract_class(); + let executable_class_hash_v2 = CompiledClassHash(felt!("0x5678")); + + // Simulate a partial write: class files are on disk, but the existence marker was never + // committed (the process crashed in between). + storage.write_class_atomically(class_id, class.clone(), executable_class.clone()).unwrap(); + assert_eq!(storage.get_executable_class_hash_v2(class_id), Ok(None)); + assert!(storage.get_persistent_dir(class_id).join("sierra").exists()); + + // `set_class` must recover the orphaned directory and complete the write. + storage + .set_class(class_id, class.clone(), executable_class_hash_v2, executable_class.clone()) + .unwrap(); + + // The class is now fully readable and marked as existent. + assert_eq!(storage.get_sierra(class_id).unwrap(), Some(class)); + assert_eq!(storage.get_executable(class_id).unwrap(), Some(executable_class)); + assert_eq!(storage.get_executable_class_hash_v2(class_id), Ok(Some(executable_class_hash_v2))); +} + +/// As above, for the deprecated-class write path: an orphaned, non-empty directory at the class's +/// persistent path must not permanently block `set_deprecated_class` with ENOTEMPTY. +#[tokio::test] +async fn set_deprecated_class_recovers_from_orphaned_class_dir() { + let persistent_root = tempfile::tempdir().unwrap(); + let class_hash_storage_path_prefix = tempfile::tempdir().unwrap(); + let mut storage = + FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); + + let class_id = ClassHash(felt!("0x1234")); + let executable_class = RawExecutableClass::test_casm_contract_class(); + + // Simulate a leftover, non-empty persistent directory without the deprecated-class file, so the + // class is still considered absent. + let persistent_dir = storage.get_persistent_dir(class_id); + std::fs::create_dir_all(&persistent_dir).unwrap(); + std::fs::write(persistent_dir.join("stale"), b"leftover").unwrap(); + assert!(!storage.contains_deprecated_class(class_id)); + + // `set_deprecated_class` must recover the orphaned directory and complete the write. + storage.set_deprecated_class(class_id, executable_class.clone()).unwrap(); + + assert_eq!(storage.get_deprecated_class(class_id).unwrap(), Some(executable_class)); +} + #[tokio::test] async fn cached_storage_none_flows_do_not_cache() { let persistent_root = tempfile::tempdir().unwrap(); From 3732da8bb93a7f0a28d2045aa9838c756cfa7715 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:21:14 +0300 Subject: [PATCH 21/53] apollo_dashboard: fall back to vector(1) so no-data doesn't fire consensus_block_number_stuck (#14705) (#14752) consensus_block_number_stuck paged p1 on a healthy Mainnet node-0: at Grafana eval time increase(consensus_block_number[120s]) intermittently returned no data (cross-region GMP recency on the lone us-west1 node), and `or vector(0)` turned that empty result into a hard 0 < 1 -> false page. Fall back to vector(1) instead: an absent/late series no longer reads as a halt, while a real halt keeps the gauge present (increase yields a present 0) and still fires immediately. A dead pod stays covered by pod_state_not_ready / pod_state_crashloopbackoff. (cherry picked from commit 72ced2bb7312d74f4ef361edef90068c808a24d8) Co-authored-by: Claude Opus 4.8 (1M context) --- crates/apollo_dashboard/resources/dev_grafana_alerts.json | 4 ++-- .../src/alert_scenarios/block_production_halt.rs | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts.json b/crates/apollo_dashboard/resources/dev_grafana_alerts.json index 39a5031389f..a7c5f635a6d 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts.json @@ -382,7 +382,7 @@ "name": "consensus_block_number_stuck", "title": "Consensus Block Number Stuck", "ruleGroup": "evaluation_rate_default", - "expr": "(sum(increase(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$$$consensus_block_number_stuck-sampling_window_secs-expression$$$s])) or vector(0)) and on() (is_observer{cluster=~\"$cluster\", namespace=~\"$namespace\"} == 0)", + "expr": "(sum(increase(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$$$consensus_block_number_stuck-sampling_window_secs-expression$$$s])) or vector(1)) and on() (is_observer{cluster=~\"$cluster\", namespace=~\"$namespace\"} == 0)", "conditions": [ { "evaluator": { @@ -408,7 +408,7 @@ "name": "consensus_block_number_stuck_long_time", "title": "Consensus Block Number Stuck Long Time", "ruleGroup": "evaluation_rate_default", - "expr": "(sum(increase(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$$$consensus_block_number_stuck_long_time-sampling_window_secs-expression$$$s])) or vector(0)) and on() (is_observer{cluster=~\"$cluster\", namespace=~\"$namespace\"} == 0)", + "expr": "(sum(increase(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$$$consensus_block_number_stuck_long_time-sampling_window_secs-expression$$$s])) or vector(1)) and on() (is_observer{cluster=~\"$cluster\", namespace=~\"$namespace\"} == 0)", "conditions": [ { "evaluator": { diff --git a/crates/apollo_dashboard/src/alert_scenarios/block_production_halt.rs b/crates/apollo_dashboard/src/alert_scenarios/block_production_halt.rs index 309ac65d48d..a01939e4e91 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/block_production_halt.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/block_production_halt.rs @@ -30,8 +30,13 @@ fn get_consensus_block_number_stuck( alert_severity: impl Into, ) -> Alert { let name = title.to_lowercase().replace(' ', "_"); + // Fall back to `vector(1)`, not `vector(0)`, when the metric has no samples: an absent/late + // series (e.g. transient query-time gaps for a remote-region node) must not read as a halt. + // A real halt keeps the gauge present, so `increase` yields a present `0` and still fires; + // a dead pod is caught by the `pod_state_not_ready` / `pod_state_crashloopbackoff` alerts. + // The fallback must stay `>=` the stuck threshold (`< 1`). let expr_template_string = format!( - "sum(increase({}[{{}}s])) or vector(0)", + "sum(increase({}[{{}}s])) or vector(1)", CONSENSUS_BLOCK_NUMBER.get_name_with_filter() ); Alert::new( From be9d3bf4f3da58e2859dd40e5bc94c12e05e70de Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:21:37 +0300 Subject: [PATCH 22/53] apollo_consensus: statically cap cached future votes to prevent OOM (#14500) (#14757) Future-height votes were cached with no count limit, no committee-membership check, and no signature verification (the voter is attacker-controlled), so a peer could flood the node with forged votes for future heights and grow future_votes without bound until OOM (H-19). Cap the per-height future-vote cache statically at MAX_COMMITTEE_SIZE * NUM_VOTE_TYPES * (future_height_round_limit + 1) -- an upper bound on what an honest committee could produce. Using the static MAX_COMMITTEE_SIZE (added to apollo_staking) rather than the live committee size keeps the cap always active, including on syncing nodes that never run a height locally, so future votes are still cached (crucial for catch-up) but bounded. Votes beyond the cap are dropped and logged. (cherry picked from commit c52fd6de4e6f384905b23fe872b3966b93bff644) Co-authored-by: Claude Opus 4.8 (1M context) --- crates/apollo_consensus/src/manager.rs | 38 +++++++++++++++-- crates/apollo_consensus/src/manager_test.rs | 42 ++++++++++++++++++- .../apollo_staking/src/committee_provider.rs | 5 +++ 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/crates/apollo_consensus/src/manager.rs b/crates/apollo_consensus/src/manager.rs index 88abe855b22..05d11f2db0b 100644 --- a/crates/apollo_consensus/src/manager.rs +++ b/crates/apollo_consensus/src/manager.rs @@ -24,7 +24,7 @@ use apollo_network::network_manager::BroadcastTopicClientTrait; use apollo_network_types::network_types::BroadcastedMessageMetadata; use apollo_protobuf::consensus::{BuildParam, ProposalInit, Vote, VoteType}; use apollo_protobuf::converters::ProtobufConversionError; -use apollo_staking::committee_provider::{CommitteeProvider, CommitteeTrait}; +use apollo_staking::committee_provider::{CommitteeProvider, CommitteeTrait, MAX_COMMITTEE_SIZE}; use apollo_time::time::{Clock, ClockExt, DefaultClock}; use futures::channel::mpsc::{self}; use futures::future::BoxFuture; @@ -211,6 +211,10 @@ pub struct EquivocationVoteReport { pub new_vote: Vote, } +/// Number of vote types a validator can cast per round ([`VoteType::Prevote`] and +/// [`VoteType::Precommit`]). Used to bound the future-vote cache. +const NUM_VOTE_TYPES: usize = 2; + /// Manages votes and proposals for future heights. #[derive(Debug)] struct ConsensusCache { @@ -286,8 +290,21 @@ impl ConsensusCache { self.get_current_height_proposals(height); } + /// Maximum number of future votes cached per height: an upper bound on the number of distinct, + /// non-equivocating votes an honest committee can produce across the cached future rounds + /// (`MAX_COMMITTEE_SIZE * NUM_VOTE_TYPES * rounds`). Uses the static `MAX_COMMITTEE_SIZE` + /// rather than the live committee size so the cap is always available (e.g. on syncing + /// nodes that never run a height locally). + fn future_votes_cap(&self) -> usize { + let cached_rounds = usize::try_from(self.future_msg_limit.future_height_round_limit) + .expect("future_height_round_limit should fit in usize") + + 1; + MAX_COMMITTEE_SIZE.saturating_mul(NUM_VOTE_TYPES).saturating_mul(cached_rounds) + } + /// Caches a vote for a future height. fn cache_future_vote(&mut self, vote: Vote) -> Result<(), Box> { + let cap = self.future_votes_cap(); let votes = self.future_votes.entry(vote.height).or_default(); // Find a vote in the list with the same type, round, and voter. If found, do not add it to // list. @@ -306,8 +323,23 @@ impl ConsensusCache { })) } } else { - // If no duplicate vote was found, we add the vote to the list. - votes.push(vote); + // Bound the cache to what an honest committee could produce. Since vote signatures are + // not yet verified, a peer can forge votes with arbitrary voter addresses; without this + // cap that would grow `future_votes` without bound and exhaust memory. + if votes.len() < cap { + votes.push(vote); + } else { + // TODO(Matan): once the network expands beyond the current trusted set, rate-limit + // this log (e.g. `trace_every_n_ms!`) so that dropping votes can't itself be used + // as a log-flood DoS. + warn!( + height = vote.height.0, + round = vote.round, + voter = ?vote.voter, + cap, + "Dropping future vote: per-height cache cap reached." + ); + } Ok(()) } } diff --git a/crates/apollo_consensus/src/manager_test.rs b/crates/apollo_consensus/src/manager_test.rs index cef3f87e550..6e704e5dc2f 100644 --- a/crates/apollo_consensus/src/manager_test.rs +++ b/crates/apollo_consensus/src/manager_test.rs @@ -26,6 +26,7 @@ use apollo_staking::committee_provider::{ MockCommitteeProvider, MockCommitteeTrait, Staker, + MAX_COMMITTEE_SIZE, }; use apollo_storage::StorageConfig; use apollo_test_utils::{get_rng, GetTestInstance}; @@ -41,7 +42,7 @@ use starknet_types_core::felt::Felt; use tokio::sync::Mutex; use tracing_test::traced_test; -use super::{run_consensus, MultiHeightManager, RunHeightRes}; +use super::{run_consensus, ConsensusCache, MultiHeightManager, RunHeightRes, NUM_VOTE_TYPES}; use crate::manager::CONSENSUS_RUNNING_PAST_STOP_HEIGHT; use crate::storage::MockHeightVotedStorageTrait; use crate::test_utils::{ @@ -1291,6 +1292,45 @@ async fn cache_future_vote_deduplication(consensus_config: ConsensusConfig) { ); } +/// Builds `n` distinct validator ids, for use as distinct vote voters. +fn distinct_voters(n: usize) -> Vec { + (0..n) + .map(|i| { + let offset = u64::try_from(i).expect("voter index should fit in u64"); + (DEFAULT_VALIDATOR_ID + 1 + offset).into() + }) + .collect() +} + +/// The number of future votes cached for a height is statically bounded by the +/// `MAX_COMMITTEE_SIZE`-derived cap, even when flooded with votes from arbitrary (forged) voters. +#[test] +fn future_votes_capped() { + let mut cache = ConsensusCache::::new(FutureMsgLimitsConfig::default()); + let cached_rounds = usize::try_from(FutureMsgLimitsConfig::default().future_height_round_limit) + .expect("future_height_round_limit should fit in usize") + + 1; + let expected_cap = MAX_COMMITTEE_SIZE * NUM_VOTE_TYPES * cached_rounds; + + // Flood more distinct-voter future votes than the cap allows. + for voter in distinct_voters(expected_cap + 5) { + cache.cache_future_vote(prevote(Some(Felt::ONE), HEIGHT_1, ROUND_0, voter)).unwrap(); + } + + assert_eq!(cache.future_votes[&HEIGHT_1].len(), expected_cap); +} + +/// Honest volume (well under the cap) is fully retained. +#[test] +fn future_votes_below_cap_are_all_retained() { + let mut cache = ConsensusCache::::new(FutureMsgLimitsConfig::default()); + let num_votes = 50; + for voter in distinct_voters(num_votes) { + cache.cache_future_vote(prevote(Some(Felt::ONE), HEIGHT_1, ROUND_0, voter)).unwrap(); + } + assert_eq!(cache.future_votes[&HEIGHT_1].len(), num_votes); +} + #[rstest] #[tokio::test] async fn manager_ignores_invalid_network_messages(consensus_config: ConsensusConfig) { diff --git a/crates/apollo_staking/src/committee_provider.rs b/crates/apollo_staking/src/committee_provider.rs index 3d08cf89edc..f9dfe481d75 100644 --- a/crates/apollo_staking/src/committee_provider.rs +++ b/crates/apollo_staking/src/committee_provider.rs @@ -12,6 +12,11 @@ use thiserror::Error; use crate::staking_contract::StakingContractError; +/// A generous upper bound on the committee size, used by consumers that need a static bound on +/// committee-derived quantities (e.g. sizing caches) without fetching the live committee. The +/// configured committee size is operationally ~100; this leaves ample headroom. +pub const MAX_COMMITTEE_SIZE: usize = 1000; + pub type StakerSet = Vec; #[cfg_attr(test, derive(Clone))] From 690b365d7f7cd47406d940aff86c169ffb8e8d81 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:21:51 +0300 Subject: [PATCH 23/53] apollo_dashboard: extract shared exchange-rate oracle alert builders (#14702) (#14762) (cherry picked from commit 3251ad1bb3b49fc6ca6ffebf8754b2817b31637f) Co-authored-by: Claude Opus 4.8 (1M context) --- .../apollo_dashboard/src/alert_definitions.rs | 18 +---- .../src/alert_scenarios/l1_gas_prices.rs | 71 +++++++++++++++---- 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index f04b2e1c7e8..f167b6bc24e 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -28,7 +28,6 @@ use apollo_l1_events::metrics::{ L1_MESSAGE_SCRAPER_REORG_DETECTED, }; use apollo_l1_gas_price::metrics::{ - ETH_TO_STRK_ERROR_COUNT, L1_GAS_PRICE_INFRA_METRICS, L1_GAS_PRICE_SCRAPER_BASELAYER_ERROR_COUNT, L1_GAS_PRICE_SCRAPER_REORG_DETECTED, @@ -71,6 +70,7 @@ use crate::alert_scenarios::infra_alerts::{ }; use crate::alert_scenarios::l1_endpoints::get_primary_l1_endpoint_down_too_long_alerts; use crate::alert_scenarios::l1_gas_prices::{ + get_eth_to_strk_error_count_alert, get_eth_to_strk_success_count_alert, get_l1_gas_price_provider_insufficient_history_alert, get_l1_gas_price_scraper_success_count_alert, @@ -310,22 +310,6 @@ fn get_consensus_retrospective_block_hash_mismatch() -> Alert { ) } -fn get_eth_to_strk_error_count_alert() -> Alert { - Alert::new( - "eth_to_strk_error_count", - "Eth to Strk error count", - EvaluationRate::Default, - format!( - "sum(increase({}[1h])) or vector(0)", - ETH_TO_STRK_ERROR_COUNT.get_name_with_filter() - ), - vec![AlertCondition::new(AlertComparisonOp::GreaterThan, 10.0, AlertLogicalOp::And)], - "1m", - AlertSeverity::Informational, - ObserverApplicability::NotApplicable, - ) -} - fn get_l1_gas_price_scraper_baselayer_error_count_alert() -> Alert { Alert::new( "l1_gas_price_scraper_baselayer_error_count", diff --git a/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs b/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs index 81f3d9a2ad4..176f0a3ef96 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs @@ -1,4 +1,5 @@ use apollo_l1_gas_price::metrics::{ + ETH_TO_STRK_ERROR_COUNT, ETH_TO_STRK_SUCCESS_COUNT, L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, @@ -11,29 +12,29 @@ use crate::alerts::{ AlertComparisonOp, AlertCondition, AlertLogicalOp, + AlertSeverity, EvaluationRate, ObserverApplicability, PENDING_DURATION_DEFAULT, }; use crate::query_builder::sum_increase; -/// Alert if we have no successful eth to strk rates data from the last hour. -/// -/// Uses `sum_increase` instead of bare `increase` to avoid false positives on spot eviction: when -/// a pod is evicted and rescheduled, the new pod's counter resets to 0, so a bare `increase([1h])` -/// would return 0 until the first success. `sum` aggregates across all pod series, and the -/// evicted pod's data points remain in the TSDB for the full 1h window, keeping the sum ≥ 1. pub(crate) fn get_eth_to_strk_success_count_alert() -> Alert { const ALERT_NAME: &str = "eth_to_strk_success_count"; - Alert::new( + oracle_success_count_alert( ALERT_NAME, "Eth to Strk success count", - EvaluationRate::Default, - sum_increase(Ð_TO_STRK_SUCCESS_COUNT, "1h"), - vec![AlertCondition::new(AlertComparisonOp::LessThan, 1.0, AlertLogicalOp::And)], - PENDING_DURATION_DEFAULT, + Ð_TO_STRK_SUCCESS_COUNT, SeverityValueOrPlaceholder::Placeholder(ALERT_NAME.to_string()), - ObserverApplicability::NotApplicable, + ) +} + +pub(crate) fn get_eth_to_strk_error_count_alert() -> Alert { + oracle_error_count_alert( + "eth_to_strk_error_count", + "Eth to Strk error count", + Ð_TO_STRK_ERROR_COUNT, + AlertSeverity::Informational, ) } @@ -70,3 +71,49 @@ pub(crate) fn get_l1_gas_price_provider_insufficient_history_alert() -> Alert { ObserverApplicability::NotApplicable, ) } + +/// Alert if an exchange-rate oracle had no successful query in the last hour. +/// +/// Uses `sum_increase` instead of bare `increase` to avoid false positives on spot eviction: when +/// a pod is evicted and rescheduled, the new pod's counter resets to 0, so a bare `increase([1h])` +/// would return 0 until the first success. `sum` aggregates across all pod series, and the +/// evicted pod's data points remain in the TSDB for the full 1h window, keeping the sum ≥ 1. +fn oracle_success_count_alert( + name: &str, + title: &str, + success_count_metric: &dyn MetricQueryName, + severity: impl Into, +) -> Alert { + Alert::new( + name, + title, + EvaluationRate::Default, + sum_increase(success_count_metric, "1h"), + vec![AlertCondition::new(AlertComparisonOp::LessThan, 1.0, AlertLogicalOp::And)], + PENDING_DURATION_DEFAULT, + severity, + ObserverApplicability::NotApplicable, + ) +} + +/// Alert if an exchange-rate oracle exceeded the failure threshold in the last hour. +/// +/// `or vector(0)` keeps the query defined (evaluating to 0) when the metric has no samples yet, +/// so the alert stays silent instead of going to no-data before the first error is recorded. +fn oracle_error_count_alert( + name: &str, + title: &str, + error_count_metric: &dyn MetricQueryName, + severity: impl Into, +) -> Alert { + Alert::new( + name, + title, + EvaluationRate::Default, + format!("{} or vector(0)", sum_increase(error_count_metric, "1h")), + vec![AlertCondition::new(AlertComparisonOp::GreaterThan, 10.0, AlertLogicalOp::And)], + "1m", + severity, + ObserverApplicability::NotApplicable, + ) +} From 77865aa24b218c32d41e9cd3acfc9c6644574d80 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:31:23 +0300 Subject: [PATCH 24/53] apollo_staking,apollo_consensus_manager: read mock epoch height from batcher first (#14698) (#14761) The mock staking contract derives the current epoch from the chain's latest block number. It read this solely from state sync, which is a downstream reader that can lag the commit tip significantly. Because committee resolution can only look ahead MIN_EPOCH_LENGTH (150) blocks past the epoch boundary implied by that height, a state-sync lag approaching ~150 blocks pushes the consensus height beyond the resolvable window: get_committee returns InvalidHeight, and consensus falls back to waiting for sync instead of producing blocks. Read the height from the batcher first (its storage marker tracks the commit tip), falling back to state sync on error, mirroring get_block_hash_with_fallback. The batcher get_height marker is the next-to-build height, so the latest committed block is one below it. Epoch math is unchanged; only the height source moves closer to the tip. This also aligns the mock with CairoStakingContract, which already reads epoch data via the batcher. (cherry picked from commit 6cfff03e4fba0225a238f645667603c61cd7d14c) Co-authored-by: Claude Opus 4.8 (1M context) --- .../src/consensus_manager.rs | 1 + .../src/mock_staking_contract.rs | 29 +++++- .../src/mock_staking_contract_test.rs | 98 +++++++++++++++++-- crates/apollo_staking/src/staking_manager.rs | 7 +- 4 files changed, 121 insertions(+), 14 deletions(-) diff --git a/crates/apollo_consensus_manager/src/consensus_manager.rs b/crates/apollo_consensus_manager/src/consensus_manager.rs index 362c48c4e44..b782c61ae71 100644 --- a/crates/apollo_consensus_manager/src/consensus_manager.rs +++ b/crates/apollo_consensus_manager/src/consensus_manager.rs @@ -382,6 +382,7 @@ pub fn create_committee_provider( let staking_manager_config = config.staking_manager_config.clone(); // TODO(Asmaa/Dafna): Create StakingContract according to config. let mock_staking_contract = Arc::new(MockStakingContract::new( + batcher_client.clone(), state_sync_client.clone(), staking_manager_config.dynamic_config.clone(), )); diff --git a/crates/apollo_staking/src/mock_staking_contract.rs b/crates/apollo_staking/src/mock_staking_contract.rs index 4a970c97735..c55d0c6a9fc 100644 --- a/crates/apollo_staking/src/mock_staking_contract.rs +++ b/crates/apollo_staking/src/mock_staking_contract.rs @@ -1,3 +1,4 @@ +use apollo_batcher_types::communication::SharedBatcherClient; use apollo_staking_config::config::{ get_config_for_epoch, ConfiguredStaker, @@ -6,6 +7,7 @@ use apollo_staking_config::config::{ use apollo_state_sync_types::communication::SharedStateSyncClient; use async_trait::async_trait; use starknet_api::block::BlockNumber; +use tracing::warn; use crate::committee_provider::Staker; use crate::staking_contract::{StakingContract, StakingContractResult}; @@ -27,6 +29,7 @@ impl From<&ConfiguredStaker> for Staker { /// Mock implementation of the staking contract backed by static in-memory configuration. pub struct MockStakingContract { + batcher_client: SharedBatcherClient, state_sync_client: SharedStateSyncClient, // Default configuration used when no other configuration is provided. default_config: StakingManagerDynamicConfig, @@ -37,10 +40,31 @@ impl MockStakingContract { pub const EPOCH_LENGTH: u64 = 30; pub fn new( + batcher_client: SharedBatcherClient, state_sync_client: SharedStateSyncClient, default_config: StakingManagerDynamicConfig, ) -> Self { - Self { state_sync_client, default_config } + Self { batcher_client, state_sync_client, default_config } + } + + // Returns the latest committed block number, preferring the batcher and falling back to state + // sync on batcher error. The batcher's height marker tracks the commit tip, whereas state sync + // is a downstream reader that can lag it significantly; deriving the epoch from a lagging + // source can push the consensus height beyond the resolvable committee window and stall block + // production. `get_height` returns the next-to-build marker, so the latest committed block is + // one below it. + async fn latest_committed_block(&self) -> StakingContractResult { + match self.batcher_client.get_height().await { + Ok(response) => Ok(BlockNumber(response.height.0.saturating_sub(1))), + Err(batcher_error) => { + warn!("Batcher get_height failed, falling back to state sync: {batcher_error}"); + Ok(self + .state_sync_client + .get_latest_block_number() + .await? + .unwrap_or(BlockNumber(0))) + } + } } } @@ -61,8 +85,7 @@ impl StakingContract for MockStakingContract { } async fn get_current_epoch(&self) -> StakingContractResult { - let latest_block_number = - self.state_sync_client.get_latest_block_number().await?.unwrap_or(BlockNumber(0)); + let latest_block_number = self.latest_committed_block().await?; let epoch_id = latest_block_number.0 / Self::EPOCH_LENGTH; let start_block = BlockNumber(epoch_id * Self::EPOCH_LENGTH); diff --git a/crates/apollo_staking/src/mock_staking_contract_test.rs b/crates/apollo_staking/src/mock_staking_contract_test.rs index 49c261fff78..fa36ab07df0 100644 --- a/crates/apollo_staking/src/mock_staking_contract_test.rs +++ b/crates/apollo_staking/src/mock_staking_contract_test.rs @@ -1,5 +1,12 @@ use std::sync::Arc; +use apollo_batcher_types::batcher_types::GetHeightResponse; +use apollo_batcher_types::communication::{ + BatcherClientError, + MockBatcherClient, + SharedBatcherClient, +}; +use apollo_batcher_types::errors::BatcherError; use apollo_staking_config::config::{ CommitteeConfig, ConfiguredStaker, @@ -78,6 +85,31 @@ fn mock_client_with_latest(block: Option) -> SharedStateSyncClient Arc::new(mock) } +// A no-op batcher client for tests that never query the current height. +fn no_batcher() -> SharedBatcherClient { + Arc::new(MockBatcherClient::new()) +} + +// A batcher whose next-to-build height marker is `marker`; the latest committed block is one below. +fn mock_batcher_with_marker(marker: BlockNumber) -> SharedBatcherClient { + let mut mock = MockBatcherClient::new(); + mock.expect_get_height().returning(move || Ok(GetHeightResponse { height: marker })); + Arc::new(mock) +} + +// A batcher reporting `committed` as its latest committed block (marker = committed + 1). +fn mock_batcher_with_committed(committed: BlockNumber) -> SharedBatcherClient { + mock_batcher_with_marker(BlockNumber(committed.0 + 1)) +} + +// A batcher whose height query always fails, forcing the state-sync fallback. +fn mock_batcher_erroring() -> SharedBatcherClient { + let mut mock = MockBatcherClient::new(); + mock.expect_get_height() + .returning(|| Err(BatcherClientError::BatcherError(BatcherError::InternalError))); + Arc::new(mock) +} + #[rstest] #[tokio::test] async fn get_stakers_with_config_picks_latest_config_for_epoch( @@ -93,7 +125,8 @@ async fn get_stakers_with_config_picks_latest_config_for_epoch( ..default_config }; - let contract = MockStakingContract::new(mock_state_sync_client, input_config.clone()); + let contract = + MockStakingContract::new(no_batcher(), mock_state_sync_client, input_config.clone()); // Epoch 1 < 3, so should use default (STAKER_1 only). let stakers = contract.get_stakers_with_config(1, &input_config).await.unwrap(); @@ -110,7 +143,7 @@ async fn get_stakers_uses_internal_default_config( mock_state_sync_client: SharedStateSyncClient, default_config: StakingManagerDynamicConfig, ) { - let contract = MockStakingContract::new(mock_state_sync_client, default_config); + let contract = MockStakingContract::new(no_batcher(), mock_state_sync_client, default_config); // get_stakers() should use the internal default_config. let stakers = contract.get_stakers(0).await.unwrap(); @@ -129,8 +162,11 @@ async fn get_current_epoch_success( #[case] expected_epoch: Epoch, default_config: StakingManagerDynamicConfig, ) { - let contract = - MockStakingContract::new(mock_client_with_latest(Some(block_number)), default_config); + let contract = MockStakingContract::new( + mock_batcher_with_committed(block_number), + Arc::new(MockStateSyncClient::new()), + default_config, + ); let epoch = contract.get_current_epoch().await.unwrap(); assert_eq!(epoch, expected_epoch); @@ -141,7 +177,11 @@ async fn get_current_epoch_success( async fn get_current_epoch_defaults_to_epoch_zero_when_no_blocks( default_config: StakingManagerDynamicConfig, ) { - let contract = MockStakingContract::new(mock_client_with_latest(None), default_config); + let contract = MockStakingContract::new( + mock_batcher_with_marker(BlockNumber(0)), + Arc::new(MockStateSyncClient::new()), + default_config, + ); let epoch = contract.get_current_epoch().await.unwrap(); assert_eq!(epoch, EPOCH_0); @@ -158,8 +198,11 @@ async fn get_previous_epoch_success( #[case] expected_previous_epoch: Option, default_config: StakingManagerDynamicConfig, ) { - let contract = - MockStakingContract::new(mock_client_with_latest(Some(block_number)), default_config); + let contract = MockStakingContract::new( + mock_batcher_with_committed(block_number), + Arc::new(MockStateSyncClient::new()), + default_config, + ); let previous_epoch = contract.get_previous_epoch().await.unwrap(); assert_eq!(previous_epoch, expected_previous_epoch); @@ -170,8 +213,47 @@ async fn get_previous_epoch_success( async fn get_previous_epoch_returns_none_when_no_blocks( default_config: StakingManagerDynamicConfig, ) { - let contract = MockStakingContract::new(mock_client_with_latest(None), default_config); + let contract = MockStakingContract::new( + mock_batcher_with_marker(BlockNumber(0)), + Arc::new(MockStateSyncClient::new()), + default_config, + ); let previous_epoch = contract.get_previous_epoch().await.unwrap(); assert_eq!(previous_epoch, None); } + +// The batcher's `get_height` returns the next-to-build marker, so the latest committed block is +// one below it. A marker at an epoch boundary must resolve to the previous epoch, not the next. +#[rstest] +#[tokio::test] +async fn get_current_epoch_uses_committed_tip_not_marker( + default_config: StakingManagerDynamicConfig, +) { + // Marker == EPOCH_LENGTH means the latest committed block is EPOCH_LENGTH - 1, still in epoch + // 0. + let contract = MockStakingContract::new( + mock_batcher_with_marker(BlockNumber(EPOCH_LENGTH)), + Arc::new(MockStateSyncClient::new()), + default_config, + ); + + let epoch = contract.get_current_epoch().await.unwrap(); + assert_eq!(epoch, EPOCH_0); +} + +// When the batcher height query fails, the epoch is derived from the state-sync latest block. +#[rstest] +#[tokio::test] +async fn get_current_epoch_falls_back_to_state_sync_on_batcher_error( + default_config: StakingManagerDynamicConfig, +) { + let contract = MockStakingContract::new( + mock_batcher_erroring(), + mock_client_with_latest(Some(E2_H1)), + default_config, + ); + + let epoch = contract.get_current_epoch().await.unwrap(); + assert_eq!(epoch, EPOCH_2); +} diff --git a/crates/apollo_staking/src/staking_manager.rs b/crates/apollo_staking/src/staking_manager.rs index 0961c1111b3..beee4dd91a9 100644 --- a/crates/apollo_staking/src/staking_manager.rs +++ b/crates/apollo_staking/src/staking_manager.rs @@ -47,9 +47,10 @@ mod staking_manager_test; // The minimum number of blocks in an epoch. This is used to anticipate if a // height falls within the next epoch, even when the exact epoch length is unknown. // -// CONSTRAINT: Must be ≥ `STORED_BLOCK_HASH_BUFFER` - the maximum StateSync lag. -// A smaller value could cause the consensus tip to advance beyond our knowledge of the next epoch, -// resulting in a failure to retrieve the committee. +// CONSTRAINT: Must be ≥ `STORED_BLOCK_HASH_BUFFER` - the maximum lag between the consensus tip and +// the height source used to resolve the current epoch (the batcher's committed height, falling +// back to StateSync). A smaller value could cause the consensus tip to advance beyond our +// knowledge of the next epoch, resulting in a failure to retrieve the committee. const MIN_EPOCH_LENGTH: u64 = 5 * 60 / 2; // Roughly 5 minutes in 2 seconds blocks. const_assert!(MIN_EPOCH_LENGTH >= STORED_BLOCK_HASH_BUFFER); From e55d4cab48954947386e0a53bc363155596e6caa Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:43:39 +0300 Subject: [PATCH 25/53] apollo_dashboard: add strk_to_usd oracle success and error alerts (#14703) (#14763) (cherry picked from commit 9e24339b07b46b2517ad057ca5c3d35e35bf3665) Co-authored-by: Claude Opus 4.8 (1M context) --- .../resources/dev_grafana_alerts.json | 52 +++++++++++++++++++ .../apollo_dashboard/src/alert_definitions.rs | 4 ++ .../src/alert_scenarios/l1_gas_prices.rs | 21 ++++++++ 3 files changed, 77 insertions(+) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts.json b/crates/apollo_dashboard/resources/dev_grafana_alerts.json index a7c5f635a6d..c42740f25ad 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts.json @@ -2146,6 +2146,58 @@ "for": "30s", "severity": "p2" }, + { + "name": "strk_to_usd_error_count", + "title": "Strk to Usd error count", + "ruleGroup": "evaluation_rate_default", + "expr": "(sum(increase(snip35_strk_usd_error_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1h])) or vector(0)) and on() (is_observer{cluster=~\"$cluster\", namespace=~\"$namespace\"} == 0)", + "conditions": [ + { + "evaluator": { + "params": [ + 10.0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "1m", + "severity": "p5" + }, + { + "name": "strk_to_usd_success_count", + "title": "Strk to Usd success count", + "ruleGroup": "evaluation_rate_default", + "expr": "(sum(increase(snip35_strk_usd_success_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1h]))) and on() (is_observer{cluster=~\"$cluster\", namespace=~\"$namespace\"} == 0)", + "conditions": [ + { + "evaluator": { + "params": [ + 1.0 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "30s", + "severity": "$$$strk_to_usd_success_count-severity$$$" + }, { "name": "sync_storage_open_read_transactions", "title": "sync - High number of open read transactions", diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index f167b6bc24e..55cd11781b7 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -74,6 +74,8 @@ use crate::alert_scenarios::l1_gas_prices::{ get_eth_to_strk_success_count_alert, get_l1_gas_price_provider_insufficient_history_alert, get_l1_gas_price_scraper_success_count_alert, + get_strk_to_usd_error_count_alert, + get_strk_to_usd_success_count_alert, }; use crate::alert_scenarios::l1_handlers::{ get_l1_handler_transaction_waiting_in_l1_alert, @@ -605,6 +607,7 @@ pub fn get_apollo_alerts() -> Alerts { get_consensus_round_above_zero(), get_consensus_votes_num_sent_messages_alert(), get_eth_to_strk_error_count_alert(), + get_strk_to_usd_error_count_alert(), get_gateway_add_tx_idle(), get_gateway_proof_archive_write_failure(), get_general_pod_state_not_ready(), @@ -636,6 +639,7 @@ pub fn get_apollo_alerts() -> Alerts { alerts.push(get_consensus_round_above_zero_multiple_times()); alerts.push(get_consensus_round_high()); alerts.push(get_eth_to_strk_success_count_alert()); + alerts.push(get_strk_to_usd_success_count_alert()); alerts.append(&mut get_general_pod_memory_utilization_vec()); alerts.append(&mut get_general_pod_disk_utilization_vec()); alerts.push(get_http_server_avg_add_tx_latency_alert()); diff --git a/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs b/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs index 176f0a3ef96..9304cce737a 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs @@ -3,6 +3,8 @@ use apollo_l1_gas_price::metrics::{ ETH_TO_STRK_SUCCESS_COUNT, L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, + SNIP35_STRK_USD_ERROR_COUNT, + SNIP35_STRK_USD_SUCCESS_COUNT, }; use apollo_metrics::metrics::MetricQueryName; @@ -38,6 +40,25 @@ pub(crate) fn get_eth_to_strk_error_count_alert() -> Alert { ) } +pub(crate) fn get_strk_to_usd_success_count_alert() -> Alert { + const ALERT_NAME: &str = "strk_to_usd_success_count"; + oracle_success_count_alert( + ALERT_NAME, + "Strk to Usd success count", + &SNIP35_STRK_USD_SUCCESS_COUNT, + SeverityValueOrPlaceholder::Placeholder(ALERT_NAME.to_string()), + ) +} + +pub(crate) fn get_strk_to_usd_error_count_alert() -> Alert { + oracle_error_count_alert( + "strk_to_usd_error_count", + "Strk to Usd error count", + &SNIP35_STRK_USD_ERROR_COUNT, + AlertSeverity::Informational, + ) +} + /// Alert if had no successful l1 gas price scrape in the last hour. /// /// Uses `sum_increase` for the same spot-eviction reason as `get_eth_to_strk_success_count_alert`. From 61985d2404a5c25db957f5d0df6939698eb7cc1a Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 10:49:53 +0300 Subject: [PATCH 26/53] apollo_consensus: store decided round in Decision to drop fragile precommits[0] index (#14605) (#14758) Both run_consensus and run_height derived the decided round from decision.precommits[0]/.first(), a latent panic if a Decision ever carried an empty precommit set (unreachable today, but a fragile invariant). Add an explicit `round` field to `Decision`, populated in upon_decision where the round is already in scope, and read it at both call sites. This removes the raw index and the sibling expect, making the empty-precommit case irrelevant to round derivation. (cherry picked from commit 68863a6c12edf5783d7bd96634bebe750924a735) Co-authored-by: asaf-sw Co-authored-by: Claude Opus 4.8 (1M context) --- crates/apollo_consensus/src/manager.rs | 11 ++---- crates/apollo_consensus/src/state_machine.rs | 2 +- .../src/state_machine_test.rs | 35 +++++++++++++++++++ crates/apollo_consensus/src/types.rs | 2 ++ 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/crates/apollo_consensus/src/manager.rs b/crates/apollo_consensus/src/manager.rs index 05d11f2db0b..baa58250c07 100644 --- a/crates/apollo_consensus/src/manager.rs +++ b/crates/apollo_consensus/src/manager.rs @@ -162,9 +162,7 @@ where .await? { RunHeightRes::Decision(decision) => { - // We expect there to be under 100 validators, so this is a reasonable number of - // precommits to print. - let round = decision.precommits[0].round; + let round = decision.round; // Proposer should never fail here, we already checked it in the state machine. let proposer = get_proposer_for_height( &run_consensus_args.committee_provider, @@ -176,6 +174,7 @@ where if proposer == run_consensus_args.consensus_config.dynamic_config.validator_id { CONSENSUS_DECISIONS_REACHED_AS_PROPOSER.increment(1); } + // Under 100 validators expected, so printing all precommits is reasonable. info!( "DECISION_REACHED: Decision reached for round {} with proposer {}. {:?}", round, proposer, decision @@ -508,11 +507,7 @@ impl MultiHeightManager { let res = match consensus_result { Ok(ok) => match ok { RunHeightRes::Decision(decision) => { - let decided_round = decision - .precommits - .first() - .expect("Decision must contain at least one precommit") - .round; + let decided_round = decision.round; let wait_for_last_commitment = self.consensus_config.dynamic_config.stop_at_height == Some(height); // Commit decision to context. diff --git a/crates/apollo_consensus/src/state_machine.rs b/crates/apollo_consensus/src/state_machine.rs index 90193af73c5..47764a82c37 100644 --- a/crates/apollo_consensus/src/state_machine.rs +++ b/crates/apollo_consensus/src/state_machine.rs @@ -712,7 +712,7 @@ impl StateMachine { .map(|(_vote_key, (v, _w))| v.clone()) .collect(); - let decision = Decision { precommits: supporting_precommits, block: *proposal_id }; + let decision = Decision { precommits: supporting_precommits, block: *proposal_id, round }; VecDeque::from([SMRequest::DecisionReached(decision)]) } diff --git a/crates/apollo_consensus/src/state_machine_test.rs b/crates/apollo_consensus/src/state_machine_test.rs index df6cca8dabf..070de754b27 100644 --- a/crates/apollo_consensus/src/state_machine_test.rs +++ b/crates/apollo_consensus/src/state_machine_test.rs @@ -70,6 +70,7 @@ fn assert_decision_reached(wrapper: &mut TestWrapper, expected_block: Option { assert_eq!(dec.block, expected_block.unwrap()); + assert_eq!(dec.round, ROUND, "Decision should carry the round it was reached at"); assert!(!dec.precommits.is_empty(), "Decision should have precommits"); } req => panic!("Expected DecisionReached, got {:?}", req), @@ -674,6 +675,40 @@ fn observer_node_reaches_decision() { assert_decision_reached(&mut wrapper, PROPOSAL_ID); } +#[test] +fn decision_carries_the_round_it_was_reached_at() { + let decided_round = ROUND + 1; + let mut wrapper = TestWrapper::new( + *VALIDATOR_ID, + UNIT_VALIDATOR_WEIGHTS.clone(), + |_: Round| *PROPOSER_ID, + |_: Round| Ok(*PROPOSER_ID), + QuorumType::Byzantine, + IS_OBSERVER, + ); + + advance_validator_after_start(&mut wrapper); + + // A precommit quorum at the next round skips the current round; once the proposal is validated + // there, the observer reaches a decision at that round. + for _ in 0..3 { + wrapper.send_precommit(PROPOSAL_ID, decided_round); + } + wrapper.send_finished_validation(PROPOSAL_ID, decided_round); + + let mut decision = None; + while let Some(request) = wrapper.next_request() { + if let SMRequest::DecisionReached(dec) = request { + decision = Some(dec); + break; + } + } + let decision = decision.expect("Expected a DecisionReached request"); + assert_eq!(decision.round, decided_round); + assert!(!decision.precommits.is_empty()); + assert!(decision.precommits.iter().all(|vote| vote.round == decided_round)); +} + #[test_case(QuorumType::Byzantine; "byzantine")] #[test_case(QuorumType::Honest; "honest")] fn number_of_required_votes(quorum_type: QuorumType) { diff --git a/crates/apollo_consensus/src/types.rs b/crates/apollo_consensus/src/types.rs index d115bfa449a..6f264a5b31d 100644 --- a/crates/apollo_consensus/src/types.rs +++ b/crates/apollo_consensus/src/types.rs @@ -118,6 +118,8 @@ pub trait ConsensusContext { pub struct Decision { pub precommits: Vec, pub block: ProposalCommitment, + /// The round at which this decision was reached. + pub round: Round, } pub struct BroadcastVoteChannel { From 2c241f0a7746999b946ddbe9f698ad077a3adb38 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 11:09:42 +0300 Subject: [PATCH 27/53] apollo_dashboard: alert on frozen exchange-rate oracle (eth_to_strk, strk_to_usd) (#14706) (#14764) (cherry picked from commit e871c40c4d26ca6c4867661b335644ec45e68f48) Co-authored-by: Claude Opus 4.8 (1M context) --- .../resources/dev_grafana_alerts.json | 52 +++++++++++++++++++ .../apollo_dashboard/src/alert_definitions.rs | 4 ++ .../src/alert_scenarios/l1_gas_prices.rs | 51 ++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts.json b/crates/apollo_dashboard/resources/dev_grafana_alerts.json index c42740f25ad..1408c07786a 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts.json @@ -898,6 +898,32 @@ "for": "1m", "severity": "p5" }, + { + "name": "eth_to_strk_rate_frozen", + "title": "Eth to Strk rate frozen", + "ruleGroup": "evaluation_rate_default", + "expr": "sum(changes(eth_to_strk_rate{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1h]))", + "conditions": [ + { + "evaluator": { + "params": [ + 1.0 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "30s", + "severity": "$$$eth_to_strk_rate_frozen-severity$$$" + }, { "name": "eth_to_strk_success_count", "title": "Eth to Strk success count", @@ -2172,6 +2198,32 @@ "for": "1m", "severity": "p5" }, + { + "name": "strk_to_usd_rate_frozen", + "title": "Strk to Usd rate frozen", + "ruleGroup": "evaluation_rate_default", + "expr": "sum(changes(snip35_strk_usd_rate{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1h]))", + "conditions": [ + { + "evaluator": { + "params": [ + 1.0 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "30s", + "severity": "$$$strk_to_usd_rate_frozen-severity$$$" + }, { "name": "strk_to_usd_success_count", "title": "Strk to Usd success count", diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index 55cd11781b7..0e0473c9e77 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -71,10 +71,12 @@ use crate::alert_scenarios::infra_alerts::{ use crate::alert_scenarios::l1_endpoints::get_primary_l1_endpoint_down_too_long_alerts; use crate::alert_scenarios::l1_gas_prices::{ get_eth_to_strk_error_count_alert, + get_eth_to_strk_rate_frozen_alert, get_eth_to_strk_success_count_alert, get_l1_gas_price_provider_insufficient_history_alert, get_l1_gas_price_scraper_success_count_alert, get_strk_to_usd_error_count_alert, + get_strk_to_usd_rate_frozen_alert, get_strk_to_usd_success_count_alert, }; use crate::alert_scenarios::l1_handlers::{ @@ -640,6 +642,8 @@ pub fn get_apollo_alerts() -> Alerts { alerts.push(get_consensus_round_high()); alerts.push(get_eth_to_strk_success_count_alert()); alerts.push(get_strk_to_usd_success_count_alert()); + alerts.push(get_eth_to_strk_rate_frozen_alert()); + alerts.push(get_strk_to_usd_rate_frozen_alert()); alerts.append(&mut get_general_pod_memory_utilization_vec()); alerts.append(&mut get_general_pod_disk_utilization_vec()); alerts.push(get_http_server_avg_add_tx_latency_alert()); diff --git a/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs b/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs index 9304cce737a..01cc7c19d43 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs @@ -1,9 +1,11 @@ use apollo_l1_gas_price::metrics::{ ETH_TO_STRK_ERROR_COUNT, + ETH_TO_STRK_RATE, ETH_TO_STRK_SUCCESS_COUNT, L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, SNIP35_STRK_USD_ERROR_COUNT, + SNIP35_STRK_USD_RATE, SNIP35_STRK_USD_SUCCESS_COUNT, }; use apollo_metrics::metrics::MetricQueryName; @@ -59,6 +61,26 @@ pub(crate) fn get_strk_to_usd_error_count_alert() -> Alert { ) } +pub(crate) fn get_eth_to_strk_rate_frozen_alert() -> Alert { + const ALERT_NAME: &str = "eth_to_strk_rate_frozen"; + oracle_rate_frozen_alert( + ALERT_NAME, + "Eth to Strk rate frozen", + Ð_TO_STRK_RATE, + SeverityValueOrPlaceholder::Placeholder(ALERT_NAME.to_string()), + ) +} + +pub(crate) fn get_strk_to_usd_rate_frozen_alert() -> Alert { + const ALERT_NAME: &str = "strk_to_usd_rate_frozen"; + oracle_rate_frozen_alert( + ALERT_NAME, + "Strk to Usd rate frozen", + &SNIP35_STRK_USD_RATE, + SeverityValueOrPlaceholder::Placeholder(ALERT_NAME.to_string()), + ) +} + /// Alert if had no successful l1 gas price scrape in the last hour. /// /// Uses `sum_increase` for the same spot-eviction reason as `get_eth_to_strk_success_count_alert`. @@ -138,3 +160,32 @@ fn oracle_error_count_alert( ObserverApplicability::NotApplicable, ) } + +/// Alert if an exchange-rate oracle's rate gauge has not changed at all in the last hour. +/// +/// Detects a *frozen feed*: the oracle keeps resolving successfully (so the success count and +/// last-success timestamp stay healthy) while serving a stale, unchanging price. `changes` over 1h +/// is 0 only when the value never moved across the ~4 update buckets in that window — effectively +/// impossible for a live 18-decimal rate. Unlike the error-count alert there is deliberately no +/// `or vector(0)`: an absent gauge must stay no-data (so an oracle that never resolves doesn't look +/// "frozen"); only a present-but-flat gauge trips this. +/// +/// Applies to observers too: a frozen upstream feed is env-wide and observer nodes run the same +/// oracle client, so the alert should fire regardless of node role. +fn oracle_rate_frozen_alert( + name: &str, + title: &str, + rate_metric: &dyn MetricQueryName, + severity: impl Into, +) -> Alert { + Alert::new( + name, + title, + EvaluationRate::Default, + format!("sum(changes({}[1h]))", rate_metric.get_name_with_filter()), + vec![AlertCondition::new(AlertComparisonOp::LessThan, 1.0, AlertLogicalOp::And)], + PENDING_DURATION_DEFAULT, + severity, + ObserverApplicability::Applicable, + ) +} From 48213fb5693e89f864ebfb81c181994329401420 Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Sun, 12 Jul 2026 12:50:21 +0300 Subject: [PATCH 28/53] starknet_transaction_prover: add prover input validation unit tests (#14047) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds unit tests for VirtualSnosProver input validation: pending block rejection, DeployAccount rejection, proof/proof_facts field rejection, non-zero fee field rejection (with the validation knob respected when disabled), and a happy-path test that asserts a valid invoke reaches the runner. Adds two test runners — UnreachableRunner (panics on invocation, for tests where validation must reject the input) and FailingRunner (returns an error, for tests that must verify the runner is reached without needing a real node). --- .../src/proving/virtual_snos_prover.rs | 37 ++- .../src/proving/virtual_snos_prover_test.rs | 255 +++++++++++++++++- 2 files changed, 274 insertions(+), 18 deletions(-) diff --git a/crates/starknet_transaction_prover/src/proving/virtual_snos_prover.rs b/crates/starknet_transaction_prover/src/proving/virtual_snos_prover.rs index cab35ca317b..6fa4f63978e 100644 --- a/crates/starknet_transaction_prover/src/proving/virtual_snos_prover.rs +++ b/crates/starknet_transaction_prover/src/proving/virtual_snos_prover.rs @@ -112,32 +112,43 @@ impl VirtualSnosProver { /// Creates a new VirtualSnosProver from a runner. /// /// This constructor allows using any runner implementation. - #[allow(dead_code)] + #[cfg(test)] pub(crate) fn from_runner(runner: R) -> Self { - #[cfg(feature = "stwo_proving")] - let precomputes = prepare_recursive_prover_precomputes() - .expect("Failed to prepare recursive prover precomputes"); - Self { - runner, - validate_zero_fee_fields: true, - blocking_check_client: None, - #[cfg(feature = "stwo_proving")] - precomputes, - } + Self::from_runner_with_options(runner, true, None) } /// Creates a new VirtualSnosProver from a runner with an optional blocking check client. - #[allow(dead_code)] + #[cfg(test)] pub(crate) fn from_runner_with_blocking_check( runner: R, blocking_check_client: Option, + ) -> Self { + Self::from_runner_with_options(runner, true, blocking_check_client) + } + + /// Creates a new VirtualSnosProver from a runner with fee-field validation disabled. + /// + /// Tests that drive the runner with non-zero resource bounds or tip use this so the request + /// reaches the runner instead of being rejected by the up-front fee-field check. + #[cfg(test)] + pub(crate) fn from_runner_without_fee_validation(runner: R) -> Self { + Self::from_runner_with_options(runner, false, None) + } + + /// Shared constructor backing the `from_runner*` helpers; `validate_zero_fee_fields` mirrors + /// the `ProverConfig` field of the same name. + #[cfg(test)] + fn from_runner_with_options( + runner: R, + validate_zero_fee_fields: bool, + blocking_check_client: Option, ) -> Self { #[cfg(feature = "stwo_proving")] let precomputes = prepare_recursive_prover_precomputes() .expect("Failed to prepare recursive prover precomputes"); Self { runner, - validate_zero_fee_fields: true, + validate_zero_fee_fields, blocking_check_client, #[cfg(feature = "stwo_proving")] precomputes, diff --git a/crates/starknet_transaction_prover/src/proving/virtual_snos_prover_test.rs b/crates/starknet_transaction_prover/src/proving/virtual_snos_prover_test.rs index 58f313e2c26..fcfaeafacab 100644 --- a/crates/starknet_transaction_prover/src/proving/virtual_snos_prover_test.rs +++ b/crates/starknet_transaction_prover/src/proving/virtual_snos_prover_test.rs @@ -1,7 +1,8 @@ -//! Integration tests for the VirtualSnosProver (full prove_transaction flow). +//! Tests for VirtualSnosProver: unit tests for input validation and integration tests for the +//! full prove_transaction flow. //! -//! These tests exercise the complete prover pipeline: transaction extraction, OS execution, -//! and proof generation. They run against Sepolia and support three modes +//! The integration tests exercise the complete prover pipeline: transaction extraction, OS +//! execution, and proof generation. They run against Sepolia and support three modes //! (see [`crate::running::rpc_records`] and [`crate::test_utils::resolve_test_mode`]): //! //! - **Live mode** (default): runs against a real node (requires `NODE_URL`). @@ -15,7 +16,7 @@ //! - `CHAIN_ID`: Override the chain ID (defaults to `Sepolia`). //! - `STRK_FEE_TOKEN_ADDRESS`: Override the STRK fee token contract address. //! -//! # Running +//! # Running integration tests //! //! ```bash //! # Live mode: @@ -28,14 +29,35 @@ //! cargo test -p starknet_transaction_prover virtual_snos_prover_test -- --ignored //! ``` +use std::sync::Arc; + +use assert_matches::assert_matches; +use async_trait::async_trait; use blockifier_reexecution::state_reader::rpc_objects::BlockId; use blockifier_test_utils::calldata::create_calldata; use rstest::rstest; +use starknet_api::block::GasPrice; use starknet_api::core::ContractAddress; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::execution_resources::GasAmount; +use starknet_api::rpc_transaction::{ + RpcDeclareTransaction, + RpcDeclareTransactionV3, + RpcDeployAccountTransaction, + RpcDeployAccountTransactionV3, + RpcInvokeTransaction, + RpcInvokeTransactionV3, + RpcTransaction, +}; +use starknet_api::transaction::fields::{Proof, ProofFacts, ResourceBounds, Tip}; +use starknet_api::transaction::InvokeTransaction; use starknet_api::{contract_address, felt}; use starknet_proof_verifier::verify_proof; +use starknet_types_core::felt::Felt; +use crate::errors::{RunnerError, VirtualSnosProverError}; use crate::proving::virtual_snos_prover::VirtualSnosProver; +use crate::running::runner::{RunnerOutput, VirtualSnosRunner}; use crate::test_utils::{ build_client_side_rpc_invoke, resolve_test_mode, @@ -44,6 +66,229 @@ use crate::test_utils::{ STRK_TOKEN_ADDRESS_SEPOLIA, }; +fn dummy_account() -> ContractAddress { + ContractAddress::try_from(DUMMY_ACCOUNT_ADDRESS).unwrap() +} + +fn valid_invoke_tx() -> RpcTransaction { + build_client_side_rpc_invoke(dummy_account(), Default::default()) +} + +fn invoke_v3_mut(tx: &mut RpcTransaction) -> &mut RpcInvokeTransactionV3 { + match tx { + RpcTransaction::Invoke(RpcInvokeTransaction::V3(inner)) => inner, + _ => panic!("Expected InvokeV3"), + } +} + +/// Reaching this runner means validation failed to reject — used where the test asserts rejection. +#[derive(Clone)] +struct UnreachableRunner; + +#[async_trait] +impl VirtualSnosRunner for UnreachableRunner { + async fn run_virtual_os( + &self, + _block_id: BlockId, + _txs: Vec, + ) -> Result { + panic!("validation should have rejected the transaction before reaching the runner"); + } +} + +/// Always errors — used where the test must observe that the runner *was* reached. +#[derive(Clone)] +struct FailingRunner; + +#[async_trait] +impl VirtualSnosRunner for FailingRunner { + async fn run_virtual_os( + &self, + _block_id: BlockId, + _txs: Vec, + ) -> Result { + Err(RunnerError::InputGenerationError("mock error".to_string())) + } +} + +#[tokio::test] +async fn test_pending_block_rejected() { + let prover = VirtualSnosProver::from_runner_without_fee_validation(UnreachableRunner); + let result = prover.prove_transaction(BlockId::Pending, valid_invoke_tx()).await; + assert_matches!( + result, + Err(VirtualSnosProverError::ValidationError(msg)) if msg.contains("Pending") + ); +} + +#[rstest] +#[case::deploy_account( + RpcTransaction::DeployAccount(RpcDeployAccountTransaction::V3(RpcDeployAccountTransactionV3 { + signature: Default::default(), + nonce: Default::default(), + class_hash: Default::default(), + contract_address_salt: Default::default(), + constructor_calldata: Default::default(), + resource_bounds: Default::default(), + tip: Default::default(), + paymaster_data: Default::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + })), + "DeployAccount" +)] +#[case::declare( + RpcTransaction::Declare(RpcDeclareTransaction::V3(RpcDeclareTransactionV3 { + sender_address: Default::default(), + compiled_class_hash: Default::default(), + signature: Default::default(), + nonce: Default::default(), + contract_class: Default::default(), + resource_bounds: Default::default(), + tip: Default::default(), + paymaster_data: Default::default(), + account_deployment_data: Default::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + })), + "Declare" +)] +#[tokio::test] +async fn test_non_invoke_transaction_type_rejected( + #[case] tx: RpcTransaction, + #[case] expected_message_substring: &str, +) { + let prover = VirtualSnosProver::from_runner_without_fee_validation(UnreachableRunner); + let result = prover.prove_transaction(BlockId::Latest, tx).await; + assert_matches!( + result, + Err(VirtualSnosProverError::InvalidTransactionType(msg)) + if msg.contains(expected_message_substring) + ); +} + +#[rstest] +#[case::non_empty_proof({ + let mut tx = valid_invoke_tx(); + invoke_v3_mut(&mut tx).proof = Proof(Arc::new(vec![0u8])); + tx +})] +#[case::non_empty_proof_facts({ + let mut tx = valid_invoke_tx(); + invoke_v3_mut(&mut tx).proof_facts = ProofFacts(Arc::new(vec![Felt::ZERO])); + tx +})] +#[tokio::test] +async fn test_non_empty_proof_fields_rejected(#[case] tx: RpcTransaction) { + let prover = VirtualSnosProver::from_runner_without_fee_validation(UnreachableRunner); + let result = prover.prove_transaction(BlockId::Latest, tx).await; + assert_matches!(result, Err(VirtualSnosProverError::InvalidTransactionInput(_))); +} + +#[rstest] +#[case::non_zero_l1_gas_price( + { + let mut tx = valid_invoke_tx(); + invoke_v3_mut(&mut tx).resource_bounds.l1_gas.max_price_per_unit = GasPrice(1); + tx + }, + "l1_gas.max_price_per_unit" +)] +#[case::non_zero_l2_gas_price( + { + let mut tx = valid_invoke_tx(); + invoke_v3_mut(&mut tx).resource_bounds.l2_gas.max_price_per_unit = GasPrice(1); + tx + }, + "l2_gas.max_price_per_unit" +)] +#[case::non_zero_l1_data_gas_price( + { + let mut tx = valid_invoke_tx(); + invoke_v3_mut(&mut tx).resource_bounds.l1_data_gas.max_price_per_unit = GasPrice(1); + tx + }, + "l1_data_gas.max_price_per_unit" +)] +#[case::non_zero_tip( + { + let mut tx = valid_invoke_tx(); + invoke_v3_mut(&mut tx).tip = Tip(1); + tx + }, + "tip =" +)] +#[case::zero_l2_gas_max_amount( + { + let mut tx = valid_invoke_tx(); + invoke_v3_mut(&mut tx).resource_bounds.l2_gas.max_amount = GasAmount(0); + tx + }, + "l2_gas.max_amount" +)] +#[tokio::test] +async fn test_fee_fields_rejected_when_validation_enabled( + #[case] tx: RpcTransaction, + #[case] expected_message_substring: &str, +) { + let prover = VirtualSnosProver::from_runner(UnreachableRunner); + let result = prover.prove_transaction(BlockId::Latest, tx).await; + assert_matches!( + result, + Err(VirtualSnosProverError::InvalidTransactionInput(msg)) + if msg.contains(expected_message_substring) + ); +} + +#[tokio::test] +async fn test_non_zero_resource_bounds_accepted_when_validation_disabled() { + let mut tx = valid_invoke_tx(); + invoke_v3_mut(&mut tx).resource_bounds.l1_gas = + ResourceBounds { max_amount: GasAmount(1), max_price_per_unit: GasPrice(1) }; + + let prover = VirtualSnosProver::from_runner_without_fee_validation(FailingRunner); + let result = prover.prove_transaction(BlockId::Latest, tx).await; + assert_matches!(result, Err(VirtualSnosProverError::RunnerError(_))); +} + +/// A default-valid invoke (empty proof fields, zero fees, Latest block) must pass every validation +/// gate and be handed to the runner. Asserting on `RunnerError::InputGenerationError("mock error")` +/// proves the runner was reached; any rejection earlier would surface as a different variant. +#[tokio::test] +async fn test_valid_invoke_reaches_runner() { + let prover = VirtualSnosProver::from_runner(FailingRunner); + let result = prover.prove_transaction(BlockId::Latest, valid_invoke_tx()).await; + assert_matches!( + result, + Err(VirtualSnosProverError::RunnerError(inner)) if matches!( + *inner, + RunnerError::InputGenerationError(ref msg) if msg == "mock error" + ) + ); +} + +/// `l1_gas.max_amount` and `l1_data_gas.max_amount` do not affect OS execution and may be +/// non-zero even with fee-field validation enabled; only `max_price_per_unit` fields and `tip` +/// are required to be zero. Asserting on `RunnerError::InputGenerationError("mock error")` proves +/// the runner was reached. +#[tokio::test] +async fn test_non_fee_max_amount_fields_accepted_when_validation_enabled() { + let mut tx = valid_invoke_tx(); + let bounds = &mut invoke_v3_mut(&mut tx).resource_bounds; + bounds.l1_gas.max_amount = GasAmount(1); + bounds.l1_data_gas.max_amount = GasAmount(1); + + let prover = VirtualSnosProver::from_runner(FailingRunner); + let result = prover.prove_transaction(BlockId::Latest, tx).await; + assert_matches!( + result, + Err(VirtualSnosProverError::RunnerError(inner)) if matches!( + *inner, + RunnerError::InputGenerationError(ref msg) if msg == "mock error" + ) + ); +} + /// Integration test for the full prover pipeline with a STRK `transfer` transaction. /// Runs on a Sepolia environment; in live/recording mode requires a Sepolia RPC node via /// `NODE_URL`. @@ -54,7 +299,7 @@ async fn test_prove_transfer_transaction() { let test_mode = resolve_test_mode("test_prove_transfer_transaction").await; let strk_token = ContractAddress::try_from(STRK_TOKEN_ADDRESS_SEPOLIA).unwrap(); - let account = ContractAddress::try_from(DUMMY_ACCOUNT_ADDRESS).unwrap(); + let account = dummy_account(); let recipient = contract_address!("0x123"); // Transfer amount: 1 wei (u256 = low + high * 2^128). From d4b0fe1a2f46e9c95a6848bc994e6442491482cd Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 13:12:23 +0300 Subject: [PATCH 29/53] starknet_api: do not panic on malformed resource_bounds in tx json deserializer (#14412) (#14744) (cherry picked from commit 3428d34e396fcccd335de6a4c76d0cafb0579118) Co-authored-by: Avi Cohen Co-authored-by: Claude Opus 4.8 (1M context) --- crates/starknet_api/src/serde_utils.rs | 27 +++++++++------------ crates/starknet_api/src/serde_utils_test.rs | 23 ++++++++++++++++++ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/crates/starknet_api/src/serde_utils.rs b/crates/starknet_api/src/serde_utils.rs index af8b6ac74aa..771936f3b86 100644 --- a/crates/starknet_api/src/serde_utils.rs +++ b/crates/starknet_api/src/serde_utils.rs @@ -160,23 +160,18 @@ where /// In old transactions, the resource bounds names are lowercase. /// Need to convert to uppercase for deserialization to work. fn upper_case_resource_bounds_names(raw_transaction: &mut Value) { - let resource_bounds = raw_transaction - .get_mut("resource_bounds") - .expect("tx should contain resource_bounds field") - .as_object_mut() - .expect("resource_bounds should be an object"); - - if let Some(l1_gas_value) = resource_bounds.remove("l1_gas") { - resource_bounds.insert("L1_GAS".to_string(), l1_gas_value); - - let l2_gas_value = resource_bounds - .remove("l2_gas") - .expect("If tx contains l1_gas, it should contain l2_gas"); - resource_bounds.insert("L2_GAS".to_string(), l2_gas_value); - } + let Some(resource_bounds) = + raw_transaction.get_mut("resource_bounds").and_then(Value::as_object_mut) + else { + return; + }; - if let Some(l1_data_gas_value) = resource_bounds.remove("l1_data_gas") { - resource_bounds.insert("L1_DATA_GAS".to_string(), l1_data_gas_value); + for (lower_case_name, upper_case_name) in + [("l1_gas", "L1_GAS"), ("l2_gas", "L2_GAS"), ("l1_data_gas", "L1_DATA_GAS")] + { + if let Some(resource_bounds_value) = resource_bounds.remove(lower_case_name) { + resource_bounds.insert(upper_case_name.to_string(), resource_bounds_value); + } } } diff --git a/crates/starknet_api/src/serde_utils_test.rs b/crates/starknet_api/src/serde_utils_test.rs index 2a94ae6379d..fc4123c6dac 100644 --- a/crates/starknet_api/src/serde_utils_test.rs +++ b/crates/starknet_api/src/serde_utils_test.rs @@ -10,6 +10,7 @@ use crate::deprecated_contract_class::{ use crate::serde_utils::{ bytes_from_hex_str, deserialize_optional_contract_class_abi_entry_vector, + deserialize_transaction_json_to_starknet_api_tx, hex_str_from_bytes, BytesAsHex, InnerDeserializationError, @@ -186,3 +187,25 @@ fn deserialize_optional_contract_class_abi_entry_vector_none() { let res: DummyContractClass = serde_json::from_str(json).unwrap(); assert_eq!(res, DummyContractClass { abi: None }); } + +/// V3 transaction JSON may arrive from untrusted sources; a missing or malformed +/// `resource_bounds` field must surface as a deserialization error, not a panic. +#[test] +fn deserialize_transaction_json_does_not_panic_on_malformed_resource_bounds() { + // Missing resource_bounds field. + let raw_transaction = serde_json::json!({"type": "INVOKE", "version": "0x3"}); + assert!(deserialize_transaction_json_to_starknet_api_tx(raw_transaction).is_err()); + + // resource_bounds is not an object. + let raw_transaction = + serde_json::json!({"type": "INVOKE", "version": "0x3", "resource_bounds": 5}); + assert!(deserialize_transaction_json_to_starknet_api_tx(raw_transaction).is_err()); + + // l1_gas without l2_gas. + let raw_transaction = serde_json::json!({ + "type": "DECLARE", + "version": "0x3", + "resource_bounds": {"l1_gas": {"max_amount": "0x0", "max_price_per_unit": "0x0"}} + }); + assert!(deserialize_transaction_json_to_starknet_api_tx(raw_transaction).is_err()); +} From 59438eb87b28e2ea8cd86c4173d04b0619f06346 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 14:34:47 +0300 Subject: [PATCH 30/53] apollo_consensus_orchestrator,apollo_dashboard: alert when L2 gas price hits configured minimum (#14773) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fire a P3 (all envs) alert when the accepted L2 gas price is clamped at the configured minimum (min_l2_gas_price_per_height, or the versioned-constants min_gas_price fallback) for a sustained 2m window. Emit a new consensus_l2_gas_price_at_minimum gauge where consensus_l2_gas_price is already set, and have the alert read that signal rather than a literal Grafana threshold — a literal would be wrong on Mainnet (configured min = 15e9, not the 8e9 fallback) and would rot when the versioned-constants min changes. Co-authored-by: Claude Opus 4.8 (1M context) --- .../src/metrics.rs | 2 ++ .../src/sequencer_consensus_context.rs | 8 ++++++ .../src/sequencer_consensus_context_test.rs | 5 +++- .../resources/dev_grafana_alerts.json | 26 +++++++++++++++++++ .../apollo_dashboard/src/alert_definitions.rs | 2 ++ .../src/alert_scenarios/l1_gas_prices.rs | 22 ++++++++++++++++ 6 files changed, 64 insertions(+), 1 deletion(-) diff --git a/crates/apollo_consensus_orchestrator/src/metrics.rs b/crates/apollo_consensus_orchestrator/src/metrics.rs index fbae60d2ed7..0eddeb3ff51 100644 --- a/crates/apollo_consensus_orchestrator/src/metrics.rs +++ b/crates/apollo_consensus_orchestrator/src/metrics.rs @@ -15,6 +15,7 @@ define_metrics!( MetricCounter { CONSENSUS_L1_GAS_MISMATCH, "consensus_l1_gas_mismatch", "The number of times the L1 gas in a proposal does not match the value expected by this validator", init = 0 }, MetricCounter { CONSENSUS_L1_DATA_GAS_MISMATCH, "consensus_l1_data_gas_mismatch", "The number of times the L1 data gas in a proposal does not match the value expected by this validator", init = 0 }, MetricGauge { CONSENSUS_L2_GAS_PRICE, "consensus_l2_gas_price", "The L2 gas price calculated in an accepted proposal" }, + MetricGauge { CONSENSUS_L2_GAS_PRICE_AT_MINIMUM, "consensus_l2_gas_price_at_minimum", "1 when the accepted L2 gas price is clamped at the configured minimum (min_l2_gas_price_per_height, or the versioned-constants min_gas_price fallback), else 0" }, MetricCounter { CONSENSUS_L1_GAS_PRICE_PROVIDER_ERROR, "consensus_l1_gas_price_provider_error", "Number of times the context got an error when querying the L1 gas price provider", init=0}, MetricCounter { CONSENSUS_RETROSPECTIVE_BLOCK_HASH_MISMATCH, "consensus_retrospective_block_hash_mismatch", "Number of times the retrospective block hashes of the state sync and the batcher mismatched", init=0}, @@ -97,6 +98,7 @@ pub(crate) fn register_metrics() { CONSENSUS_L1_GAS_MISMATCH.register(); CONSENSUS_L1_DATA_GAS_MISMATCH.register(); CONSENSUS_L2_GAS_PRICE.register(); + CONSENSUS_L2_GAS_PRICE_AT_MINIMUM.register(); CONSENSUS_L1_GAS_PRICE_PROVIDER_ERROR.register(); CONSENSUS_RETROSPECTIVE_BLOCK_HASH_MISMATCH.register(); CENDE_LAST_PREPARED_BLOB_BLOCK_NUMBER.register(); diff --git a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs index c983d1e899e..ec044d9f510 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -101,6 +101,7 @@ use crate::metrics::{ record_validate_proposal_failure, register_metrics, CONSENSUS_L2_GAS_PRICE, + CONSENSUS_L2_GAS_PRICE_AT_MINIMUM, SNIP35_FEE_ACTUAL_FRI, SNIP35_FEE_PROPOSAL_FRI, SNIP35_FEE_TARGET_ATTO_USD, @@ -495,6 +496,11 @@ impl SequencerConsensusContext { self.l2_gas_price = self.calculate_next_l2_gas_price(height, l2_gas_used); let gas_price_u64 = u64::try_from(self.l2_gas_price.0).unwrap_or(u64::MAX); CONSENSUS_L2_GAS_PRICE.set_lossy(gas_price_u64); + let config_min = get_min_gas_price_for_height( + height, + &self.config.dynamic_config.min_l2_gas_price_per_height, + ); + CONSENSUS_L2_GAS_PRICE_AT_MINIMUM.set_lossy(u64::from(self.l2_gas_price <= config_min)); } #[allow(clippy::too_many_arguments)] @@ -1056,6 +1062,8 @@ impl ConsensusContext for SequencerConsensusContext { self.l2_gas_price = max(self.l2_gas_price, min_gas_price_for_height); let gas_price_u64 = u64::try_from(self.l2_gas_price.0).unwrap_or(u64::MAX); CONSENSUS_L2_GAS_PRICE.set_lossy(gas_price_u64); + CONSENSUS_L2_GAS_PRICE_AT_MINIMUM + .set_lossy(u64::from(self.l2_gas_price <= min_gas_price_for_height)); } self.current_height = Some(height); self.current_round = round; diff --git a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs index 2ccfffebb4c..2750de57dd1 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs @@ -64,7 +64,7 @@ use starknet_api::versioned_constants_logic::VersionedConstantsTrait; use crate::cende::{MockCendeContext, N_BLOCK_HASHES_BACK_IN_BLOB}; use crate::dynamic_gas_price::proposal_commitment_from; -use crate::metrics::CONSENSUS_L2_GAS_PRICE; +use crate::metrics::{CONSENSUS_L2_GAS_PRICE, CONSENSUS_L2_GAS_PRICE_AT_MINIMUM}; use crate::sequencer_consensus_context::{ SequencerConsensusContext, SequencerConsensusContextDeps, @@ -790,6 +790,9 @@ async fn decision_reached_sends_correct_values() { let metrics = recorder.handle().render(); CONSENSUS_L2_GAS_PRICE .assert_eq(&metrics, VersionedConstants::latest_constants().min_gas_price.0); + // The price landed at the configured minimum (empty `min_l2_gas_price_per_height` → the + // versioned-constants fallback), so the "at minimum" gauge must report 1. + CONSENSUS_L2_GAS_PRICE_AT_MINIMUM.assert_eq(&metrics, 1); } // The blob's `parent_proposal_commitment` must bind the parent block's `fee_proposal_fri`, which diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts.json b/crates/apollo_dashboard/resources/dev_grafana_alerts.json index 1408c07786a..78f29b3d85b 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts.json @@ -612,6 +612,32 @@ "for": "30s", "severity": "p5" }, + { + "name": "consensus_l2_gas_price_at_minimum", + "title": "L2 gas price at configured minimum", + "ruleGroup": "evaluation_rate_default", + "expr": "(max(consensus_l2_gas_price_at_minimum{cluster=~\"$cluster\", namespace=~\"$namespace\"})) and on() (is_observer{cluster=~\"$cluster\", namespace=~\"$namespace\"} == 0)", + "conditions": [ + { + "evaluator": { + "params": [ + 0.0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "2m", + "severity": "p3" + }, { "name": "consensus_p2p_disconnections", "title": "Consensus p2p disconnections", diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index 0e0473c9e77..a9e8fa14ace 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -75,6 +75,7 @@ use crate::alert_scenarios::l1_gas_prices::{ get_eth_to_strk_success_count_alert, get_l1_gas_price_provider_insufficient_history_alert, get_l1_gas_price_scraper_success_count_alert, + get_l2_gas_price_at_minimum_alert, get_strk_to_usd_error_count_alert, get_strk_to_usd_rate_frozen_alert, get_strk_to_usd_success_count_alert, @@ -654,6 +655,7 @@ pub fn get_apollo_alerts() -> Alerts { alerts.push(get_high_empty_blocks_ratio_alert()); alerts.push(get_l1_gas_price_provider_insufficient_history_alert()); alerts.push(get_l1_gas_price_scraper_success_count_alert()); + alerts.push(get_l2_gas_price_at_minimum_alert()); alerts.push(get_l1_message_scraper_no_successes_alert()); alerts.push(get_l1_handler_transaction_waiting_in_l1_alert()); alerts.extend(get_primary_l1_endpoint_down_too_long_alerts()); diff --git a/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs b/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs index 01cc7c19d43..94cf72de57b 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/l1_gas_prices.rs @@ -1,3 +1,4 @@ +use apollo_consensus_orchestrator::metrics::CONSENSUS_L2_GAS_PRICE_AT_MINIMUM; use apollo_l1_gas_price::metrics::{ ETH_TO_STRK_ERROR_COUNT, ETH_TO_STRK_RATE, @@ -115,6 +116,27 @@ pub(crate) fn get_l1_gas_price_provider_insufficient_history_alert() -> Alert { ) } +/// Alert when the accepted L2 gas price sits at the configured minimum for a sustained window, +/// i.e. the EIP-1559 fee market has clamped the price at its floor (demand bottomed out). +/// +/// Fires on the `consensus_l2_gas_price_at_minimum` gauge (1 = clamped at the configured min), +/// which the orchestrator derives per height from `min_l2_gas_price_per_height` (falling back to +/// the versioned-constants `min_gas_price`). Emitting the "at minimum" signal from the node — where +/// the configured min is known — avoids a hard-coded Grafana threshold that would rot on a +/// versioned-constants change or miss any env that overrides the min (e.g. Mainnet's 15e9). +pub(crate) fn get_l2_gas_price_at_minimum_alert() -> Alert { + Alert::new( + "consensus_l2_gas_price_at_minimum", + "L2 gas price at configured minimum", + EvaluationRate::Default, + format!("max({})", CONSENSUS_L2_GAS_PRICE_AT_MINIMUM.get_name_with_filter()), + vec![AlertCondition::new(AlertComparisonOp::GreaterThan, 0.0, AlertLogicalOp::And)], + "2m", + AlertSeverity::DayOnly, + ObserverApplicability::NotApplicable, + ) +} + /// Alert if an exchange-rate oracle had no successful query in the last hour. /// /// Uses `sum_increase` instead of bare `increase` to avoid false positives on spot eviction: when From 6c1fece4bcb2aa548bf7f4991fcb3652302c0f33 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 14:36:53 +0300 Subject: [PATCH 31/53] apollo_mempool: drop emptied gap accounts on tx expiry to fix accounts_with_gap leak (#14766) remove_expired_txs decremented n_stuck_txs for expired stuck txs but only fed the queued txs into update_accounts_with_gap. Stuck txs are never queued (fee mode enqueues only nonce == account_nonce), so a gap account whose stuck txs all expire was never removed from accounts_with_gap, leaving mempool_accounts_with_gap > 0 while mempool_stuck_txs == 0 (observed on mainnet). Add a cleanup loop, after the decrement loop, that removes any account expiry left with no pool txs (mirrors try_make_space). Runs separately so per-tx stuck decrements aren't skipped by early set removal. Co-authored-by: Claude Opus 4.8 (1M context) --- crates/apollo_mempool/src/fee_mempool_test.rs | 60 +++++++++++++++++++ crates/apollo_mempool/src/mempool.rs | 11 ++++ 2 files changed, 71 insertions(+) diff --git a/crates/apollo_mempool/src/fee_mempool_test.rs b/crates/apollo_mempool/src/fee_mempool_test.rs index 300e4be5229..dc35a16fda8 100644 --- a/crates/apollo_mempool/src/fee_mempool_test.rs +++ b/crates/apollo_mempool/src/fee_mempool_test.rs @@ -2037,6 +2037,66 @@ fn stuck_txs_counter_expiry_decrements_count() { assert_gap_metrics(&mempool, 1, 1); } +#[test] +fn stuck_txs_counter_expiry_removes_emptied_gap_account() { + let fake_clock = Arc::new(FakeClock::default()); + let mut mempool = Mempool::new( + MempoolConfig { + dynamic_config: MempoolDynamicConfig { transaction_ttl: Duration::from_secs(60) }, + ..Default::default() + }, + fake_clock.clone(), + ); + + // Gap account with a single stuck tx (nonce 2, gap at 0 and 1). + let tx_nonce_2 = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 2, account_nonce: 0); + add_tx(&mut mempool, &tx_nonce_2); + assert_gap_metrics(&mempool, 1, 1); + + // Expire the account's only stuck tx, then trigger the expiry sweep via a tx for another + // address. + fake_clock.advance(Duration::from_secs(61)); + let trigger = add_tx_input!(tx_hash: 2, address: "0x1", tx_nonce: 0, account_nonce: 0); + add_tx(&mut mempool, &trigger); + + // The stuck tx is non-queued, so it never re-enters update_accounts_with_gap; the emptied gap + // account must still leave accounts_with_gap so both counters return to zero. + assert_gap_metrics(&mempool, 0, 0); +} + +#[test] +fn stuck_txs_counter_expiry_removes_gap_account_with_multiple_stuck_txs() { + let fake_clock = Arc::new(FakeClock::default()); + let mut mempool = Mempool::new( + MempoolConfig { + dynamic_config: MempoolDynamicConfig { transaction_ttl: Duration::from_secs(60) }, + ..Default::default() + }, + fake_clock.clone(), + ); + + // Gap account with two stuck txs (nonces 2 and 3, gap at 0 and 1), submitted at the same time + // so they expire together in a single sweep. + let tx_nonce_2 = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 2, account_nonce: 0); + let tx_nonce_3 = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 3, account_nonce: 0); + for tx in [&tx_nonce_2, &tx_nonce_3] { + add_tx(&mut mempool, tx); + } + assert_gap_metrics(&mempool, 1, 2); + + // Expire both stuck txs, then trigger the sweep via a tx for another address. + fake_clock.advance(Duration::from_secs(61)); + let trigger = add_tx_input!(tx_hash: 3, address: "0x1", tx_nonce: 0, account_nonce: 0); + add_tx(&mut mempool, &trigger); + + // All of the account's stuck txs expired in one sweep, so both counters must reach zero. This + // guards the two-phase structure of remove_expired_txs: the account must stay in + // accounts_with_gap until every stuck tx is decremented (decrement_stuck_txs_if_gap_account + // only acts while the account is tracked), and only then be removed. Merging decrement and + // removal into one loop would no-op the second tx's decrement and leave stuck_txs == 1. + assert_gap_metrics(&mempool, 0, 0); +} + #[test] fn stuck_txs_counter_eviction_decrements_count() { let tx_gap = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 2, account_nonce: 0); diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index b1ae9321a6b..c9a40cb9bf5 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -840,6 +840,17 @@ impl Mempool { self.decrement_stuck_txs_if_gap_account(tx_ref.address, 1); } + // Drop gap accounts that expiry left with no pool txs. Their stuck txs are non-queued, so + // the queued-tx map returned below never re-evaluates them; without this they + // linger in `accounts_with_gap` (accounts_with_gap > 0 while stuck_txs == 0). Runs + // after the decrement loop above: removing an account from the set early would make + // its per-tx stuck decrements no-op. + for tx_ref in &removed_txs { + if !self.tx_pool.contains_account(tx_ref.address) { + self.remove_from_accounts_with_gap(tx_ref.address); + } + } + let queued_txs = self.tx_queue.remove_txs(&removed_txs); self.log_and_count_expired_txs(&removed_txs); From f0f5fcf17e51c0f60829b030725086104576318f Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 15:14:04 +0300 Subject: [PATCH 32/53] apollo_mempool: make fee-escalation replacement atomic to avoid dropping existing tx (#14517) (#14753) (cherry picked from commit 26ff2a263608416e14a35c72c713a68b1fa56289) Co-authored-by: dan-starkware <56217775+dan-starkware@users.noreply.github.com> --- crates/apollo_mempool/src/fee_mempool_test.rs | 145 +++++++++++++++++- crates/apollo_mempool/src/mempool.rs | 83 ++++++---- 2 files changed, 198 insertions(+), 30 deletions(-) diff --git a/crates/apollo_mempool/src/fee_mempool_test.rs b/crates/apollo_mempool/src/fee_mempool_test.rs index dc35a16fda8..5cb9bb67217 100644 --- a/crates/apollo_mempool/src/fee_mempool_test.rs +++ b/crates/apollo_mempool/src/fee_mempool_test.rs @@ -24,7 +24,13 @@ use starknet_api::block::GasPrice; use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_api::test_utils::invoke::internal_invoke_tx; use starknet_api::test_utils::valid_resource_bounds_for_testing; -use starknet_api::transaction::fields::TransactionSignature; +use starknet_api::transaction::fields::{ + AllResourceBounds, + ResourceBounds, + Tip, + TransactionSignature, + ValidResourceBounds, +}; use starknet_api::transaction::TransactionHash; use starknet_api::{contract_address, declare_tx_args, felt, invoke_tx_args, nonce, tx_hash}; @@ -1906,6 +1912,143 @@ fn rejects_or_accepts_tx_based_on_freed_space( assert!(!mempool.tx_pool.contains_account(contract_address!("0x1"))); } +// Atomic fee-escalation replacement tests (a rejected replacement must never drop the existing +// transaction). The replacement's byte size is controlled via the signature length so it can be +// made larger than the transaction it replaces. + +fn invoke_tx_with_signature_size( + tx_hash_value: u8, + address: &str, + tx_nonce_value: u8, + tip_value: u64, + max_l2_gas_price_value: u128, + signature_size: usize, +) -> InternalRpcTransaction { + let resource_bounds = ValidResourceBounds::AllResources(AllResourceBounds { + l2_gas: ResourceBounds { + max_price_per_unit: GasPrice(max_l2_gas_price_value), + ..Default::default() + }, + ..Default::default() + }); + internal_invoke_tx(invoke_tx_args!( + tx_hash: tx_hash!(tx_hash_value), + sender_address: contract_address!(address), + nonce: nonce!(tx_nonce_value), + tip: Tip(tip_value), + resource_bounds, + signature: TransactionSignature(vec![felt!("0x0"); signature_size].into()), + )) +} + +fn full_mempool_with_fee_escalation(capacity_in_bytes: u64) -> Mempool { + Mempool::new( + MempoolConfig { + static_config: MempoolStaticConfig { + capacity_in_bytes, + enable_fee_escalation: true, + fee_escalation_percentage: 10, + ..Default::default() + }, + ..Default::default() + }, + Arc::new(FakeClock::default()), + ) +} + +fn add_tx_input_for( + tx: InternalRpcTransaction, + address: &str, + account_nonce: u8, +) -> AddTransactionArgs { + AddTransactionArgs { + tx, + account_state: AccountState { + address: contract_address!(address), + nonce: nonce!(account_nonce), + }, + } +} + +#[rstest] +fn fee_escalation_rejected_replacement_does_not_drop_existing_tx() { + // Existing tx A occupies the account's next nonce (0). No other account exists, so there is + // nothing to evict and a larger replacement cannot be admitted. + let existing_tx = invoke_tx_with_signature_size(1, "0x0", 0, 90, 90, 0); + let mut mempool = full_mempool_with_fee_escalation(existing_tx.total_bytes()); + add_tx(&mut mempool, &add_tx_input_for(existing_tx.clone(), "0x0", 0)); + + // Higher-fee but larger replacement at the same nonce: rejected, and A must remain. + let larger_replacement = + add_tx_input_for(invoke_tx_with_signature_size(2, "0x0", 0, 100, 100, 32), "0x0", 0); + add_tx_expect_error(&mut mempool, &larger_replacement, MempoolError::MempoolFull); + + assert!( + mempool.tx_pool.get_by_tx_hash(existing_tx.tx_hash()).is_ok(), + "rejected replacement must not drop the existing transaction" + ); + assert!(mempool.tx_pool.get_by_tx_hash(larger_replacement.tx.tx_hash()).is_err()); +} + +#[rstest] +fn fee_escalation_rejected_replacement_of_gapped_tx_keeps_existing_tx() { + // Existing tx A sits at a future nonce (5) while the account nonce is 0, so A is gapped. A + // gapped account is never granted eviction, so a larger replacement is rejected. + let existing_tx = invoke_tx_with_signature_size(1, "0x0", 5, 90, 90, 0); + let mut mempool = full_mempool_with_fee_escalation(existing_tx.total_bytes()); + add_tx(&mut mempool, &add_tx_input_for(existing_tx.clone(), "0x0", 0)); + + let larger_replacement = + add_tx_input_for(invoke_tx_with_signature_size(2, "0x0", 5, 100, 100, 32), "0x0", 0); + add_tx_expect_error(&mut mempool, &larger_replacement, MempoolError::MempoolFull); + + assert!( + mempool.tx_pool.get_by_tx_hash(existing_tx.tx_hash()).is_ok(), + "rejected replacement of a gapped tx must not drop it" + ); +} + +#[rstest] +fn fee_escalation_same_size_replacement_succeeds_on_full_pool() { + // The common case: a same-size, higher-fee bump at the next nonce. Crediting A's freed bytes + // nets to zero, so it must replace A on a full pool without any eviction. + let existing_tx = invoke_tx_with_signature_size(1, "0x0", 0, 90, 90, 4); + let mut mempool = full_mempool_with_fee_escalation(existing_tx.total_bytes()); + add_tx(&mut mempool, &add_tx_input_for(existing_tx.clone(), "0x0", 0)); + + let replacement = + add_tx_input_for(invoke_tx_with_signature_size(2, "0x0", 0, 100, 100, 4), "0x0", 0); + add_tx(&mut mempool, &replacement); + + assert!(mempool.tx_pool.get_by_tx_hash(replacement.tx.tx_hash()).is_ok(), "B must replace A"); + assert!(mempool.tx_pool.get_by_tx_hash(existing_tx.tx_hash()).is_err(), "A must be removed"); +} + +#[rstest] +fn fee_escalation_larger_replacement_evicts_to_make_room() { + // A larger replacement at the account's next nonce gets the same eviction support as a fresh + // next-nonce tx: a third-party gap account is evicted to fit the delta, and A is replaced + // (never dropped). Locks in that eviction never targets A. + let existing_tx = invoke_tx_with_signature_size(1, "0x0", 0, 90, 90, 0); + let evictable_tx = invoke_tx_with_signature_size(2, "0x1", 5, 0, 100, 0); + let capacity = existing_tx.total_bytes() + evictable_tx.total_bytes(); + let mut mempool = full_mempool_with_fee_escalation(capacity); + add_tx(&mut mempool, &add_tx_input_for(existing_tx.clone(), "0x0", 0)); + add_tx(&mut mempool, &add_tx_input_for(evictable_tx.clone(), "0x1", 0)); + + // Delta (4 signature felts) is far smaller than the evictable tx, so eviction frees enough. + let larger_replacement = + add_tx_input_for(invoke_tx_with_signature_size(3, "0x0", 0, 100, 100, 4), "0x0", 0); + add_tx(&mut mempool, &larger_replacement); + + assert!(mempool.tx_pool.get_by_tx_hash(larger_replacement.tx.tx_hash()).is_ok()); + assert!(mempool.tx_pool.get_by_tx_hash(existing_tx.tx_hash()).is_err(), "A must be replaced"); + assert!( + mempool.tx_pool.get_by_tx_hash(evictable_tx.tx_hash()).is_err(), + "third-party gap account must be evicted, never A" + ); +} + // Stuck-tx counter tests. fn assert_gap_metrics(mempool: &Mempool, expected_accounts: usize, expected_stuck_txs: usize) { diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index c9a40cb9bf5..eedf9bba10f 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -402,7 +402,7 @@ impl Mempool { pub fn validate_tx(&mut self, args: ValidationArgs) -> MempoolResult<()> { let tx_reference = (&args).into(); self.validate_incoming_tx(tx_reference, args.account_nonce)?; - self.handle_fee_escalation(tx_reference, true)?; + self.validate_fee_escalation(tx_reference)?; Ok(()) } @@ -415,10 +415,29 @@ impl Mempool { account_nonce: Nonce, ) -> MempoolResult<()> { self.validate_incoming_tx(tx_reference, account_nonce)?; - self.handle_fee_escalation(tx_reference, false)?; + let replaced_tx_reference = self.validate_fee_escalation(tx_reference)?; + + // The replaced transaction is still pooled, so its bytes still count toward + // `size_in_bytes()`. Credit what its removal will free: a same-size bump nets to zero (no + // overflow handling), and a larger replacement only needs room for the delta, consistent + // with how a fresh next-nonce transaction is treated. The removal happens only after + // capacity is confirmed below, so a rejected incoming transaction never strands the + // account. + let freed_bytes = replaced_tx_reference.map_or(0, |reference| { + self.tx_pool + .get_by_tx_hash(reference.tx_hash) + .expect("Replacement target from pool must exist.") + .total_bytes() + }); + + if self.exceeds_capacity(tx, freed_bytes) { + self.handle_capacity_overflow(tx, account_nonce, freed_bytes)?; + } - if self.exceeds_capacity(tx) { - self.handle_capacity_overflow(tx, account_nonce)?; + // Capacity is confirmed: this is the final, infallible mutation before the incoming + // transaction is inserted by the caller. + if let Some(existing_tx_reference) = replaced_tx_reference { + self.remove_replaced_tx(existing_tx_reference); } Ok(()) @@ -591,7 +610,7 @@ impl Mempool { // Fee mode: only add transactions with matching account nonce. // Remove queued transactions the account might have. This includes old nonce // transactions that have become obsolete; those with an equal nonce should - // already have been removed in `handle_fee_escalation`. + // already have been removed via fee escalation (`remove_replaced_tx`). self.tx_queue.remove_by_address(address); self.insert_to_tx_queue(tx_reference); } @@ -734,18 +753,14 @@ impl Mempool { Ok(()) } - /// This method checks if an incoming transaction with the same (address, nonce) already exists - /// in the pool and determines whether the incoming transaction should replace it based on fee - /// escalation rules. - /// If `validation_only` is `true`, only validates whether replacement would be allowed without - /// actually removing the existing transaction. If `false`, removes the existing transaction - /// when replacement is valid. - /// Note: This method will **not** add the new incoming transaction. - fn handle_fee_escalation( - &mut self, + /// Validates whether the incoming transaction may replace an existing one at the same + /// `(address, nonce)` via fee escalation, without mutating any state. Returns the existing + /// transaction to be replaced when a valid replacement exists, `None` when there is nothing to + /// replace, or an error when a replacement is present but not permitted. + fn validate_fee_escalation( + &self, incoming_tx_reference: TransactionReference, - validation_only: bool, - ) -> MempoolResult<()> { + ) -> MempoolResult> { let TransactionReference { address, nonce, .. } = incoming_tx_reference; self.validate_no_delayed_declare_front_run(incoming_tx_reference)?; @@ -755,13 +770,13 @@ impl Mempool { return Err(MempoolError::DuplicateNonce { address, nonce }); }; - return Ok(()); + return Ok(None); } let Some(existing_tx_reference) = self.tx_pool.get_by_address_and_nonce(address, nonce) else { // Replacement irrelevant: no existing transaction with the same nonce for address. - return Ok(()); + return Ok(None); }; if !self.should_replace_tx(&existing_tx_reference, &incoming_tx_reference) { @@ -773,19 +788,20 @@ impl Mempool { return Err(MempoolError::DuplicateNonce { address, nonce }); } - if validation_only { - return Ok(()); - } + Ok(Some(existing_tx_reference)) + } - debug!("{existing_tx_reference} will be replaced by {incoming_tx_reference}."); + /// Removes the existing transaction that is being replaced via fee escalation. Must be called + /// only after the incoming replacement is guaranteed to be admitted, so the account is never + /// left without a transaction at this nonce. + fn remove_replaced_tx(&mut self, existing_tx_reference: TransactionReference) { + debug!("{existing_tx_reference} is being replaced via fee escalation."); self.tx_queue.remove_txs(&[existing_tx_reference]); self.tx_pool .remove(existing_tx_reference.tx_hash) .expect("Transaction hash from pool must exist."); - self.decrement_stuck_txs_if_gap_account(address, 1); - - Ok(()) + self.decrement_stuck_txs_if_gap_account(existing_tx_reference.address, 1); } fn should_replace_tx( @@ -929,9 +945,14 @@ impl Mempool { } } - // Returns true if the mempool will exceeds its capacity by adding the given transaction. - fn exceeds_capacity(&self, tx: &InternalRpcTransaction) -> bool { - self.size_in_bytes() + tx.total_bytes() > self.config.static_config.capacity_in_bytes + // Returns true if adding the given transaction would exceed the mempool capacity, after + // crediting `freed_bytes` that an accompanying removal (e.g. a fee-escalation replacement) + // will free. `freed_bytes` is 0 when there is no such removal. + fn exceeds_capacity(&self, tx: &InternalRpcTransaction, freed_bytes: u64) -> bool { + // The to-be-removed transaction is still counted in `size_in_bytes()` here, so subtract + // what its removal frees. `saturating_sub` guards the (impossible) underflow defensively. + (self.size_in_bytes() + tx.total_bytes()).saturating_sub(freed_bytes) + > self.config.static_config.capacity_in_bytes } fn update_accounts_with_gap(&mut self, address_to_nonce: AddressToNonce) { @@ -1014,6 +1035,7 @@ impl Mempool { &mut self, tx: &InternalRpcTransaction, account_nonce: Nonce, + freed_bytes: u64, ) -> Result<(), MempoolError> { let address = tx.contract_address(); @@ -1022,7 +1044,10 @@ impl Mempool { let closing_gap = tx.nonce() == account_nonce; let creating_gap = (account_has_gap || !account_has_txs) && !closing_gap; - if !creating_gap && self.try_make_space(tx.total_bytes()) { + // Only the net growth must be evicted: an accompanying replacement removal frees + // `freed_bytes` (0 when there is no replacement). + let required_space = tx.total_bytes().saturating_sub(freed_bytes); + if !creating_gap && self.try_make_space(required_space) { return Ok(()); } From ba53156859b5ac403e5aecd2e368fae76b7020d8 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 15:15:17 +0300 Subject: [PATCH 33/53] apollo_l1_gas_price_config: reject number_of_blocks_for_mean=0 to avoid divide-by-zero panic (#14553) (#14745) (cherry picked from commit b1cfa5ab86bd08969822ca48be823ba937fd5616) Co-authored-by: dan-starkware <56217775+dan-starkware@users.noreply.github.com> --- crates/apollo_l1_gas_price_config/src/config.rs | 7 +++++++ .../src/config_test.rs | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 crates/apollo_l1_gas_price_config/src/config_test.rs diff --git a/crates/apollo_l1_gas_price_config/src/config.rs b/crates/apollo_l1_gas_price_config/src/config.rs index 97fef531192..47669938f5a 100644 --- a/crates/apollo_l1_gas_price_config/src/config.rs +++ b/crates/apollo_l1_gas_price_config/src/config.rs @@ -21,6 +21,10 @@ use starknet_api::core::ChainId; use url::Url; use validator::Validate; +#[cfg(test)] +#[path = "config_test.rs"] +mod config_test; + #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Validate)] pub struct ExchangeRateOracleConfig { #[serde(deserialize_with = "deserialize_optional_sensitive_list_with_url_and_headers")] @@ -93,6 +97,9 @@ impl Default for ExchangeRateOracleConfig { #[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] pub struct L1GasPriceProviderConfig { // TODO(guyn): these two fields need to go into VersionedConstants. + // Must be >= 1: the provider divides the summed prices by this window when computing the mean, + // so a value of 0 would cause a divide-by-zero panic during block production. + #[validate(range(min = 1))] pub number_of_blocks_for_mean: u64, // Use seconds not Duration since seconds is the basic quanta of time for both Starknet and // Ethereum. diff --git a/crates/apollo_l1_gas_price_config/src/config_test.rs b/crates/apollo_l1_gas_price_config/src/config_test.rs new file mode 100644 index 00000000000..b0d667c967d --- /dev/null +++ b/crates/apollo_l1_gas_price_config/src/config_test.rs @@ -0,0 +1,16 @@ +use validator::Validate; + +use super::L1GasPriceProviderConfig; + +// A zero mean window would make the provider divide by zero when computing the mean gas price, +// so it must be rejected at config load instead of panicking later during block production. +#[test] +fn rejects_zero_number_of_blocks_for_mean() { + let config = L1GasPriceProviderConfig { number_of_blocks_for_mean: 0, ..Default::default() }; + assert!(config.validate().is_err()); +} + +#[test] +fn accepts_default_number_of_blocks_for_mean() { + assert!(L1GasPriceProviderConfig::default().validate().is_ok()); +} From 42c7f9d88470088a74e514d65916930cc7f64623 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 15:50:07 +0300 Subject: [PATCH 34/53] apollo_mempool: use saturating_sub for n_stuck_txs accounting (#14560) (#14754) Replace the two unchecked `n_stuck_txs -=` subtractions in decrement_stuck_txs_if_gap_account and remove_from_accounts_with_gap with saturating_sub. Guards against a latent underflow that would panic under overflow-checked builds and silently wrap the MEMPOOL_STUCK_TXS gauge in release. (cherry picked from commit 50ef162b8659b7cb1c319b22bf9a54090857c11c) Co-authored-by: Claude Opus 4.8 (1M context) --- crates/apollo_mempool/src/mempool.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index eedf9bba10f..5cff36b1cf2 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -933,7 +933,7 @@ impl Mempool { fn decrement_stuck_txs_if_gap_account(&mut self, address: ContractAddress, n: usize) { if self.accounts_with_gap.contains(&address) { - self.n_stuck_txs -= n; + self.n_stuck_txs = self.n_stuck_txs.saturating_sub(n); } } @@ -941,7 +941,8 @@ impl Mempool { // n_stuck_txs. No-op if the address was not tracked. fn remove_from_accounts_with_gap(&mut self, address: ContractAddress) { if self.accounts_with_gap.swap_remove(&address) { - self.n_stuck_txs -= self.tx_pool.n_txs_for_address(address); + self.n_stuck_txs = + self.n_stuck_txs.saturating_sub(self.tx_pool.n_txs_for_address(address)); } } From 4cc3b997cf0e643f2cde0797e80d5802a1c765b2 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 12 Jul 2026 16:38:54 +0300 Subject: [PATCH 35/53] blockifier: record blocks-full-by-resource metric once per block, not per rejected tx (#14776) The bouncer is created once per block but shared across every per-chunk WorkerExecutor, while each chunk gets a fresh scheduler. Once the block is full, the first candidate of every subsequent chunk / executor invocation re-hits BlockFull in `try_update` and re-recorded blockifier_blocks_full_by_resource, turning a per-block metric into a per-rejected-tx count (~7.6x inflation observed on mainnet: 5,872 increments vs 769 full-block closures per 24h). Gate the recording on a per-block `block_full_recorded` flag so the counter is incremented at most once per block, matching its documented semantics. Add a regression test asserting the metric is recorded once across multiple rejected txs. Co-authored-by: Claude Opus 4.8 (1M context) --- Cargo.lock | 2 + crates/blockifier/Cargo.toml | 3 + crates/blockifier/src/bouncer.rs | 10 ++- crates/blockifier/src/bouncer_test.rs | 89 ++++++++++++++++++++++++++- 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1d73e549a8..498b9b55c7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3951,6 +3951,8 @@ dependencies = [ "itertools 0.12.1", "keccak 0.1.5", "log", + "metrics", + "metrics-exporter-prometheus", "mockall", "num-bigint", "num-integer", diff --git a/crates/blockifier/Cargo.toml b/crates/blockifier/Cargo.toml index 9de2a1409c7..77a7cea5d57 100644 --- a/crates/blockifier/Cargo.toml +++ b/crates/blockifier/Cargo.toml @@ -89,6 +89,7 @@ thiserror.workspace = true validator.workspace = true [dev-dependencies] +apollo_metrics = { workspace = true, features = ["testing"] } assert_matches.workspace = true blockifier_test_utils.workspace = true criterion = { workspace = true, features = ["html_reports"] } @@ -96,6 +97,8 @@ expect-test.workspace = true glob.workspace = true hex.workspace = true itertools.workspace = true +metrics.workspace = true +metrics-exporter-prometheus.workspace = true pretty_assertions.workspace = true rand.workspace = true regex.workspace = true diff --git a/crates/blockifier/src/bouncer.rs b/crates/blockifier/src/bouncer.rs index be1feed7865..22bdc6f9331 100644 --- a/crates/blockifier/src/bouncer.rs +++ b/crates/blockifier/src/bouncer.rs @@ -572,6 +572,7 @@ pub struct Bouncer { pub state_changes_keys: StateChangesKeys, pub bouncer_config: BouncerConfig, accumulated_weights: TxWeights, + block_full_recorded: bool, } impl Bouncer { @@ -585,6 +586,7 @@ impl Bouncer { state_changes_keys: StateChangesKeys::default(), bouncer_config: BouncerConfig::empty(), accumulated_weights: TxWeights::empty(), + block_full_recorded: false, } } @@ -677,7 +679,13 @@ impl Bouncer { self.get_bouncer_weights(), exceeded_weights ); - record_exceeded_bouncer_resources(&exceeded_weights); + // Record the block-full metric only once per block. Later candidate txs that also do + // not fit (subsequent chunks / executor invocations share this bouncer) would otherwise + // inflate the counter into a per-rejected-tx count instead of a per-block count. + if !self.block_full_recorded { + record_exceeded_bouncer_resources(&exceeded_weights); + self.block_full_recorded = true; + } Err(TransactionExecutorError::BlockFull)? } diff --git a/crates/blockifier/src/bouncer_test.rs b/crates/blockifier/src/bouncer_test.rs index ac26af28f6b..cda63b8d118 100644 --- a/crates/blockifier/src/bouncer_test.rs +++ b/crates/blockifier/src/bouncer_test.rs @@ -7,6 +7,7 @@ use blockifier_test_utils::contracts::FeatureContract; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use expect_test::expect; +use metrics_exporter_prometheus::PrometheusBuilder; use rstest::{fixture, rstest}; use starknet_api::contract_class::compiled_class_hash::HashVersion; use starknet_api::core::{ClassHash, CompiledClassHash}; @@ -37,6 +38,7 @@ use crate::execution::call_info::{ OpcodeCounterMap, }; use crate::fee::resources::{ComputationResources, TransactionResources}; +use crate::metrics::{BLOCKS_FULL_BY_RESOURCE, LABEL_NAME_BLOCK_FULL_RESOURCE}; use crate::state::cached_state::{CachedState, StateChangesKeys, StateMaps, TransactionalState}; use crate::state::state_api::StateReader; use crate::test_utils::contracts::FeatureContractData; @@ -229,7 +231,8 @@ fn test_block_weights_has_room_n_txs( class_hashes_to_migrate: HashMap::from([ (class_hash!(0_u128), (CompiledClassHash(felt!(2_u128)), CompiledClassHash(felt!(1_u128)))), ]), -} +}, + block_full_recorded: false, })] fn test_bouncer_update(#[case] initial_bouncer: Bouncer) { // TODO(Aviv): Use expect! to avoid magic numbers. @@ -395,6 +398,90 @@ fn test_bouncer_try_update_gas_based(#[case] scenario: &'static str, block_conte } } +#[rstest] +fn test_block_full_metric_recorded_once_per_block(block_context: BlockContext) { + // A single bouncer is shared across all chunks of a block, so `try_update` is invoked for many + // candidate txs after the block is already full. Regression test: the + // `blockifier_blocks_full_by_resource` counter must be incremented once per block, not once per + // rejected tx. + let recorder = PrometheusBuilder::new().build_recorder(); + let _recorder_guard = metrics::set_default_local_recorder(&recorder); + + let state = &mut test_state(&block_context.chain_info, Fee(0), &[]); + let mut transactional_state = TransactionalState::create_transactional(state); + + // Block already near its (small) sierra_gas cap; proving_gas keeps its large default cap so the + // overflowing tx exceeds sierra_gas only. + let block_max_capacity = BouncerWeights { + l1_gas: 20, + message_segment_length: 20, + n_events: 20, + state_diff_size: 20, + n_txs: 20, + sierra_gas: GasAmount(20), + proving_gas: BouncerWeights::default().proving_gas, + receipt_l2_gas: GasAmount(20), + }; + let bouncer_config = BouncerConfig { + block_max_capacity, + builtin_instance_limits: BuiltinInstanceLimits::default(), + }; + let accumulated_weights = TxWeights { + bouncer_weights: BouncerWeights { + l1_gas: 10, + message_segment_length: 10, + n_events: 10, + state_diff_size: 10, + sierra_gas: GasAmount(10), + n_txs: 10, + proving_gas: GasAmount(10), + receipt_l2_gas: GasAmount(0), + }, + ..Default::default() + }; + let mut bouncer = Bouncer { accumulated_weights, bouncer_config, ..Bouncer::empty() }; + + let execution_summary = ExecutionSummary::default(); + // Accumulated sierra_gas 10 + tx sierra_gas (11 + builtins) exceeds the cap of 20. + let tx_resources = TransactionResources { + computation: ComputationResources { sierra_gas: GasAmount(11), ..Default::default() }, + ..Default::default() + }; + let tx_state_changes_keys = transactional_state.to_state_diff().unwrap().state_maps.keys(); + + // Simulate five post-full candidate txs hitting the same (shared) bouncer. + for _ in 0..5 { + let result = bouncer.try_update( + &transactional_state, + &tx_state_changes_keys, + &execution_summary, + &cairo_primitive_counter_map([(BuiltinName::range_check, 1)]), + &tx_resources, + &block_context.versioned_constants, + GasAmount::ZERO, + ); + assert_matches!(result, Err(TransactionExecutorError::BlockFull)); + } + + // Despite five rejected txs, sierra_gas is counted exactly once, and proving_gas — never the + // binding dimension — is not counted at all. + let metrics_string = recorder.handle().render(); + assert_eq!( + BLOCKS_FULL_BY_RESOURCE.parse_numeric_metric::( + &metrics_string, + &[(LABEL_NAME_BLOCK_FULL_RESOURCE, "sierra_gas")] + ), + Some(1) + ); + assert_eq!( + BLOCKS_FULL_BY_RESOURCE.parse_numeric_metric::( + &metrics_string, + &[(LABEL_NAME_BLOCK_FULL_RESOURCE, "proving_gas")] + ), + None + ); +} + #[rstest] fn test_transaction_too_large_sierra_gas_based(block_context: BlockContext) { let mut state = test_state(&block_context.chain_info, Fee(0), &[]); From 8d3a740caca6e13ff7665e822d9edd70eaea9d69 Mon Sep 17 00:00:00 2001 From: gkaempfer <39151790+gkaempfer@users.noreply.github.com> Date: Sun, 12 Jul 2026 17:14:25 +0300 Subject: [PATCH 36/53] starknet_transaction_prover: avoid redundant request-id re-parse in RequestSpanLayer (#14743) RequestSpanLayer re-parsed and re-validated the x-request-id header on every plaintext request via extract_or_generate_request_id, even though RequestLogLayer (upstream in the same chain) already computed and validated that exact id moments earlier. RequestLogLayer now stashes the validated id in a RequestId request extension; RequestSpanLayer reads it directly, falling back to re-deriving it only when used standalone (e.g. without RequestLogLayer upstream, as in some unit tests). Follow-up to #14222. Co-authored-by: Claude --- .../src/server/request_log.rs | 8 ++++ .../src/server/request_span.rs | 16 +++++--- .../src/server/request_span_test.rs | 40 ++++++++++++++++++- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/crates/starknet_transaction_prover/src/server/request_log.rs b/crates/starknet_transaction_prover/src/server/request_log.rs index 079dc32cdbb..a9899df1cc6 100644 --- a/crates/starknet_transaction_prover/src/server/request_log.rs +++ b/crates/starknet_transaction_prover/src/server/request_log.rs @@ -41,6 +41,13 @@ mod request_log_test; /// HTTP header carrying the request id. pub const REQUEST_ID_HEADER: &str = "x-request-id"; +/// Request extension carrying the id this layer already validated/generated, +/// so a downstream layer (e.g. `RequestSpanLayer`) can reuse it on the +/// plaintext path instead of re-parsing and re-validating the header it just +/// set. +#[derive(Clone)] +pub(crate) struct RequestId(pub String); + /// tower [`Layer`] producing [`RequestLogService`]. #[derive(Clone, Copy, Default)] pub struct RequestLogLayer; @@ -78,6 +85,7 @@ where let request_id = extract_or_generate_request_id(&request); let id_header_value = request_id_header_value(&request_id); request.headers_mut().insert(REQUEST_ID_HEADER, id_header_value.clone()); + request.extensions_mut().insert(RequestId(request_id.clone())); let is_health_probe = request.method() == Method::GET && request.uri().path() == HEALTH_PATH; let method = request.method().clone(); diff --git a/crates/starknet_transaction_prover/src/server/request_span.rs b/crates/starknet_transaction_prover/src/server/request_span.rs index 413a1d205bf..aa75a6fa5db 100644 --- a/crates/starknet_transaction_prover/src/server/request_span.rs +++ b/crates/starknet_transaction_prover/src/server/request_span.rs @@ -24,6 +24,7 @@ use crate::server::request_log::{ extract_or_generate_request_id, new_request_id, request_id_header_value, + RequestId, REQUEST_ID_HEADER, }; @@ -69,11 +70,16 @@ where request.headers_mut().insert(REQUEST_ID_HEADER, request_id_header_value(&fresh_id)); fresh_id } else { - // Re-derives, via the shared validator, the exact id - // `RequestLogLayer` already assigned — the header is left - // untouched. This also keeps the layer correct standalone, - // e.g. in unit tests without `RequestLogLayer` upstream. - extract_or_generate_request_id(&request) + // Reuses the id `RequestLogLayer` already validated/generated via + // its request extension, avoiding a second header parse and + // validation pass per request. Falls back to re-deriving it (the + // header is left untouched either way) so the layer stays correct + // standalone, e.g. in unit tests without `RequestLogLayer` + // upstream. + request.extensions().get::().map_or_else( + || extract_or_generate_request_id(&request), + |request_id| request_id.0.clone(), + ) }; self.inner.call(request).instrument(info_span!("http_request", request_id = %request_id)) } diff --git a/crates/starknet_transaction_prover/src/server/request_span_test.rs b/crates/starknet_transaction_prover/src/server/request_span_test.rs index f800cde5d5c..d242edbbd35 100644 --- a/crates/starknet_transaction_prover/src/server/request_span_test.rs +++ b/crates/starknet_transaction_prover/src/server/request_span_test.rs @@ -1,12 +1,13 @@ use bytes::Bytes; -use http::{Method, Request}; +use http::{Method, Request, Response, StatusCode}; use http_body_util::Full; use jsonrpsee::server::HttpBody; use tower::{Layer, ServiceExt}; use tower_ohttp::Decapsulated; +use tracing_test::traced_test; use crate::server::middleware_test_utils::{echo_request_id_service, read_body_and_headers}; -use crate::server::request_log::{RequestLogLayer, REQUEST_ID_HEADER}; +use crate::server::request_log::{RequestId, RequestLogLayer, REQUEST_ID_HEADER}; use crate::server::request_span::RequestSpanLayer; #[tokio::test] @@ -43,6 +44,41 @@ async fn decapsulated_gets_fresh_id_discarding_inbound() { assert!(uuid::Uuid::parse_str(&id).is_ok(), "must mint a fresh UUID, got {id:?}"); } +/// Proves the fast path actually reads the `RequestId` extension instead of +/// re-parsing the header: the two are set to different values here, which +/// `RequestLogLayer` never lets happen in production, and the span (checked +/// via a log line emitted inside it) must carry the extension's value, not +/// the header's. +#[tokio::test] +#[traced_test] +async fn plaintext_prefers_request_id_extension_over_header() { + let mut request = Request::builder() + .method(Method::POST) + .uri("/") + .header(REQUEST_ID_HEADER, "header-value") + .body(HttpBody::new(Full::new(Bytes::new()))) + .expect("static body is infallible"); + request.extensions_mut().insert(RequestId("extension-value".to_string())); + + let logging_service = tower::service_fn(|_request: Request| async move { + tracing::info!("handler invoked"); + Ok::<_, std::convert::Infallible>( + Response::builder() + .status(StatusCode::OK) + .body(HttpBody::new(Full::new(Bytes::new()))) + .expect("static body is infallible"), + ) + }); + + RequestSpanLayer.layer(logging_service).oneshot(request).await.unwrap(); + + assert!(logs_contain("extension-value"), "span must carry the RequestId extension's value"); + assert!( + !logs_contain("header-value"), + "the mismatched header value must not leak into the span" + ); +} + /// The cross-layer plaintext contract: with `RequestLogLayer` (outer) stacked /// over `RequestSpanLayer` (inner) and no inbound id, the id the outer layer /// generates and echoes on the response must be the same id the inner layer From e953b25c6eae9096a8c28a19638049c5fe91f13b Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Mon, 13 Jul 2026 09:11:47 +0300 Subject: [PATCH 37/53] papyrus_base_layer: reset retry-primary clock on failed reset to avoid churning a down primary (#14700) (#14751) (cherry picked from commit 3175159095a1e0a087bf02c5b0638550724b51a7) Co-authored-by: asaf-sw Co-authored-by: Claude Opus 4.8 (1M context) --- .../src/cyclic_base_layer_wrapper.rs | 7 ++--- .../src/cyclic_base_layer_wrapper_test.rs | 27 +++++++++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/crates/papyrus_base_layer/src/cyclic_base_layer_wrapper.rs b/crates/papyrus_base_layer/src/cyclic_base_layer_wrapper.rs index 2d42260505a..69a99d86191 100644 --- a/crates/papyrus_base_layer/src/cyclic_base_layer_wrapper.rs +++ b/crates/papyrus_base_layer/src/cyclic_base_layer_wrapper.rs @@ -49,10 +49,11 @@ impl CyclicBaseLayerWrapper { return Ok(()); } if self.last_primary_retry.elapsed() >= self.retry_primary_interval { - // Advance the clock only after a successful reset, so a failed reset retries on the - // next access instead of waiting another full interval. - self.base_layer.reset_provider_url_to_primary().await?; + // Advance the clock before attempting the reset, so that whether or not the primary is + // back up we wait a full interval before retrying it again. This avoids churning the + // primary on every access while it is still down. self.last_primary_retry = tokio::time::Instant::now(); + self.base_layer.reset_provider_url_to_primary().await?; } Ok(()) } diff --git a/crates/papyrus_base_layer/src/cyclic_base_layer_wrapper_test.rs b/crates/papyrus_base_layer/src/cyclic_base_layer_wrapper_test.rs index cf370d2eb95..dc57719e56a 100644 --- a/crates/papyrus_base_layer/src/cyclic_base_layer_wrapper_test.rs +++ b/crates/papyrus_base_layer/src/cyclic_base_layer_wrapper_test.rs @@ -698,28 +698,39 @@ async fn test_retry_primary_fires_only_after_interval_elapses() { assert!(result.is_ok()); } -// A failed primary retry must not advance the clock, so the next L1 access retries the primary -// again instead of waiting another full interval. +// A failed primary retry still advances the clock, so the next L1 access within the interval does +// not churn the primary again — it waits a full interval before retrying it. #[tokio::test(start_paused = true)] -async fn test_retry_clock_not_advanced_when_reset_fails() { +async fn test_retry_clock_advanced_when_reset_fails() { const INTERVAL: Duration = Duration::from_secs(60); let mut base_layer = MockBaseLayerContract::new(); base_layer.expect_is_at_primary().returning(|| Ok(false)); - // Reset fails each time; the clock advances only on success, so each access stays due. + // Reset fires exactly once: the first access advances the clock even though the reset fails, + // so the second access (still within the interval) does not retry the primary again. base_layer .expect_reset_provider_url_to_primary() - .times(2) + .times(1) .returning(|| Err(MockError::MockError)); + base_layer.expect_get_url().returning(|| { + Ok(Sensitive::new(Url::parse("http://first_endpoint").unwrap()) + .with_redactor(to_safe_string)) + }); + // The second access skips the retry and runs the operation, which succeeds. + base_layer + .expect_get_proved_block_at() + .times(1) + .returning(|_| Ok(BlockHashAndNumber::default())); let mut wrapper = CyclicBaseLayerWrapper::new(base_layer, INTERVAL, ScraperLabel::L1Events); // Make the retry due. tokio::time::advance(INTERVAL).await; - // First access: retry is due, reset fails, so the operation errors. - assert!(wrapper.get_proved_block_at(1).await.is_err()); - // Still due (the failed reset did not advance the clock): the next access retries again. + // First access: retry is due, reset fails, so the operation errors before it runs. assert!(wrapper.get_proved_block_at(1).await.is_err()); + // The failed reset advanced the clock, so this access is no longer due: no second reset fires, + // and the operation runs and succeeds. + assert!(wrapper.get_proved_block_at(1).await.is_ok()); } // Verifies the primary-down-since gauge: From 1309215199e502efad4d35cb84089283efa0972c Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Mon, 13 Jul 2026 09:12:10 +0300 Subject: [PATCH 38/53] apollo_l1_events,apollo_l1_events_config: chunk L1 getLogs range into bounded windows (M-25) (#14602) (#14749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The L1 events scraper fetched the entire range from its cursor to the latest (finality-adjusted) L1 block in a single events()/eth_getLogs request. After downtime, an L1 outage, or with a large startup rewind, that range can span thousands of blocks, materializing an unbounded Vec/Vec and a single oversized RPC request that most providers reject or that hits the 1s base-layer timeout — wedging the scraper and (via the cyclic wrapper) misfiring the primary-down-since alert. Cap each fetch to a configurable max_blocks_per_fetch (default 1000, validated >= 1). fetch_events now requests scraping_start..=min(latest, start + cap - 1) and returns the L1BlockReference for the window end, so the cursor advances by exactly one window per poll and the steady-state loop drains a backlog over successive polls. The finality ceiling and the once-per-poll reorg check are preserved. initialize sends the first bounded window via the provider's initialize() and lets the steady loop drain the rest via add_events, so the provider's initialize-once contract is unchanged. Regenerated config_schema.json for the new field. Assumptions (documented in code): default 1000 is conservative versus common public-RPC eth_getLogs caps (~1k-10k) and the 1s timeout; operators on private RPCs may raise it. Saturating arithmetic guards against a 0 cap even though validation rejects it. (cherry picked from commit a1201fe37c67401ce85dfbcdda38e78ecd2e2f9b) Co-authored-by: asaf-sw Co-authored-by: Claude Opus 4.8 (1M context) --- .../app_configs/l1_events_scraper_config.json | 1 + .../replacer_l1_events_scraper_config.json | 1 + crates/apollo_l1_events/src/l1_scraper.rs | 43 ++- .../apollo_l1_events/src/l1_scraper_tests.rs | 314 +++++++++++++++++- crates/apollo_l1_events_config/src/config.rs | 17 + .../apollo_node/resources/config_schema.json | 5 + 6 files changed, 370 insertions(+), 11 deletions(-) diff --git a/crates/apollo_deployments/resources/app_configs/l1_events_scraper_config.json b/crates/apollo_deployments/resources/app_configs/l1_events_scraper_config.json index 99ca99f35a1..8b1217a787a 100644 --- a/crates/apollo_deployments/resources/app_configs/l1_events_scraper_config.json +++ b/crates/apollo_deployments/resources/app_configs/l1_events_scraper_config.json @@ -1,6 +1,7 @@ { "l1_events_scraper_config.finality": 10, "l1_events_scraper_config.l1_block_time_seconds": 12.0, + "l1_events_scraper_config.max_blocks_per_fetch": 1000, "l1_events_scraper_config.polling_interval_seconds": 30, "l1_events_scraper_config.set_provider_historic_height_to_l2_genesis": false, "l1_events_scraper_config.startup_rewind_time_seconds": 21600 diff --git a/crates/apollo_deployments/resources/app_configs/replacer_l1_events_scraper_config.json b/crates/apollo_deployments/resources/app_configs/replacer_l1_events_scraper_config.json index 99ca99f35a1..8b1217a787a 100644 --- a/crates/apollo_deployments/resources/app_configs/replacer_l1_events_scraper_config.json +++ b/crates/apollo_deployments/resources/app_configs/replacer_l1_events_scraper_config.json @@ -1,6 +1,7 @@ { "l1_events_scraper_config.finality": 10, "l1_events_scraper_config.l1_block_time_seconds": 12.0, + "l1_events_scraper_config.max_blocks_per_fetch": 1000, "l1_events_scraper_config.polling_interval_seconds": 30, "l1_events_scraper_config.set_provider_historic_height_to_l2_genesis": false, "l1_events_scraper_config.startup_rewind_time_seconds": 21600 diff --git a/crates/apollo_l1_events/src/l1_scraper.rs b/crates/apollo_l1_events/src/l1_scraper.rs index 0268311ef49..c6285ad18c5 100644 --- a/crates/apollo_l1_events/src/l1_scraper.rs +++ b/crates/apollo_l1_events/src/l1_scraper.rs @@ -207,25 +207,28 @@ impl L1EventsScraper L1EventsScraperResult { - let (latest_l1_block, events) = self.fetch_events().await?; + let (window_end_block, events) = self.fetch_events().await?; - debug!("Latest L1 block for initialize: {latest_l1_block:?}"); + debug!("Scraped up to L1 block for initialize: {window_end_block:?}"); debug!("All events scraped during initialize: {events:?}"); - // If this gets too high, send in batches. let initialize_result = self.l1_events_provider_client.initialize(historic_l2_height, events).await; handle_client_error(initialize_result)?; - Ok(latest_l1_block) + Ok(window_end_block) } /// Scrape recent events and send them to the L1 provider. @@ -299,9 +302,31 @@ impl L1EventsScraper L1EventsScraper L1Event { + L1Event::LogMessageToL2 { + tx: L1HandlerTransaction { + calldata: Calldata(vec![Felt::ONE].into()), + ..Default::default() + }, + fee: Fee::default(), + l1_tx_hash: None, + block_timestamp: BlockTimestamp::default(), + } +} + +// A getLogs failure must not advance the cursor; the same window is retried on the next poll. +#[tokio::test] +async fn cursor_not_advanced_on_events_rpc_failure() { + const START_BLOCK_NUMBER: u64 = 42; + const MAX_BLOCKS_PER_FETCH: u64 = 1000; + const LATEST_BLOCK_NUMBER: u64 = START_BLOCK_NUMBER + 5; + const L1_BLOCK_HASH: L1BlockHash = L1BlockHash([7; 32]); + + let mut base_layer = MockBaseLayerContract::new(); + base_layer.expect_latest_l1_block_number().returning(|| Ok(LATEST_BLOCK_NUMBER)); + base_layer + .expect_l1_block_at() + .returning(move |number| Ok(Some(L1BlockReference { number, hash: L1_BLOCK_HASH }))); + base_layer.expect_events().returning(|_, _| Err(MockError::MockError)); + + let mut scraper = scraper_with_dummy().await; + scraper.config.max_blocks_per_fetch = MAX_BLOCKS_PER_FETCH; + scraper.scrape_from_this_l1_block = + Some(L1BlockReference { number: START_BLOCK_NUMBER, hash: L1_BLOCK_HASH }); + scraper.base_layer = base_layer; + + assert_matches!( + scraper.send_events_to_l1_events_provider().await, + Err(L1EventsScraperError::BaseLayerError(_)) + ); + assert_eq!(scraper.scrape_from_this_l1_block.unwrap().number, START_BLOCK_NUMBER); +} + +// A commit (add_events) failure must not advance the cursor, so the events are not skipped. +#[tokio::test] +async fn cursor_not_advanced_on_add_events_failure() { + const START_BLOCK_NUMBER: u64 = 42; + const MAX_BLOCKS_PER_FETCH: u64 = 1000; + const LATEST_BLOCK_NUMBER: u64 = START_BLOCK_NUMBER + 5; + const L1_BLOCK_HASH: L1BlockHash = L1BlockHash([7; 32]); + + let mut base_layer = MockBaseLayerContract::new(); + base_layer.expect_latest_l1_block_number().returning(|| Ok(LATEST_BLOCK_NUMBER)); + base_layer + .expect_l1_block_at() + .returning(move |number| Ok(Some(L1BlockReference { number, hash: L1_BLOCK_HASH }))); + base_layer.expect_events().returning(|_, _| Ok(vec![log_message_to_l2_event()])); + + let mut l1_events_provider_client = MockL1EventsProviderClient::default(); + l1_events_provider_client.expect_add_events().once().returning(|_| { + Err(apollo_l1_events_types::errors::L1EventsProviderClientError::L1EventsProviderError( + L1EventsProviderError::Uninitialized, + )) + }); + + let mut scraper = scraper_with_dummy().await; + scraper.config.max_blocks_per_fetch = MAX_BLOCKS_PER_FETCH; + scraper.scrape_from_this_l1_block = + Some(L1BlockReference { number: START_BLOCK_NUMBER, hash: L1_BLOCK_HASH }); + scraper.base_layer = base_layer; + scraper.l1_events_provider_client = Arc::new(l1_events_provider_client); + + assert!(scraper.send_events_to_l1_events_provider().await.is_err()); + assert_eq!(scraper.scrape_from_this_l1_block.unwrap().number, START_BLOCK_NUMBER); +} + +// After a getLogs failure the retry must re-request the exact same [start, end] window (no bisect). +#[tokio::test] +async fn retry_refetches_same_window() { + const START_BLOCK_NUMBER: u64 = 10; + const MAX_BLOCKS_PER_FETCH: u64 = 100; + const LATEST_BLOCK_NUMBER: u64 = 1000; + const L1_BLOCK_HASH: L1BlockHash = L1BlockHash([7; 32]); + // Inclusive window [start+1 ..= start+max], so the expected end is start + max. + const EXPECTED_WINDOW_END: u64 = START_BLOCK_NUMBER + MAX_BLOCKS_PER_FETCH; + + let mut base_layer = MockBaseLayerContract::new(); + base_layer.expect_latest_l1_block_number().returning(|| Ok(LATEST_BLOCK_NUMBER)); + base_layer + .expect_l1_block_at() + .returning(move |number| Ok(Some(L1BlockReference { number, hash: L1_BLOCK_HASH }))); + // First attempt fails while requesting the capped window. + base_layer + .expect_events() + .withf(|block_range, _| { + *block_range.start() == START_BLOCK_NUMBER + 1 + && *block_range.end() == EXPECTED_WINDOW_END + }) + .times(1) + .returning(|_, _| Err(MockError::MockError)); + // The retry must request the identical window, not a bisected one. + base_layer + .expect_events() + .withf(|block_range, _| { + *block_range.start() == START_BLOCK_NUMBER + 1 + && *block_range.end() == EXPECTED_WINDOW_END + }) + .times(1) + .returning(|_, _| Ok(vec![])); + + let mut scraper = scraper_with_dummy().await; + scraper.config.max_blocks_per_fetch = MAX_BLOCKS_PER_FETCH; + scraper.scrape_from_this_l1_block = + Some(L1BlockReference { number: START_BLOCK_NUMBER, hash: L1_BLOCK_HASH }); + scraper.base_layer = base_layer; + + assert_matches!( + scraper.send_events_to_l1_events_provider().await, + Err(L1EventsScraperError::BaseLayerError(_)) + ); + assert_eq!(scraper.scrape_from_this_l1_block.unwrap().number, START_BLOCK_NUMBER); + + scraper.send_events_to_l1_events_provider().await.unwrap(); + assert_eq!(scraper.scrape_from_this_l1_block.unwrap().number, EXPECTED_WINDOW_END); +} + +// Capping the block range must never drop events: every event in the dense window is forwarded. +#[tokio::test] +async fn fetch_events_returns_all_events_in_dense_window() { + const MAX_BLOCKS_PER_FETCH: u64 = 10; + const START_BLOCK_NUMBER: u64 = 0; + const LATEST_BLOCK_NUMBER: u64 = 1000; + const NUM_EVENTS: usize = 500; + const L1_BLOCK_HASH: L1BlockHash = L1BlockHash([7; 32]); + // Inclusive window [start+1 ..= start+max], so the expected end is start + max. + const EXPECTED_WINDOW_END: u64 = START_BLOCK_NUMBER + MAX_BLOCKS_PER_FETCH; + + let mut base_layer = MockBaseLayerContract::new(); + base_layer.expect_latest_l1_block_number().returning(|| Ok(LATEST_BLOCK_NUMBER)); + base_layer + .expect_l1_block_at() + .returning(move |number| Ok(Some(L1BlockReference { number, hash: L1_BLOCK_HASH }))); + base_layer + .expect_events() + .times(1) + .returning(|_, _| Ok((0..NUM_EVENTS).map(|_| log_message_to_l2_event()).collect())); + + let forwarded_events: Arc>> = Arc::new(Mutex::new(vec![])); + let forwarded_events_clone = forwarded_events.clone(); + let mut l1_events_provider_client = MockL1EventsProviderClient::default(); + l1_events_provider_client.expect_add_events().once().returning(move |events| { + *forwarded_events_clone.lock().unwrap() = events; + Ok(()) + }); + + let mut scraper = scraper_with_dummy().await; + scraper.config.max_blocks_per_fetch = MAX_BLOCKS_PER_FETCH; + scraper.scrape_from_this_l1_block = + Some(L1BlockReference { number: START_BLOCK_NUMBER, hash: L1_BLOCK_HASH }); + scraper.base_layer = base_layer; + scraper.l1_events_provider_client = Arc::new(l1_events_provider_client); + + scraper.send_events_to_l1_events_provider().await.unwrap(); + + assert_eq!(forwarded_events.lock().unwrap().len(), NUM_EVENTS); + assert_eq!(scraper.scrape_from_this_l1_block.unwrap().number, EXPECTED_WINDOW_END); +} + #[test] #[ignore = "similar to backlog_happy_flow, only shorter, and sprinkle some start_block/get_txs \ attempts while its catching up (and assert failure on height), then assert that they \ diff --git a/crates/apollo_l1_events_config/src/config.rs b/crates/apollo_l1_events_config/src/config.rs index 07966baebc2..d6161fd998e 100644 --- a/crates/apollo_l1_events_config/src/config.rs +++ b/crates/apollo_l1_events_config/src/config.rs @@ -115,6 +115,11 @@ pub struct L1EventsScraperConfig { pub set_provider_historic_height_to_l2_genesis: bool, #[serde(deserialize_with = "deserialize_float_seconds_to_duration")] pub l1_block_time_seconds: Duration, + /// Maximum number of L1 blocks fetched per `events` (eth_getLogs) request. Caps the catch-up + /// window so a large backlog is drained over successive polls instead of one unbounded + /// request. + #[validate(range(min = 1))] + pub max_blocks_per_fetch: u64, } impl Default for L1EventsScraperConfig { @@ -126,6 +131,10 @@ impl Default for L1EventsScraperConfig { polling_interval_seconds: Duration::from_secs(30), set_provider_historic_height_to_l2_genesis: false, l1_block_time_seconds: Duration::from_secs(12), + // Conservative default: well under the common public-RPC eth_getLogs block-range caps + // (~1k-10k) and the 1s base-layer timeout. Operators on permissive private RPCs may + // raise it. + max_blocks_per_fetch: 1000, } } } @@ -170,6 +179,14 @@ impl SerializeConfig for L1EventsScraperConfig { "The time it takes for a new L1 block to be created.", ParamPrivacyInput::Public, ), + ser_param( + "max_blocks_per_fetch", + &self.max_blocks_per_fetch, + "Maximum number of L1 blocks fetched per events (eth_getLogs) request. Caps the \ + catch-up window so a large backlog is drained over successive polls instead of in \ + one unbounded request.", + ParamPrivacyInput::Public, + ), ]) } } diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 70000431765..cc1c89356af 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -3269,6 +3269,11 @@ "privacy": "Public", "value": 12 }, + "l1_events_scraper_config.max_blocks_per_fetch": { + "description": "Maximum number of L1 blocks fetched per events (eth_getLogs) request. Caps the catch-up window so a large backlog is drained over successive polls instead of in one unbounded request.", + "privacy": "Public", + "value": 1000 + }, "l1_events_scraper_config.polling_interval_seconds": { "description": "Interval in Seconds between each scraping attempt of L1.", "privacy": "Public", From e2296ea7c0c7c8f38042846fdf5edf7279f15fa4 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Mon, 13 Jul 2026 09:15:58 +0300 Subject: [PATCH 39/53] apollo_mempool: remove evicted txs from queue in try_make_space (#14568) (#14755) In Echonet/FIFO mode gap-account txs are queued, so evicting them from the pool without removing them from the queue left an orphaned reference that panicked the next get_txs. Reconcile the queue with the pool after eviction. (cherry picked from commit 0481c81312963fff3a4740cc56efb8b0ea684b7a) Co-authored-by: dan-starkware <56217775+dan-starkware@users.noreply.github.com> --- .../apollo_mempool/src/fifo_mempool_test.rs | 64 ++++++++++++++++++- crates/apollo_mempool/src/mempool.rs | 12 +++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/crates/apollo_mempool/src/fifo_mempool_test.rs b/crates/apollo_mempool/src/fifo_mempool_test.rs index f7e4225a628..046f2637689 100644 --- a/crates/apollo_mempool/src/fifo_mempool_test.rs +++ b/crates/apollo_mempool/src/fifo_mempool_test.rs @@ -3,10 +3,13 @@ use std::time::Duration; use apollo_config::behavior_mode::BehaviorMode; use apollo_mempool_config::config::{MempoolConfig, MempoolDynamicConfig, MempoolStaticConfig}; +use apollo_mempool_types::mempool_types::{AccountState, AddTransactionArgs}; use apollo_time::test_utils::FakeClock; use rstest::{fixture, rstest}; +use starknet_api::test_utils::invoke::internal_invoke_tx; use starknet_api::test_utils::valid_resource_bounds_for_testing; -use starknet_api::{contract_address, declare_tx_args, tx_hash}; +use starknet_api::transaction::fields::TransactionSignature; +use starknet_api::{contract_address, declare_tx_args, felt, invoke_tx_args, nonce, tx_hash}; use crate::add_tx_input; use crate::mempool::Mempool; @@ -572,3 +575,62 @@ fn test_rejected_tx_removes_same_address_from_fifo_queue(mut mempool: Mempool) { assert_eq!(mempool.resolve_batch_timestamp(), 1001); get_txs_and_assert_expected(&mut mempool, 10, &[other_address_tx.tx]); } + +#[rstest] +fn test_eviction_keeps_pool_and_queue_consistent() { + // In Echonet/FIFO mode, a gap account's transactions are enqueued (unlike fee mode, where gap + // accounts hold nothing in the queue). When `try_make_space` evicts such an account to free + // capacity, the evicted txs must be removed from BOTH the pool and the FIFO queue. Otherwise + // the queue keeps an orphaned reference to a tx no longer in the pool, and the next `get_txs` + // panics when it pops that reference (`get_submission_id(...).expect(...)`). + + // A gap account ("0x1") with a single, deliberately large transaction (large signature) so + // evicting it frees more than enough room for the smaller trigger tx. + let large_gap_tx = AddTransactionArgs { + tx: internal_invoke_tx(invoke_tx_args!( + tx_hash: tx_hash!(1), + sender_address: contract_address!("0x1"), + nonce: nonce!(1), + signature: TransactionSignature(vec![felt!("0x0"); 64].into()), + )), + account_state: AccountState { address: contract_address!("0x1"), nonce: nonce!(0) }, + }; + // A new account whose tx nonce equals its account nonce, so adding it does NOT create a gap and + // therefore takes the `try_make_space` eviction path in `handle_capacity_overflow`. + let trigger_tx = add_tx_input!(tx_hash: 2, address: "0x2", tx_nonce: 0, account_nonce: 0); + + // Capacity holds exactly the large gap tx; adding the trigger tx overflows and forces eviction. + let mut mempool = Mempool::new( + MempoolConfig { + static_config: MempoolStaticConfig { + behavior_mode: BehaviorMode::Echonet, + capacity_in_bytes: large_gap_tx.tx.total_bytes(), + ..Default::default() + }, + ..Default::default() + }, + Arc::new(FakeClock::default()), + ); + + mempool.update_tx_block_metadata(tx_hash!(1), tx_metadata(1000, 100)); + mempool.update_tx_block_metadata(tx_hash!(2), tx_metadata(1000, 100)); + + // The gap account's tx is enqueued in FIFO mode (added regardless of nonce) and the account + // enters `accounts_with_gap` (lowest nonce 1 > account nonce 0). + add_tx(&mut mempool, &large_gap_tx); + + // Adding the trigger tx overflows capacity and evicts the gap account via `try_make_space`. + add_tx(&mut mempool, &trigger_tx); + + // Before the fix this `get_txs` pops the orphaned gap-tx reference and panics. After the fix + // the orphan is gone from the queue, so only the trigger tx is returned. + get_txs_and_assert_expected(&mut mempool, 10, std::slice::from_ref(&trigger_tx.tx)); + + // The evicted gap tx must be absent from both the pool and the queue. + let snapshot = mempool.mempool_snapshot().unwrap(); + assert!(!snapshot.transactions.contains(&tx_hash!(1)), "evicted tx still present in pool"); + assert!( + !snapshot.transaction_queue.priority_queue.contains(&tx_hash!(1)), + "evicted tx still present in queue" + ); +} diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index 5cff36b1cf2..6c5b4d72da9 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -1003,10 +1003,11 @@ impl Mempool { // Returns true if enough space was freed, false otherwise. pub fn try_make_space(&mut self, required_space: u64) -> bool { let mut total_space_freed = 0; + let mut evicted_txs = Vec::new(); while total_space_freed < required_space { let Some(address) = self.get_evictable_account() else { - return false; + break; }; let txs: Vec<_> = self.tx_pool.account_txs_sorted_by_nonce(address).copied().collect(); @@ -1016,6 +1017,7 @@ impl Mempool { .remove(tx_ref.tx_hash) .expect("Transaction must exist in the pool."); total_space_freed += tx.total_bytes(); + evicted_txs.push(*tx_ref); metric_count_evicted_txs(1); self.decrement_stuck_txs_if_gap_account(address, 1); if total_space_freed >= required_space { @@ -1029,7 +1031,13 @@ impl Mempool { } } - true + // Keep the queue consistent with the pool: the evicted txs were removed from the pool, so + // drop their (now-orphaned) queue references too. In fee mode gap accounts are never + // queued, so this is a no-op there; in Echonet/FIFO mode they are, and skipping this leaves + // a dangling reference that panics the next `get_txs`. + self.tx_queue.remove_txs(&evicted_txs); + + total_space_freed >= required_space } fn handle_capacity_overflow( From 99261aa5bc26055e91fee238910626ccc25a5fa5 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Mon, 13 Jul 2026 10:01:54 +0300 Subject: [PATCH 40/53] apollo_mempool,apollo_mempool_config: round up required fee-escalation bump on replacement (#14604) (#14756) Fee-escalation replacement required `incoming >= existing + existing*pct/100` with truncating division. For small fee values the required bump truncated to zero, so an equal-fee transaction was accepted, allowing replacement churn at no added cost. Fix `increased_enough` to round the required increase up via `div_ceil(100)`, so any positive `fee_escalation_percentage` always demands a strictly higher fee, even for small values. Overflow still gracefully rejects via `checked_*`. No absolute floor is needed: real fees are in the millions, and round-up alone already forces a strictly higher fee for every >=1% escalation. The integer-percentage minimum is enforced at config level via `#[validate(range(min = 1, max = 100))]` on `fee_escalation_percentage`, which rules out the degenerate `0%` case. Replace the minimum-bump tests with `test_fee_escalation_rounds_up_required_bump` (existing fee 5 at 10% rounds up to a required +1) and keep the config-validation test asserting `fee_escalation_percentage = 0` fails `validate()`. (cherry picked from commit 9736a24a75bed439b0ef8be386389a7c91f0773d) Co-authored-by: asaf-sw Co-authored-by: Claude Opus 4.8 (1M context) --- crates/apollo_mempool/src/fee_mempool_test.rs | 36 ++++++++++++++++--- crates/apollo_mempool/src/mempool.rs | 9 +++-- crates/apollo_mempool_config/src/config.rs | 6 +++- .../apollo_mempool_config/src/config_test.rs | 14 ++++++++ 4 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 crates/apollo_mempool_config/src/config_test.rs diff --git a/crates/apollo_mempool/src/fee_mempool_test.rs b/crates/apollo_mempool/src/fee_mempool_test.rs index 5cb9bb67217..bf262c1475a 100644 --- a/crates/apollo_mempool/src/fee_mempool_test.rs +++ b/crates/apollo_mempool/src/fee_mempool_test.rs @@ -828,12 +828,12 @@ fn fee_escalation_queue_removal() { let mut mempool = MempoolTestContentBuilder::new() .with_priority_queue([queued_tx_reference]) .with_pool([queued_tx.clone(), tx_to_be_replaced]) - .with_fee_escalation_percentage(0) // Always replace. + .with_fee_escalation_percentage(10) .build_full_mempool(); // Test and assert: replacement doesn't affect queue. - let valid_replacement_input = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 1, tip: 0, max_l2_gas_price: min_gas_price); + let valid_replacement_input = add_tx_input!(tx_hash: 2, address: "0x0", tx_nonce: 1, tip: 1, max_l2_gas_price: min_gas_price + 1); add_tx(&mut mempool, &valid_replacement_input); let expected_mempool_content = MempoolTestContentBuilder::new() .with_pool([queued_tx, valid_replacement_input.tx]) @@ -849,12 +849,12 @@ fn test_fee_escalation_valid_replacement_minimum_values() { let tx = tx!(tx_hash: 0, tip: 0, max_l2_gas_price: min_gas_price); let mempool = MempoolTestContentBuilder::new() .with_pool([tx]) - .with_fee_escalation_percentage(0) // Always replace. + .with_fee_escalation_percentage(10) .build_full_mempool(); - // Test and assert: replacement with maximum values. + // Test and assert: smallest replacement that clears the minimum bump on both bounds. let valid_replacement_input = - add_tx_input!(tx_hash: 1, tip: 0, max_l2_gas_price: min_gas_price); + add_tx_input!(tx_hash: 1, tip: 1, max_l2_gas_price: min_gas_price + 1); validate_and_add_tx_and_verify_replacement_in_pool(mempool, valid_replacement_input); } @@ -922,6 +922,32 @@ fn test_fee_escalation_invalid_replacement_overflow_gracefully_handled() { ); } +#[rstest] +fn test_fee_escalation_rounds_up_required_bump() { + // 10% of 5 is 0.5, which rounds up to a required increase of 1: an equal fee is rejected and a + // +1 replacement is accepted. + let existing_tx = tx!(tx_hash: 0, tip: 5, max_l2_gas_price: 5); + + let equal_fee_replacement = add_tx_input!(tx_hash: 1, tip: 5, max_l2_gas_price: 5); + let mempool = MempoolTestContentBuilder::new() + .with_pool([existing_tx.clone()]) + .with_fee_escalation_percentage(10) + .build_full_mempool(); + validate_and_add_txs_and_verify_no_replacement_in_pool( + mempool, + existing_tx, + [equal_fee_replacement], + ); + + let existing_tx = tx!(tx_hash: 0, tip: 5, max_l2_gas_price: 5); + let plus_one_replacement = add_tx_input!(tx_hash: 2, tip: 6, max_l2_gas_price: 6); + let mempool = MempoolTestContentBuilder::new() + .with_pool([existing_tx]) + .with_fee_escalation_percentage(10) + .build_full_mempool(); + validate_and_add_tx_and_verify_replacement_in_pool(mempool, plus_one_replacement); +} + // `update_gas_price_threshold` tests. #[rstest] diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index 6c5b4d72da9..adce91f0e52 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -821,13 +821,12 @@ impl Mempool { fn increased_enough(&self, existing_value: u128, incoming_value: u128) -> bool { let percentage = u128::from(self.config.static_config.fee_escalation_percentage); - // Note: To reduce precision loss, we first multiply by the percentage and then divide by - // 100. This could cause an overflow and an automatic rejection of the transaction, but the - // values aren't expected to be large enough for this to be an issue. + // Round up the required increase so any positive percentage always demands a strictly + // higher fee, even for small values. let Some(escalation_qualified_value) = existing_value .checked_mul(percentage) - .map(|v| v / 100) - .and_then(|increase| existing_value.checked_add(increase)) + .map(|scaled| scaled.div_ceil(100)) + .and_then(|required_increase| existing_value.checked_add(required_increase)) else { // Overflow occurred during calculation; reject the transaction. return false; diff --git a/crates/apollo_mempool_config/src/config.rs b/crates/apollo_mempool_config/src/config.rs index 8c059e452fd..baa944856ad 100644 --- a/crates/apollo_mempool_config/src/config.rs +++ b/crates/apollo_mempool_config/src/config.rs @@ -9,6 +9,10 @@ use serde::{Deserialize, Serialize}; use url::Url; use validator::Validate; +#[cfg(test)] +#[path = "config_test.rs"] +mod config_test; + /// Configuration for consensus containing both static and dynamic configs. #[derive(Debug, Deserialize, Default, Serialize, Clone, PartialEq, Validate)] pub struct MempoolConfig { @@ -57,8 +61,8 @@ impl SerializeConfig for MempoolDynamicConfig { #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Validate)] pub struct MempoolStaticConfig { pub enable_fee_escalation: bool, - // TODO(AlonH): consider adding validations; should be bounded? // Percentage increase for tip and max gas price to enable transaction replacement. + #[validate(range(min = 1, max = 100))] pub fee_escalation_percentage: u8, // E.g., 10 for a 10% increase. // If true, only transactions with max L2 gas price per unit bound that are above the threshold // are inserted into the priority queue. If false, all transactions are inserted into the diff --git a/crates/apollo_mempool_config/src/config_test.rs b/crates/apollo_mempool_config/src/config_test.rs new file mode 100644 index 00000000000..25f365df004 --- /dev/null +++ b/crates/apollo_mempool_config/src/config_test.rs @@ -0,0 +1,14 @@ +use validator::Validate; + +use super::MempoolStaticConfig; + +#[test] +fn default_static_config_passes_validation() { + assert!(MempoolStaticConfig::default().validate().is_ok()); +} + +#[test] +fn zero_fee_escalation_percentage_fails_validation() { + let static_config = MempoolStaticConfig { fee_escalation_percentage: 0, ..Default::default() }; + assert!(static_config.validate().is_err()); +} From ec68ee579c50036705c180871de2e5c9070a6778 Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Wed, 15 Jul 2026 13:08:42 +0300 Subject: [PATCH 41/53] starknet_transaction_prover,blockifier_reexecution: drop sierra-compile sidecar from docker images (#14418) Co-authored-by: Claude Opus 4.8 (1M context) --- crates/blockifier_reexecution/replay/Dockerfile | 14 +++++++------- crates/starknet_transaction_prover/Dockerfile | 11 ----------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/crates/blockifier_reexecution/replay/Dockerfile b/crates/blockifier_reexecution/replay/Dockerfile index eb0b6ad628e..b4a7ef53667 100644 --- a/crates/blockifier_reexecution/replay/Dockerfile +++ b/crates/blockifier_reexecution/replay/Dockerfile @@ -86,11 +86,11 @@ RUN cargo chef cook --release -p blockifier_reexecution --features cairo_native COPY . . RUN cargo build --release -p blockifier_reexecution --features cairo_native -# Install compiler binaries used for Sierra compilation at runtime. -# Binaries land under $CARGO_TOOLS_ROOT/-/bin/; the -# final stage below COPYs the entire $CARGO_TOOLS_ROOT tree so this layout is -# preserved at runtime. -RUN scripts/install_compiler_binaries.sh +# Install the Sierra-to-Native compiler binary used at runtime (Sierra-to-Casm +# compilation is done in-process). The binary lands under +# $CARGO_TOOLS_ROOT/-/bin/; the final stage below COPYs +# the entire $CARGO_TOOLS_ROOT tree so this layout is preserved at runtime. +RUN scripts/install_compiler_binaries.sh --native # ============================================================================= # Stage 4: Final runtime image @@ -108,9 +108,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ENV ID=1001 WORKDIR /app -# Copy the binary and both compilers (Sierra-to-CASM and Sierra-to-Native). +# Copy the binary and the Sierra-to-Native compiler. COPY --from=builder /app/target/release/blockifier_reexecution ./target/release/blockifier_reexecution -# Per-version compiler binaries; their absolute path is constructed from +# Per-version compiler binary; its absolute path is constructed from # $CARGO_TOOLS_ROOT at runtime. ENV CARGO_TOOLS_ROOT=/opt/cargo-tools COPY --from=builder /var/tmp/rust/tools ${CARGO_TOOLS_ROOT} diff --git a/crates/starknet_transaction_prover/Dockerfile b/crates/starknet_transaction_prover/Dockerfile index f9a094401bb..71bacc14c94 100644 --- a/crates/starknet_transaction_prover/Dockerfile +++ b/crates/starknet_transaction_prover/Dockerfile @@ -144,12 +144,6 @@ RUN BUILD_FLAGS=$([ "$BUILD_MODE" = "release" ] && echo "--release" || true); \ cargo build $BUILD_FLAGS -p starknet_transaction_prover --features stwo_proving; \ fi -# Install compiler binary used for Sierra to CASM compilation at runtime. -# Binary lands under $CARGO_TOOLS_ROOT/-/bin/; the -# final stage below COPYs the entire $CARGO_TOOLS_ROOT tree so this layout is -# preserved at runtime. -RUN scripts/install_compiler_binaries.sh --sierra - # ============================================================================= # Stage 4: Final runtime image # ============================================================================= @@ -172,11 +166,6 @@ COPY --from=builder /app/target/${BUILD_MODE}/starknet_transaction_prover ./targ # Copy resources needed by the service. COPY --from=builder /app/crates/starknet_transaction_prover/resources ./crates/starknet_transaction_prover/resources -# Per-version Sierra-to-CASM compiler binary; its absolute path is constructed -# from $CARGO_TOOLS_ROOT at runtime. -ENV CARGO_TOOLS_ROOT=/opt/cargo-tools -COPY --from=builder /var/tmp/rust/tools ${CARGO_TOOLS_ROOT} - # Copy tini for proper init handling. COPY --from=builder /usr/bin/tini /usr/bin/tini From 499878ef14e771488bf91b913f1354bd32f6d461 Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Wed, 15 Jul 2026 13:37:42 +0300 Subject: [PATCH 42/53] workspace: upgrade cairo compiler to v2.19.3 (#14805) Bumps the Rust cairo-lang-* crates and the Sierra compiler binary version from 2.19.2 to 2.19.3. The bump moves the Sierra version from 1.9.1 to 1.9.2, cascading into Cairo1 class hashes and their downstream fixtures: starknet_os_flow_tests hint-coverage/fuzz fixtures, the cende blob regression (operator/fee-token addresses, GCS blob generation), and the apollo_integration_tests proof-flow fixtures. Co-authored-by: Claude Opus 4.8 (1M context) --- Cargo.lock | 124 +++++++++--------- Cargo.toml | 12 +- .../src/cairo_compiler_version.txt | 2 +- .../resources/proof_flow/proof.bin | Bin 231405 -> 229672 bytes .../resources/proof_flow/proof_facts.json | 4 +- .../src/state_reader.rs | 2 +- .../src/fee_token_addresses.rs | 2 +- .../resources/blob_file_generation | 2 +- .../resources/chain_info.json | 2 +- .../resources/preconfirmed_block.json | 24 ++-- .../src/cende_blob_regression_test.rs | 4 +- .../src/contract_class/structs.rs | 2 +- .../hint_coverage/test_deploy_syscall.json | 3 + ...est_deprecated_call_contract_variants.json | 3 + .../test_direct_execute_call.json | 3 + ...se_full_output_false_private_keys_3_1.json | 3 + ..._full_output_false_private_keys_empty.json | 3 + ...e_full_output_false_private_keys_none.json | 3 + ...lse_full_output_true_private_keys_3_1.json | 3 + ...e_full_output_true_private_keys_empty.json | 3 + ...se_full_output_true_private_keys_none.json | 3 + ...ue_full_output_false_private_keys_3_1.json | 3 + ..._full_output_false_private_keys_empty.json | 3 + ...e_full_output_false_private_keys_none.json | 3 + ...rue_full_output_true_private_keys_3_1.json | 3 + ...e_full_output_true_private_keys_empty.json | 3 + ...ue_full_output_true_private_keys_none.json | 3 + ...class_execution_info_use_kzg_da_false.json | 3 + ..._class_execution_info_use_kzg_da_true.json | 3 + .../hint_coverage/test_resources_type.json | 3 + .../hint_coverage/test_reverted_call.json | 3 + .../test_reverted_invoke_tx_cairo0.json | 3 + .../test_reverted_invoke_tx_cairo1.json | 3 + ...lse_full_output_false_contract_cairo0.json | 3 + ...lse_full_output_false_contract_cairo1.json | 3 + ...alse_full_output_true_contract_cairo0.json | 3 + ...alse_full_output_true_contract_cairo1.json | 3 + ...rue_full_output_false_contract_cairo0.json | 3 + ...rue_full_output_false_contract_cairo1.json | 3 + ...true_full_output_true_contract_cairo0.json | 3 + ...true_full_output_true_contract_cairo1.json | 3 + .../starknet_os_flow_tests/src/fuzz_tests.rs | 10 +- 42 files changed, 182 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 498b9b55c7c..461ca119474 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4277,9 +4277,9 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ec715a91e425ffc27a20b78ca9b5e0f63479af2277f99402fd329ef6c30d12" +checksum = "1d4a41f443251ec4a5792dea7336ec53080e03289c9bb220dcb40c9f4b8e1aa5" dependencies = [ "cairo-lang-utils", "indoc 2.0.7", @@ -4292,9 +4292,9 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceae4e541648118405b7c9012abaa3ddeec5ed5712f5443eb6f1fa823297c342" +checksum = "a3992825e97d751ea37fda93202de8bca84561ee269f1c056758cf49036ffcbd" dependencies = [ "anyhow", "cairo-lang-defs", @@ -4319,9 +4319,9 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55819e6796708cd4fc0713a98f3e4c1b1474371d400244f3a5a67986a7c7849f" +checksum = "4a3766f806466e41373f3541f1c8b710700c91e9ea1908779ff5334b0b63436c" dependencies = [ "cairo-lang-utils", "id-arena", @@ -4330,9 +4330,9 @@ dependencies = [ [[package]] name = "cairo-lang-defs" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "986247de31f01b2d97edb841d13cd63486b57a2a642275ec9c2d12144a7015b7" +checksum = "07f02936c38adb8bcce44df3d566f1402187b76c29d0d067190ee0db9a0723d8" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -4351,9 +4351,9 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79af76a3d672eb6264e27cb822da41f7db317ee57dddf2aac9cc82301e244e5c" +checksum = "80ecb908bc28c05f1f940f494da698e778fe025ef37d89052b68b4abb93d8dc1" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -4365,9 +4365,9 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b1402e0d1ba3d3520503b7167c1d6a67d1130a60cd3d97a4a47a153bd01d24" +checksum = "7f35cb0ec48cffb591040574adf3de3ceca736a70a171095a8b435f1a037871a" dependencies = [ "cairo-lang-utils", "good_lp", @@ -4375,9 +4375,9 @@ dependencies = [ [[package]] name = "cairo-lang-executable" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76081cb2ee71e4f17851d6a8ce676b24dc6cee84e2f8b931a9411f7f3776c6c2" +checksum = "5da465e2f463d9ce7029825838e51b5b8e601c062b98ee2d1632d4af42fb0f95" dependencies = [ "anyhow", "cairo-lang-casm", @@ -4400,9 +4400,9 @@ dependencies = [ [[package]] name = "cairo-lang-executable-plugin" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf365491e69985e1956f68170484ad696e5189a987c32b6c179756667dd17c67" +checksum = "a0309ae3ecd4a99e0c18cc25fc96186f0452696fe7004dfb5503bad1d3cda795" dependencies = [ "cairo-lang-defs", "cairo-lang-filesystem", @@ -4415,9 +4415,9 @@ dependencies = [ [[package]] name = "cairo-lang-execute-utils" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda43c673bde6774cd83b967cc5c92236fcf623f5daa30425e344e963305c0cb" +checksum = "522512668d118ac760b1fc4802f38df0dfd23c955c9e7bd10f2054ebefdb5518" dependencies = [ "anyhow", "cairo-lang-casm", @@ -4431,9 +4431,9 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00b4ccd5c0c503ba0fddcb8e6e69b00cedb6eb4e65b56ebac367c4689ef40bb" +checksum = "c6e41183ecb1940e99f5ee906e85851b0c6ce3a5a5f439ca19b81ad5addf475c" dependencies = [ "cairo-lang-debug", "cairo-lang-proc-macros", @@ -4449,9 +4449,9 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065d39de3cfe2e78d1a17cc604a4e10eb182ba737bb365671ad5855f895d6b42" +checksum = "9d246d5fb6de0812fa0e47c43b2e74148b7e4f0eb7d6054da409fec6e104692a" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -4469,9 +4469,9 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5290e70e800d886429bfc00bae1be9e3312e5bf22cbce302e1b3dc34e0d2c9b4" +checksum = "5c3c2419450b854a78f6e7e3840f7058a0145e9f4ffa13825a6468caf2f2539d" dependencies = [ "assert_matches", "cairo-lang-debug", @@ -4499,9 +4499,9 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16348bdf8ada212c0590a23a08c28ae57cd9db25497fc388a9651d444ab17497" +checksum = "7e4b57387ea001f7e684625873716810410a4bf17068cf4ed21a8ffc8dc0fb5e" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -4519,9 +4519,9 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9791844a410181910f864fdf1a7c64ac84fbe9d7addbcb4d65ecb51dda0aac1" +checksum = "0386b7b2c46a40c14c8172a2bff6cb9d23ffdb1dcc45085d531301ffc8eb4eb1" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", @@ -4543,9 +4543,9 @@ checksum = "123ac0ecadf31bacae77436d72b88fa9caef2b8e92c89ce63a125ae911a12fae" [[package]] name = "cairo-lang-proc-macros" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30618f3bc4463ea192be68dfe416f0b02268c986235aad3599b18564875ec035" +checksum = "0a3de5d45e554c007025f7ae45f66435f8470b9ed92b0dc279112311b485977e" dependencies = [ "cairo-lang-debug", "proc-macro2", @@ -4556,9 +4556,9 @@ dependencies = [ [[package]] name = "cairo-lang-project" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde78a3b75962ebf39a2b1cd3a7f9e5b67d058a00cad60120dfcd9df7df991a4" +checksum = "0c0107cb21aba6c1231172cfda2f0dc80232295a2f4f8565e65fc2842a3557a6" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", @@ -4569,9 +4569,9 @@ dependencies = [ [[package]] name = "cairo-lang-runnable-utils" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed383329002e7e4998ac7c76db319a1a8ab36b0a931871ca8f58900dd112dc71" +checksum = "f55fb0e2d7157a268c76d233edd64fddd6d1a63d167d522b063cfd2336b5789a" dependencies = [ "cairo-lang-casm", "cairo-lang-sierra", @@ -4586,9 +4586,9 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8674fd79d56dee8ffa915089c491ec2d06670016e4dcb6e627196c85a9cad6f2" +checksum = "889d6dab31b15f99129780cd3e074207506a8c58ebeeb8bf8093636bb0fd387b" dependencies = [ "ark-ff 0.6.0", "ark-secp256k1 0.6.0", @@ -4618,9 +4618,9 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636e004ad0f8ae193243fb6105302223c7e2b548a8c42726e54660f003b8e1d4" +checksum = "44d9db2517bdc21eab269a9f9d3a57f0b71d87a09952be775d16474c6076206b" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -4648,9 +4648,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaa94cf8bf1867ba3923fb11d8f998fe63712e19fd50be133bebb179cd0bce2" +checksum = "bccf8db70e368560725e0f8629013e5cd309edcf12699cd503ad339e94b5fe26" dependencies = [ "anyhow", "cairo-lang-utils", @@ -4674,9 +4674,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f561f526cfdbb6b1400246c92fea77bfd3e9fa34a79e88a9a15c6917931a473" +checksum = "32bd3a7458eebddc672f47937fa6eced344d50c7815b40e20aeb5d3d7dfb80a1" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -4690,9 +4690,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c13c715b678f2a9d2f7dc54ce53bb4068fb2d6ddbb21c758c4c7538ab12eca4" +checksum = "2dc33bddca1a034cd5a604caffb4a267a30d5b11d01fd64a21ae25b9fbbb05a8" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -4706,9 +4706,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0513f22a42f3d785fca47c533d6f199aa590c2b9e06bcd41ab564de611edd55c" +checksum = "b1b43bad5af32ab1520526d950e34f31fa774c4dc84123813ea851edc9a76b61" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -4731,9 +4731,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a741da915eea1822cde8cf27814066ae98aab994e52f34ad162954c3b53fbd" +checksum = "36f07e9211a6788e2456883dd48dfa5c35b1c3661afb40c693cb651cd8c0656e" dependencies = [ "assert_matches", "cairo-lang-casm", @@ -4752,9 +4752,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-type-size" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4b565cc9e67da5cab8543034353c1f8b1fc3f7ccf2e4dad16d1fc8509d038f" +checksum = "ce9d7c8f8ce5d2ace0f52b720c63f2dec73bcd8b83b62b20deed0b05a0a8801f" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -4762,9 +4762,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727381cd2b30bd84d071e797eb3ad777b9c64e072506d2271a1c08d9724010ab" +checksum = "fce0431088acdfcd698b4865e949ff485b76619ce8e5c4f87289f2183cc9be4a" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -4795,9 +4795,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet-classes" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "178980f5a61eba08802b045aa1ba067e4ad716123547b32f13bccdf821b5c8bb" +checksum = "a3ecba38ab82e8c00e0122553d83035927415db42b649268fa36e8a82f16a7fc" dependencies = [ "cairo-lang-casm", "cairo-lang-sierra", @@ -4819,9 +4819,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf61a7a6b1edb22ee6c52a198f450372e9f2541d60a99f130ee68539b35adb06" +checksum = "fd435fbc911164c57856b510412fd6fcee779da01e057855deacc4e23150b472" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -4838,9 +4838,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aa0048c370bdd67a6144a363f08cffc3cee3bf72ea5b125e8e67ef678132079" +checksum = "af5a45c069f2536df8e77133a618b11b796d3c5f260147f2ed016c6f95932710" dependencies = [ "genco", "xshell", @@ -4848,9 +4848,9 @@ dependencies = [ [[package]] name = "cairo-lang-test-utils" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3345dea097afbd49d145a4a3325d2ceefb399f389d40cd6d05d6316a7cbf5108" +checksum = "81e9aa3db79b0ab2c63b0f9b2f871bd9c863287a8f60d0861e95d1c9ece31cc3" dependencies = [ "cairo-lang-formatter", "cairo-lang-proc-macros", @@ -4862,9 +4862,9 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.19.2" +version = "2.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41afc716def9a9f1a160d38a1626064363f8d64d225acc3b00c1f877718ec666" +checksum = "2d9626f3dd0207942a7209ddf18de0fc35c0d689335237ef0c321d7c8e2d4a0f" dependencies = [ "hashbrown 0.17.1", "indexmap 2.14.0", diff --git a/Cargo.toml b/Cargo.toml index be988a18b2e..0a305ed6c5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -253,12 +253,12 @@ c-kzg = "2.1.5" cached = "0.44.0" cairo-air = "1.1.0" cairo-felt = "0.9.1" -cairo-lang-casm = "2.19.2" -cairo-lang-runner = "2.19.2" -cairo-lang-sierra = "2.19.2" -cairo-lang-sierra-to-casm = "2.19.2" -cairo-lang-starknet-classes = "2.19.2" -cairo-lang-utils = "2.19.2" +cairo-lang-casm = "2.19.3" +cairo-lang-runner = "2.19.3" +cairo-lang-sierra = "2.19.3" +cairo-lang-sierra-to-casm = "2.19.3" +cairo-lang-starknet-classes = "2.19.3" +cairo-lang-utils = "2.19.3" cairo-native = "0.9.0-rc.7" cairo-program-runner-lib = "1.1.0" cairo-vm = "3.2.0" diff --git a/crates/apollo_infra_utils/src/cairo_compiler_version.txt b/crates/apollo_infra_utils/src/cairo_compiler_version.txt index b87b08b5b01..ff0a62a01a7 100644 --- a/crates/apollo_infra_utils/src/cairo_compiler_version.txt +++ b/crates/apollo_infra_utils/src/cairo_compiler_version.txt @@ -1 +1 @@ -2.19.2 \ No newline at end of file +2.19.3 \ No newline at end of file diff --git a/crates/apollo_integration_tests/resources/proof_flow/proof.bin b/crates/apollo_integration_tests/resources/proof_flow/proof.bin index a49914c9124bc200c6b15cc24f303ed09029d452..b2d148242cb7b6bdb42592a0814f9091579d3b2d 100644 GIT binary patch literal 229672 zcmZ76XE>X07XWZ##7=AyV(+~p_6%Z=Sh14WD-nB^E~>4)6;*9*ElRZ%wOgZBi=vcT zrB#ZyRNwr+zR$Pw+~+yh?|eDWb=}vY1OOzTDg32yp`ZX${NLjv!=$lT#;k0vnMfzU zk_Fzhs~6Wxo)U4*k(W`VV@j5JTPX&O)9?QC9Q}J>8 z=SECE8z#6vWDe(e^G+`N@e!M7r;;a4ex1#Bl%0MJN;QzmW-UOxb)J4&c$wy16JMf3 z;C*%6{)fnypJ`S5bnAD#re zvQ%NB$A_8c%ny>^JRCN!ysoAZ%VNxMSMITw_Mb6@XZb$?MRh8Mt%0AdvJQM02eeB` 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

  • P1V6kaNsBZM_2 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