From fcf8d125502f8796aa64d1e2fcd71e5a33589ef6 Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:58:27 +0300 Subject: [PATCH 001/313] apollo_dashboard: add log query for consensus panels (#9322) --- .../src/sequencer_consensus_context.rs | 4 +- .../resources/dev_grafana.json | 50 +++++++++++++++---- .../apollo_dashboard/src/panels/consensus.rs | 27 ++++++++++ 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs index ad66cc71447..8fb95ec4fe9 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -249,7 +249,7 @@ impl ConsensusContext for SequencerConsensusContext { let stream_id = HeightAndRound(proposal_init.height.0, proposal_init.round); let stream_sender = self.start_stream(stream_id).await; - info!(?proposal_init, ?timeout, %proposal_id, "Building proposal"); + info!(?proposal_init, ?timeout, %proposal_id, "Start building proposal"); let cancel_token = CancellationToken::new(); let cancel_token_clone = cancel_token.clone(); let gas_price_params = GasPriceParams { @@ -693,7 +693,7 @@ impl SequencerConsensusContext { ) { let proposal_id = ProposalId(self.proposal_id); self.proposal_id += 1; - info!(?timeout, %proposal_id, %proposer, round=self.current_round, "Validating proposal."); + info!(?timeout, %proposal_id, %proposer, round=self.current_round, "Start validating proposal"); let cancel_token = CancellationToken::new(); let cancel_token_clone = cancel_token.clone(); diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 55f055976a1..26cf04c1a4e 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -9,7 +9,10 @@ "exprs": [ "consensus_round{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "log_query": "\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } }, { "title": "Write Blob Failure by Reason", @@ -72,7 +75,10 @@ "exprs": [ "consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "log_query": "\"START_HEIGHT: running consensus for height\" OR \"Start building proposal\" OR \"Start validating proposal\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } }, { "title": "Consensus Round", @@ -81,7 +87,10 @@ "exprs": [ "consensus_round{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "log_query": "\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } }, { "title": "Consensus Height Diff From Sync", @@ -110,7 +119,10 @@ "exprs": [ "increase(consensus_decisions_reached_by_consensus{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" ], - "extra_params": {} + "extra_params": { + "log_query": "\"DECISION_REACHED: Decision reached for round\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } }, { "title": "Decisions Reached By Sync", @@ -119,7 +131,10 @@ "exprs": [ "increase(consensus_decisions_reached_by_sync{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" ], - "extra_params": {} + "extra_params": { + "log_query": "\"Decision learned via sync protocol.\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } }, { "title": "Proposal Build: Number of Proposals Started", @@ -147,7 +162,8 @@ "sum by (build_proposal_failure_reason) (increase(consensus_build_proposal_failure{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) > 0" ], "extra_params": { - "log_query": "\"PROPOSAL_FAILED: Proposal failed as proposer\"" + "log_query": "\"PROPOSAL_FAILED: Proposal failed as proposer\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" } }, { @@ -166,7 +182,10 @@ "exprs": [ "increase(consensus_proposals_validated{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" ], - "extra_params": {} + "extra_params": { + "log_query": "\"Validated proposal.\" OR \"PROPOSAL_FAILED\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } }, { "title": "Proposal Validation: Number of Invalid Proposals", @@ -175,7 +194,10 @@ "exprs": [ "increase(consensus_proposals_invalid{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" ], - "extra_params": {} + "extra_params": { + "log_query": "\"Validated proposal.\" OR \"PROPOSAL_FAILED\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } }, { "title": "Proposal Validation: Proposal Failure by Reason", @@ -185,7 +207,8 @@ "sum by (validate_proposal_failure_reason) (increase(consensus_validate_proposal_failure{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) > 0" ], "extra_params": { - "log_query": "\"PROPOSAL_FAILED: Proposal failed as validator\"" + "log_query": "\"PROPOSAL_FAILED: Proposal failed as validator\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" } }, { @@ -195,7 +218,10 @@ "exprs": [ "sum by (timeout_type) (increase(consensus_timeouts{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m]))" ], - "extra_params": {} + "extra_params": { + "log_query": "\"Applying Timeout\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } }, { "title": "L2 Gas Price (GFri)", @@ -263,7 +289,9 @@ "exprs": [ "increase(batcher_preconfirmed_block_written{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" ], - "extra_params": {} + "extra_params": { + "log_query": "\"write_pre_confirmed_block request succeeded.\"" + } } ], "collapsed": true diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index ad0a989e82e..1c43130d825 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -43,6 +43,12 @@ use apollo_state_sync_metrics::metrics::STATE_SYNC_CLASS_MANAGER_MARKER; use crate::dashboard::{Panel, PanelType, Row, Unit, HISTOGRAM_QUANTILES, HISTOGRAM_TIME_RANGE}; +// The key events that are relevant to the consensus panel. +const CONSENSUS_KEY_EVENTS_LOG_QUERY: &str = + "\"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \ + \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \ + \"Broadcasting\""; + fn get_panel_consensus_block_number() -> Panel { Panel::new( "Consensus Height", @@ -50,7 +56,13 @@ fn get_panel_consensus_block_number() -> Panel { vec![CONSENSUS_BLOCK_NUMBER.get_name_with_filter().to_string()], PanelType::Stat, ) + .with_log_query( + "\"START_HEIGHT: running consensus for height\" OR \"Start building proposal\" OR \"Start \ + validating proposal\"", + ) + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + fn get_panel_consensus_block_number_diff_from_sync() -> Panel { Panel::new( "Consensus Height Diff From Sync", @@ -70,6 +82,8 @@ pub(crate) fn get_panel_consensus_round() -> Panel { vec![CONSENSUS_ROUND.get_name_with_filter().to_string()], PanelType::TimeSeries, ) + .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } fn get_panel_consensus_block_time_avg() -> Panel { Panel::new( @@ -90,6 +104,8 @@ fn get_panel_consensus_decisions_reached_by_consensus() -> Panel { )], PanelType::TimeSeries, ) + .with_log_query("DECISION_REACHED: Decision reached for round") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } fn get_panel_consensus_decisions_reached_by_sync() -> Panel { Panel::new( @@ -101,6 +117,8 @@ fn get_panel_consensus_decisions_reached_by_sync() -> Panel { )], PanelType::TimeSeries, ) + .with_log_query("Decision learned via sync protocol.") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } fn get_panel_consensus_proposals_received() -> Panel { Panel::new( @@ -117,6 +135,8 @@ fn get_panel_consensus_proposals_validated() -> Panel { vec![format!("increase({}[10m])", CONSENSUS_PROPOSALS_VALIDATED.get_name_with_filter())], PanelType::TimeSeries, ) + .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } fn get_panel_consensus_proposals_invalid() -> Panel { Panel::new( @@ -125,6 +145,8 @@ fn get_panel_consensus_proposals_invalid() -> Panel { vec![format!("increase({}[10m])", CONSENSUS_PROPOSALS_INVALID.get_name_with_filter())], PanelType::TimeSeries, ) + .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } fn get_panel_validate_proposal_failure() -> Panel { Panel::new( @@ -138,6 +160,7 @@ fn get_panel_validate_proposal_failure() -> Panel { PanelType::Stat, ) .with_log_query("PROPOSAL_FAILED: Proposal failed as validator") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } fn get_panel_consensus_build_proposal_total() -> Panel { Panel::new( @@ -167,6 +190,7 @@ fn get_panel_build_proposal_failure() -> Panel { PanelType::Stat, ) .with_log_query("PROPOSAL_FAILED: Proposal failed as proposer") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } fn get_panel_consensus_timeouts_by_type() -> Panel { Panel::new( @@ -184,6 +208,8 @@ fn get_panel_consensus_timeouts_by_type() -> Panel { )], PanelType::TimeSeries, ) + .with_log_query("Applying Timeout") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } fn get_panel_consensus_l2_gas_price() -> Panel { Panel::new( @@ -318,6 +344,7 @@ fn get_panel_cende_write_preconfirmed_block() -> Panel { vec![format!("increase({}[10m])", PRECONFIRMED_BLOCK_WRITTEN.get_name_with_filter())], PanelType::TimeSeries, ) + .with_log_query("write_pre_confirmed_block request succeeded.") } fn get_panel_consensus_network_events_by_type() -> Panel { From 7520df947d66c5811fe4bc5ac530411ce17e9ce4 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Wed, 17 Sep 2025 16:09:20 +0300 Subject: [PATCH 002/313] apollo_dashboard: align alerts to mainnet (#9317) --- .../resources/dev_grafana_alerts_mainnet.json | 28 +++++++++---------- .../resources/dev_grafana_alerts_testnet.json | 18 ++++++------ .../alert_scenarios/block_production_delay.rs | 8 +++--- .../src/alert_scenarios/mempool_size.rs | 4 +-- .../src/alert_scenarios/preconfirmed.rs | 2 +- .../src/alert_scenarios/tps.rs | 14 ++++++---- .../src/alert_scenarios/transaction_delays.rs | 2 +- 7 files changed, 40 insertions(+), 36 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json index 7d57f24d871..04eaf4fb029 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json @@ -309,8 +309,8 @@ "observer_applicable": "false" }, { - "name": "gateway_add_tx_idle_all_sources", - "title": "Gateway add_tx idle (all sources)", + "name": "gateway_add_tx_idle_p2p_rpc", + "title": "Gateway add_tx idle (p2p+rpc)", "ruleGroup": "gateway", "expr": "sum(increase(gateway_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[120s])) or vector(0)", "conditions": [ @@ -333,7 +333,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p1", + "severity": "p2", "observer_applicable": "false" }, { @@ -501,7 +501,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p1", + "severity": "p2", "observer_applicable": "false" }, { @@ -617,8 +617,8 @@ "observer_applicable": "false" }, { - "name": "mempool_add_tx_idle_all_sources", - "title": "Mempool add_tx idle (all sources)", + "name": "mempool_add_tx_idle_p2p_rpc", + "title": "Mempool add_tx idle (p2p+rpc)", "ruleGroup": "mempool", "expr": "sum(increase(mempool_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[120s])) or vector(0)", "conditions": [ @@ -865,7 +865,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p1", + "severity": "p2", "observer_applicable": "true" }, { @@ -977,7 +977,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p1", + "severity": "p2", "observer_applicable": "true" }, { @@ -1012,12 +1012,12 @@ "name": "consensus_round_above_zero_multiple_times", "title": "Consensus round above zero multiple times", "ruleGroup": "consensus", - "expr": "increase(consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"}[30m])", + "expr": "increase(consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])", "conditions": [ { "evaluator": { "params": [ - 5.0 + 30.0 ], "type": "gt" }, @@ -1313,7 +1313,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p2", + "severity": "p4", "observer_applicable": "false" }, { @@ -1465,7 +1465,7 @@ { "evaluator": { "params": [ - 2000.0 + 10000.0 ], "type": "gt" }, @@ -1481,7 +1481,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p2", + "severity": "p3", "observer_applicable": "false" }, { @@ -1537,7 +1537,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p2", + "severity": "p1", "observer_applicable": "false" }, { diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json index 2451808dcb2..c8b1ff501c1 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json @@ -309,8 +309,8 @@ "observer_applicable": "false" }, { - "name": "gateway_add_tx_idle_all_sources", - "title": "Gateway add_tx idle (all sources)", + "name": "gateway_add_tx_idle_p2p_rpc", + "title": "Gateway add_tx idle (p2p+rpc)", "ruleGroup": "gateway", "expr": "sum(increase(gateway_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[120s])) or vector(0)", "conditions": [ @@ -333,7 +333,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p1", + "severity": "p2", "observer_applicable": "false" }, { @@ -501,7 +501,7 @@ ], "for": "30s", "intervalSec": 30, - "severity": "p1", + "severity": "p2", "observer_applicable": "false" }, { @@ -617,8 +617,8 @@ "observer_applicable": "false" }, { - "name": "mempool_add_tx_idle_all_sources", - "title": "Mempool add_tx idle (all sources)", + "name": "mempool_add_tx_idle_p2p_rpc", + "title": "Mempool add_tx idle (p2p+rpc)", "ruleGroup": "mempool", "expr": "sum(increase(mempool_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[120s])) or vector(0)", "conditions": [ @@ -1096,12 +1096,12 @@ "name": "consensus_round_above_zero_multiple_times", "title": "Consensus round above zero multiple times", "ruleGroup": "consensus", - "expr": "increase(consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"}[30m])", + "expr": "increase(consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])", "conditions": [ { "evaluator": { "params": [ - 5.0 + 30.0 ], "type": "gt" }, @@ -1549,7 +1549,7 @@ { "evaluator": { "params": [ - 2000.0 + 10000.0 ], "type": "gt" }, diff --git a/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs b/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs index 70ebe2a7291..e439c53d1e4 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs @@ -60,10 +60,10 @@ fn get_consensus_round_above_zero_multiple_times( "consensus_round_above_zero_multiple_times", "Consensus round above zero multiple times", AlertGroup::Consensus, - format!("increase({}[30m])", CONSENSUS_ROUND_ABOVE_ZERO.get_name_with_filter()), + format!("increase({}[10m])", CONSENSUS_ROUND_ABOVE_ZERO.get_name_with_filter()), vec![AlertCondition { comparison_op: AlertComparisonOp::GreaterThan, - comparison_value: 5.0, + comparison_value: 30.0, logical_op: AlertLogicalOp::And, }], PENDING_DURATION_DEFAULT, @@ -147,7 +147,7 @@ fn get_consensus_p2p_peer_down( pub(crate) fn get_consensus_p2p_peer_down_vec() -> Vec { vec![ - get_consensus_p2p_peer_down(AlertEnvFiltering::MainnetStyleAlerts, AlertSeverity::Sos), + get_consensus_p2p_peer_down(AlertEnvFiltering::MainnetStyleAlerts, AlertSeverity::Regular), get_consensus_p2p_peer_down( AlertEnvFiltering::TestnetStyleAlerts, AlertSeverity::WorkingHours, @@ -204,7 +204,7 @@ pub(crate) fn get_consensus_block_number_progress_is_slow_vec() -> Vec { vec![ get_consensus_block_number_progress_is_slow( AlertEnvFiltering::MainnetStyleAlerts, - AlertSeverity::Sos, + AlertSeverity::Regular, ), get_consensus_block_number_progress_is_slow( AlertEnvFiltering::TestnetStyleAlerts, diff --git a/crates/apollo_dashboard/src/alert_scenarios/mempool_size.rs b/crates/apollo_dashboard/src/alert_scenarios/mempool_size.rs index 0c14240b554..107efbdad71 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/mempool_size.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/mempool_size.rs @@ -29,7 +29,7 @@ fn get_mempool_pool_size_increase( MEMPOOL_POOL_SIZE.get_name_with_filter().to_string(), vec![AlertCondition { comparison_op: AlertComparisonOp::GreaterThan, - comparison_value: 2000.0, + comparison_value: 10000.0, logical_op: AlertLogicalOp::And, }], PENDING_DURATION_DEFAULT, @@ -44,7 +44,7 @@ pub(crate) fn get_mempool_pool_size_increase_vec() -> Vec { vec![ get_mempool_pool_size_increase( AlertEnvFiltering::MainnetStyleAlerts, - AlertSeverity::Regular, + AlertSeverity::DayOnly, ), get_mempool_pool_size_increase( AlertEnvFiltering::TestnetStyleAlerts, diff --git a/crates/apollo_dashboard/src/alert_scenarios/preconfirmed.rs b/crates/apollo_dashboard/src/alert_scenarios/preconfirmed.rs index 83bc266cfed..4d35e37e030 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/preconfirmed.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/preconfirmed.rs @@ -40,7 +40,7 @@ pub(crate) fn get_preconfirmed_block_not_written_vec() -> Vec { vec![ get_preconfirmed_block_not_written( AlertEnvFiltering::MainnetStyleAlerts, - AlertSeverity::Regular, + AlertSeverity::Sos, ), get_preconfirmed_block_not_written( AlertEnvFiltering::TestnetStyleAlerts, diff --git a/crates/apollo_dashboard/src/alert_scenarios/tps.rs b/crates/apollo_dashboard/src/alert_scenarios/tps.rs index e6297af1907..e5f37411c4b 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/tps.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/tps.rs @@ -27,6 +27,7 @@ fn build_idle_alert( alert_group: AlertGroup, metric_name_with_filter: &str, duration: Duration, + alert_severity: AlertSeverity, ) -> Alert { Alert::new( alert_name, @@ -40,7 +41,7 @@ fn build_idle_alert( }], PENDING_DURATION_DEFAULT, EVALUATION_INTERVAL_SEC_DEFAULT, - AlertSeverity::Sos, + alert_severity, ObserverApplicability::NotApplicable, AlertEnvFiltering::All, ) @@ -53,26 +54,29 @@ pub(crate) fn get_http_server_no_successful_transactions() -> Alert { AlertGroup::HttpServer, &ADDED_TRANSACTIONS_SUCCESS.get_name_with_filter(), Duration::from_secs(30 * SECS_IN_MIN), + AlertSeverity::Regular, ) } pub(crate) fn get_gateway_add_tx_idle() -> Alert { build_idle_alert( - "gateway_add_tx_idle_all_sources", - "Gateway add_tx idle (all sources)", + "gateway_add_tx_idle_p2p_rpc", + "Gateway add_tx idle (p2p+rpc)", AlertGroup::Gateway, &GATEWAY_TRANSACTIONS_RECEIVED.get_name_with_filter(), Duration::from_secs(2 * SECS_IN_MIN), + AlertSeverity::Regular, ) } pub(crate) fn get_mempool_add_tx_idle() -> Alert { build_idle_alert( - "mempool_add_tx_idle_all_sources", - "Mempool add_tx idle (all sources)", + "mempool_add_tx_idle_p2p_rpc", + "Mempool add_tx idle (p2p+rpc)", AlertGroup::Mempool, &MEMPOOL_TRANSACTIONS_RECEIVED.get_name_with_filter(), Duration::from_secs(2 * SECS_IN_MIN), + AlertSeverity::Sos, ) } diff --git a/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs b/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs index 7c47d5daeae..ff51a821d45 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs @@ -122,7 +122,7 @@ pub(crate) fn get_http_server_p95_add_tx_latency_alert_vec() -> Vec { vec![ get_http_server_p95_add_tx_latency_alert( AlertEnvFiltering::MainnetStyleAlerts, - AlertSeverity::Regular, + AlertSeverity::WorkingHours, ), get_http_server_p95_add_tx_latency_alert( AlertEnvFiltering::TestnetStyleAlerts, From 90631c139fcf3fad4634a28cdec44b662c2f25fc Mon Sep 17 00:00:00 2001 From: dorimedini-starkware Date: Wed, 17 Sep 2025 22:24:38 +0300 Subject: [PATCH 003/313] release: upgrade starknet-core (#9357) Signed-off-by: Dori Medini --- Cargo.lock | 184 ++++++------------ Cargo.toml | 2 +- .../tests/gateway_integration_test.rs | 15 +- 3 files changed, 63 insertions(+), 138 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 933d3fd9e7a..bc04a7a1d7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -830,7 +830,7 @@ dependencies = [ "reqwest 0.12.12", "rstest", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -891,7 +891,7 @@ dependencies = [ "reqwest 0.12.12", "serde", "simple_logger", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "thiserror 1.0.69", "tokio", @@ -956,7 +956,7 @@ dependencies = [ "rstest", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "tempfile", "thiserror 1.0.69", @@ -1101,7 +1101,7 @@ dependencies = [ "mockall", "prost", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -1198,7 +1198,7 @@ dependencies = [ "serde", "serde_json", "shared_execution_objects", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -1308,7 +1308,7 @@ dependencies = [ "rstest", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -1368,7 +1368,7 @@ dependencies = [ "rstest", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "thiserror 1.0.69", "tokio", @@ -1394,7 +1394,7 @@ dependencies = [ "rstest", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -1481,7 +1481,7 @@ dependencies = [ "rstest", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "tempfile", @@ -1595,7 +1595,7 @@ dependencies = [ "pretty_assertions", "rstest", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "thiserror 1.0.69", "tokio", @@ -1648,7 +1648,7 @@ dependencies = [ "rand 0.8.5", "rstest", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -1752,7 +1752,7 @@ dependencies = [ "pretty_assertions", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "thiserror 1.0.69", "tokio", @@ -1888,7 +1888,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "static_assertions", "thiserror 1.0.69", @@ -1939,7 +1939,7 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "tempfile", "thiserror 1.0.69", @@ -2002,7 +2002,7 @@ dependencies = [ "serde", "serde_json", "starknet-core", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -2037,7 +2037,7 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "thiserror 1.0.69", "tokio", @@ -2067,7 +2067,7 @@ dependencies = [ "serde_json", "serde_repr", "simple_logger", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -2087,7 +2087,7 @@ dependencies = [ "cairo-vm", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "thiserror 1.0.69", "tokio", @@ -2105,7 +2105,7 @@ dependencies = [ "cairo-lang-starknet-classes", "indexmap 2.9.0", "rstest", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "tokio", ] @@ -2134,7 +2134,7 @@ dependencies = [ "papyrus_common", "rand_chacha 0.3.1", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "tokio", "tracing", @@ -2167,7 +2167,7 @@ dependencies = [ "futures", "mockall", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -2215,7 +2215,7 @@ dependencies = [ "serde", "serde_json", "simple_logger", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "statistical", "tempfile", @@ -2255,7 +2255,7 @@ dependencies = [ "reqwest 0.12.12", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", ] @@ -3197,7 +3197,7 @@ version = "0.15.0-rc.4" dependencies = [ "blake2", "digest 0.10.7", - "starknet-types-core 0.2.1", + "starknet-types-core", ] [[package]] @@ -3266,7 +3266,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -3295,7 +3295,7 @@ dependencies = [ "serde", "serde_json", "starknet-core", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "thiserror 1.0.69", "tokio", @@ -3310,7 +3310,7 @@ dependencies = [ "pretty_assertions", "rstest", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -3736,7 +3736,7 @@ dependencies = [ "rand 0.9.2", "sha2", "smol_str", - "starknet-types-core 0.2.1", + "starknet-types-core", "thiserror 2.0.12", ] @@ -3790,7 +3790,7 @@ dependencies = [ "serde_json", "sha3", "smol_str", - "starknet-types-core 0.2.1", + "starknet-types-core", "thiserror 2.0.12", ] @@ -3867,7 +3867,7 @@ dependencies = [ "itertools 0.14.0", "num-bigint 0.4.6", "num-traits", - "starknet-types-core 0.2.1", + "starknet-types-core", "thiserror 2.0.12", ] @@ -3908,7 +3908,7 @@ dependencies = [ "serde", "serde_json", "smol_str", - "starknet-types-core 0.2.1", + "starknet-types-core", "thiserror 2.0.12", "typetag", ] @@ -3932,7 +3932,7 @@ dependencies = [ "serde_json", "sha3", "smol_str", - "starknet-types-core 0.2.1", + "starknet-types-core", "thiserror 2.0.12", ] @@ -3989,7 +3989,7 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", ] [[package]] @@ -4067,8 +4067,8 @@ dependencies = [ "serde", "serde_json", "sha2", - "starknet-curve 0.6.0", - "starknet-types-core 0.2.1", + "starknet-curve", + "starknet-types-core", "stats_alloc", "tempfile", "thiserror 2.0.12", @@ -4103,8 +4103,8 @@ dependencies = [ "serde_json", "sha2", "sha3", - "starknet-crypto 0.8.1", - "starknet-types-core 0.2.1", + "starknet-crypto", + "starknet-types-core", "thiserror 2.0.12", "zip", ] @@ -7714,25 +7714,13 @@ dependencies = [ "rustversion", ] -[[package]] -name = "lambdaworks-crypto" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc2a4da0d9e52ccfe6306801a112e81a8fc0c76aa3e4449fefeda7fef72bb34" -dependencies = [ - "lambdaworks-math 0.10.0", - "serde", - "sha2", - "sha3", -] - [[package]] name = "lambdaworks-crypto" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce8f59622ed408c318c9b5eca17f1a1154159e3738b5c4d5a22a0dd3700c906" dependencies = [ - "lambdaworks-math 0.12.0", + "lambdaworks-math", "rand 0.8.5", "rand_chacha 0.3.1", "serde", @@ -7740,16 +7728,6 @@ dependencies = [ "sha3", ] -[[package]] -name = "lambdaworks-math" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1bd2632acbd9957afc5aeec07ad39f078ae38656654043bf16e046fa2730e23" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "lambdaworks-math" version = "0.12.0" @@ -8481,7 +8459,7 @@ dependencies = [ "blockifier_test_utils", "papyrus_base_layer", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", ] @@ -8812,7 +8790,7 @@ dependencies = [ "pyo3-log", "serde_json", "shared_execution_objects", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "tempfile", "thiserror 1.0.69", @@ -9360,7 +9338,7 @@ dependencies = [ "mockall", "pretty_assertions", "serde", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "tar", "tempfile", @@ -9383,7 +9361,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", ] @@ -11821,7 +11799,7 @@ dependencies = [ name = "sizeof_internal" version = "0.15.0-rc.4" dependencies = [ - "starknet-types-core 0.2.1", + "starknet-types-core", ] [[package]] @@ -11980,9 +11958,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "starknet-core" -version = "0.12.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37abf0af45a3b866dd108880ace9949ae7830f6830adb8963024302ae9e82c24" +checksum = "efb7212226769766c1c7d79b70f9242ffbd213290a41604ecc7e78faa0ed0deb" dependencies = [ "base64 0.21.7", "crypto-bigint", @@ -11997,8 +11975,8 @@ dependencies = [ "serde_with", "sha3", "starknet-core-derive", - "starknet-crypto 0.7.4", - "starknet-types-core 0.1.8", + "starknet-crypto", + "starknet-types-core", ] [[package]] @@ -12012,25 +11990,6 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "starknet-crypto" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039a3bad70806b494c9e6b21c5238a6c8a373d66a26071859deb0ccca6f93634" -dependencies = [ - "crypto-bigint", - "hex", - "hmac", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "rfc6979", - "sha2", - "starknet-curve 0.5.1", - "starknet-types-core 0.1.8", - "zeroize", -] - [[package]] name = "starknet-crypto" version = "0.8.1" @@ -12045,43 +12004,18 @@ dependencies = [ "num-traits", "rfc6979", "sha2", - "starknet-curve 0.6.0", - "starknet-types-core 0.2.1", + "starknet-curve", + "starknet-types-core", "zeroize", ] -[[package]] -name = "starknet-curve" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcde6bd74269b8161948190ace6cf069ef20ac6e79cd2ba09b320efa7500b6de" -dependencies = [ - "starknet-types-core 0.1.8", -] - [[package]] name = "starknet-curve" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22c898ae81b6409532374cf237f1bd752d068b96c6ad500af9ebbd0d9bb712f6" dependencies = [ - "starknet-types-core 0.2.1", -] - -[[package]] -name = "starknet-types-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4037bcb26ce7c508448d221e570d075196fd4f6912ae6380981098937af9522a" -dependencies = [ - "lambdaworks-crypto 0.10.0", - "lambdaworks-math 0.10.0", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "serde", - "size-of", - "zeroize", + "starknet-types-core", ] [[package]] @@ -12092,8 +12026,8 @@ checksum = "c043ab183b1cb1daab10d592719d27f283e7ef7e7ac8accd243b4e70b4e1c0d8" dependencies = [ "blake2", "digest 0.10.7", - "lambdaworks-crypto 0.12.0", - "lambdaworks-math 0.12.0", + "lambdaworks-crypto", + "lambdaworks-math", "lazy_static", "num-bigint 0.4.6", "num-integer", @@ -12132,8 +12066,8 @@ dependencies = [ "serde_json", "sha3", "size-of", - "starknet-crypto 0.8.1", - "starknet-types-core 0.2.1", + "starknet-crypto", + "starknet-types-core", "strum 0.25.0", "strum_macros 0.25.3", "thiserror 1.0.69", @@ -12148,7 +12082,7 @@ dependencies = [ "pretty_assertions", "rstest", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "starknet_patricia", "starknet_patricia_storage", @@ -12179,7 +12113,7 @@ dependencies = [ "serde", "serde_json", "serde_repr", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "starknet_committer", "starknet_os", @@ -12230,7 +12164,7 @@ dependencies = [ "sha2", "sha3", "shared_execution_objects", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "starknet_committer", "starknet_patricia", @@ -12253,7 +12187,7 @@ dependencies = [ "rstest", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_patricia_storage", "strum 0.25.0", "strum_macros 0.25.3", @@ -12269,7 +12203,7 @@ dependencies = [ "hex", "serde", "serde_json", - "starknet-types-core 0.2.1", + "starknet-types-core", "starknet_api", "thiserror 1.0.69", ] diff --git a/Cargo.toml b/Cargo.toml index 284619e2a0f..f4db0ee56ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -295,7 +295,7 @@ simple_logger = "4.0.0" size-of = "0.1.5" sizeof_internal = { path = "crates/sizeof/sizeof_internal" } socket2 = "0.5.8" -starknet-core = "0.12.1" +starknet-core = "0.16.0" starknet-crypto = "0.8.1" starknet-types-core = "0.2.1" starknet_api = { path = "crates/starknet_api", version = "0.15.0-rc.4" } diff --git a/crates/apollo_rpc/tests/gateway_integration_test.rs b/crates/apollo_rpc/tests/gateway_integration_test.rs index 5569b0db8f2..db42f29cd8d 100644 --- a/crates/apollo_rpc/tests/gateway_integration_test.rs +++ b/crates/apollo_rpc/tests/gateway_integration_test.rs @@ -106,24 +106,15 @@ async fn test_gw_integration_testnet() { &TransactionOptions::default(), ) .unwrap(); - // TODO(Dori): Remove useless qualification and conversion once `starknet_core::types::Felt` is - // the same type as `starknet_types_core::felt::Felt` (currently `starknet_types_core` is used - // with two different versions). let signature = ecdsa_sign( - &starknet_core::types::Felt::from_hex(&env::var("SENDER_PRIVATE_KEY").expect( + &Felt::from_hex(&env::var("SENDER_PRIVATE_KEY").expect( "Sender private key must be given in SENDER_PRIVATE_KEY environment variable.", )) .unwrap(), - &starknet_core::types::Felt::from_bytes_be(&hash.0.to_bytes_be()), + &hash.0, ) .unwrap(); - invoke_tx.signature = TransactionSignature( - vec![ - Felt::from_bytes_be(&signature.r.to_bytes_be()), - Felt::from_bytes_be(&signature.s.to_bytes_be()), - ] - .into(), - ); + invoke_tx.signature = TransactionSignature(vec![signature.r, signature.s].into()); let invoke_res = client .request::( From 6549923eeac3779ae726cf407175145f5b9d0494 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Wed, 17 Sep 2025 22:28:04 +0300 Subject: [PATCH 004/313] apollo_l1_provider: validate_height panics instead of returning error to caller (#9356) * apollo_l1_provider: validate_height panics instead of returning error to caller * apollo_l1_provider: fix CI --- crates/apollo_l1_provider/src/l1_provider.rs | 27 ++++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_provider.rs b/crates/apollo_l1_provider/src/l1_provider.rs index 1d7fd689d28..37ba0c1b4e9 100644 --- a/crates/apollo_l1_provider/src/l1_provider.rs +++ b/crates/apollo_l1_provider/src/l1_provider.rs @@ -55,7 +55,7 @@ impl L1Provider { return Err(L1ProviderError::Uninitialized); } - self.validate_height(height)?; + self.validate_height(height); info!("Starting block at height: {height}"); self.state = state.into(); self.tx_manager.start_block(); @@ -87,7 +87,7 @@ impl L1Provider { return Err(L1ProviderError::Uninitialized); } - self.validate_height(height)?; + self.validate_height(height); match self.state { ProviderState::Propose => { @@ -122,7 +122,7 @@ impl L1Provider { return Err(L1ProviderError::Uninitialized); } - self.validate_height(height)?; + self.validate_height(height); match self.state { ProviderState::Validate => { Ok(self.tx_manager.validate_tx(tx_hash, self.clock.unix_now())) @@ -161,7 +161,7 @@ impl L1Provider { return self.bootstrap(committed_txs, height); } - self.validate_height(height)?; + self.validate_height(height); self.apply_commit_block(committed_txs, rejected_txs); self.state = self.state.transition_to_pending(); @@ -249,14 +249,19 @@ impl L1Provider { }) } - fn validate_height(&mut self, height: BlockNumber) -> L1ProviderResult<()> { - if height != self.current_height { - return Err(L1ProviderError::UnexpectedHeight { - expected_height: self.current_height, - got: height, - }); + fn validate_height(&mut self, height: BlockNumber) { + if height > self.current_height { + // TODO(shahak): Add a way to move to bootstrap mode from any point and move to + // bootstrap here instead of panicking. + panic!( + "Batcher surpassed l1 provider. Panicking in order to restart the provider and \ + bootstrap again. l1 provider height: {}, batcher height: {}", + self.current_height, height + ); + } + if height < self.current_height { + panic!("Unexpected height: expected >= {}, got {}", self.current_height, height); } - Ok(()) } fn apply_commit_block( From f8acf6a1e8ab03587aa35500ba2bbfe17c9777ef Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Thu, 18 Sep 2025 08:17:42 +0300 Subject: [PATCH 005/313] apollo_dashboard: use Panel::from_hist across histogram panels (#9350) --- .../resources/dev_grafana.json | 6 +-- crates/apollo_dashboard/src/dashboard.rs | 18 +++++--- .../apollo_dashboard/src/panels/consensus.rs | 17 ++------ crates/apollo_dashboard/src/panels/gateway.rs | 41 +++++++------------ .../src/panels/http_server.rs | 15 ++----- crates/apollo_dashboard/src/panels/mempool.rs | 28 +++---------- .../src/panels/mempool_p2p.rs | 6 ++- .../src/panels/sierra_compiler.rs | 13 +----- crates/apollo_dashboard/src/panels/storage.rs | 28 +++---------- 9 files changed, 54 insertions(+), 118 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 26cf04c1a4e..6bbb1958873 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -580,7 +580,7 @@ "extra_params": {} }, { - "title": "gateway_validate_stateful_tx_storage_micros", + "title": "Gateway Validate Stateful Tx Storage Micros", "description": "Total time spent in storage operations in micros during stateful tx validation", "type": "timeseries", "exprs": [ @@ -590,7 +590,7 @@ "extra_params": {} }, { - "title": "gateway_validate_stateful_tx_storage_operations", + "title": "Gateway Validate Stateful Tx Storage Operations", "description": "Total number of storage operations during stateful tx validation", "type": "timeseries", "exprs": [ @@ -1129,7 +1129,7 @@ "extra_params": {} }, { - "title": "apollo_mempool_p2p_broadcasted_transaction_batch_size", + "title": "Mempool P2p Broadcasted Transaction Batch Size", "description": "The number of transactions in batches broadcast by the mempool p2p component", "type": "timeseries", "exprs": [ diff --git a/crates/apollo_dashboard/src/dashboard.rs b/crates/apollo_dashboard/src/dashboard.rs index 7cf1458a074..ae6ceeef850 100644 --- a/crates/apollo_dashboard/src/dashboard.rs +++ b/crates/apollo_dashboard/src/dashboard.rs @@ -308,10 +308,14 @@ impl Panel { ) } - pub(crate) fn from_hist(metric: &MetricHistogram, panel_type: PanelType) -> Self { + pub(crate) fn from_hist( + metric: &MetricHistogram, + name: impl ToString, + description: impl ToString, + ) -> Self { Self::new( - metric.get_name(), - metric.get_description(), + name.to_string(), + description.to_string(), HISTOGRAM_QUANTILES .iter() .map(|q| { @@ -322,7 +326,7 @@ impl Panel { ) }) .collect(), - panel_type, + PanelType::TimeSeries, ) } } @@ -346,7 +350,11 @@ impl From<&LocalClientMetrics> for UnlabeledPanels { impl From<&RemoteClientMetrics> for UnlabeledPanels { fn from(metrics: &RemoteClientMetrics) -> Self { - Self(vec![Panel::from_hist(metrics.get_attempts_metric(), PanelType::TimeSeries)]) + Self(vec![Panel::from_hist( + metrics.get_attempts_metric(), + metrics.get_attempts_metric().get_name(), + metrics.get_attempts_metric().get_description(), + )]) } } diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 1c43130d825..678cc9df161 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -41,7 +41,7 @@ use apollo_network::network_manager::metrics::{ }; use apollo_state_sync_metrics::metrics::STATE_SYNC_CLASS_MANAGER_MARKER; -use crate::dashboard::{Panel, PanelType, Row, Unit, HISTOGRAM_QUANTILES, HISTOGRAM_TIME_RANGE}; +use crate::dashboard::{Panel, PanelType, Row, Unit}; // The key events that are relevant to the consensus panel. const CONSENSUS_KEY_EVENTS_LOG_QUERY: &str = @@ -289,21 +289,10 @@ fn get_panel_cende_last_prepared_blob_block_number() -> Panel { .with_log_query("Blob for block number") } fn get_panel_cende_write_prev_height_blob_latency() -> Panel { - Panel::new( + Panel::from_hist( + &CENDE_WRITE_PREV_HEIGHT_BLOB_LATENCY, "Write Blob Latency", "The time it takes to write the blob to Cende", - // TODO(Dafna): add an helper function to generate a vector of histogram expressions, to be - // used everywhere - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - CENDE_WRITE_PREV_HEIGHT_BLOB_LATENCY.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } diff --git a/crates/apollo_dashboard/src/panels/gateway.rs b/crates/apollo_dashboard/src/panels/gateway.rs index c01181d3986..7c066dab821 100644 --- a/crates/apollo_dashboard/src/panels/gateway.rs +++ b/crates/apollo_dashboard/src/panels/gateway.rs @@ -12,7 +12,7 @@ use apollo_gateway::metrics::{ LABEL_NAME_TX_TYPE as GATEWAY_LABEL_NAME_TX_TYPE, }; -use crate::dashboard::{Panel, PanelType, Row, Unit, HISTOGRAM_QUANTILES, HISTOGRAM_TIME_RANGE}; +use crate::dashboard::{Panel, PanelType, Row, Unit}; fn get_panel_gateway_transactions_received_by_type() -> Panel { Panel::new( @@ -55,38 +55,19 @@ fn get_panel_gateway_transactions_received_rate() -> Panel { } fn get_panel_gateway_add_tx_latency() -> Panel { - // TODO(Asmaa): refactor Panel::from_hist to accept custom name and description parameters. - Panel::new( + Panel::from_hist( + &GATEWAY_ADD_TX_LATENCY, "Add Tx Latency", "The time it takes the gateway to add a transaction to the mempool", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - GATEWAY_ADD_TX_LATENCY.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } fn get_panel_gateway_validate_tx_latency() -> Panel { - Panel::new( + Panel::from_hist( + &GATEWAY_VALIDATE_TX_LATENCY, "Validate Tx Latency", "The time it takes to validate a transaction", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - GATEWAY_VALIDATE_TX_LATENCY.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } @@ -135,11 +116,19 @@ fn get_panel_gateway_transactions_sent_to_mempool() -> Panel { } fn get_panel_gateway_validate_stateful_tx_storage_micros() -> Panel { - Panel::from_hist(&GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_MICROS, PanelType::TimeSeries) + Panel::from_hist( + &GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_MICROS, + "Gateway Validate Stateful Tx Storage Micros", + "Total time spent in storage operations in micros during stateful tx validation", + ) } fn get_panel_gateway_validate_stateful_tx_storage_operations() -> Panel { - Panel::from_hist(&GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_OPERATIONS, PanelType::TimeSeries) + Panel::from_hist( + &GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_OPERATIONS, + "Gateway Validate Stateful Tx Storage Operations", + "Total number of storage operations during stateful tx validation", + ) } pub(crate) fn get_gateway_row() -> Row { diff --git a/crates/apollo_dashboard/src/panels/http_server.rs b/crates/apollo_dashboard/src/panels/http_server.rs index 84bd07b42ae..ccb35b1c4a7 100644 --- a/crates/apollo_dashboard/src/panels/http_server.rs +++ b/crates/apollo_dashboard/src/panels/http_server.rs @@ -7,7 +7,7 @@ use apollo_http_server::metrics::{ HTTP_SERVER_ADD_TX_LATENCY, }; -use crate::dashboard::{Panel, PanelType, Row, Unit, HISTOGRAM_QUANTILES, HISTOGRAM_TIME_RANGE}; +use crate::dashboard::{Panel, PanelType, Row, Unit}; fn get_panel_total_transactions_received() -> Panel { Panel::new( @@ -42,19 +42,10 @@ pub(crate) fn get_panel_http_server_transactions_received_rate() -> Panel { ) } fn get_panel_http_add_tx_latency() -> Panel { - Panel::new( + Panel::from_hist( + &HTTP_SERVER_ADD_TX_LATENCY, "HTTP Server Add Tx Latency", "The time it takes to add a transaction to the HTTP Server", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - HTTP_SERVER_ADD_TX_LATENCY.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } diff --git a/crates/apollo_dashboard/src/panels/mempool.rs b/crates/apollo_dashboard/src/panels/mempool.rs index 3e8e86a217a..3ea6e6a9323 100644 --- a/crates/apollo_dashboard/src/panels/mempool.rs +++ b/crates/apollo_dashboard/src/panels/mempool.rs @@ -12,7 +12,7 @@ use apollo_mempool::metrics::{ TRANSACTION_TIME_SPENT_UNTIL_COMMITTED, }; -use crate::dashboard::{Panel, PanelType, Row, Unit, HISTOGRAM_QUANTILES, HISTOGRAM_TIME_RANGE}; +use crate::dashboard::{Panel, PanelType, Row, Unit}; fn get_panel_mempool_transactions_received_rate() -> Panel { Panel::new( @@ -88,36 +88,18 @@ fn get_panel_mempool_delayed_declares_size() -> Panel { ) } fn get_panel_mempool_transaction_time_spent_until_batched() -> Panel { - Panel::new( + Panel::from_hist( + &TRANSACTION_TIME_SPENT_UNTIL_BATCHED, "Transaction Time Spent in Mempool Until Batched", "The time a transaction spends in the mempool until it is batched (5m window)", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - TRANSACTION_TIME_SPENT_UNTIL_BATCHED.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } fn get_panel_mempool_transaction_time_spent_until_committed() -> Panel { - Panel::new( + Panel::from_hist( + &TRANSACTION_TIME_SPENT_UNTIL_COMMITTED, "Transaction Time Spent in Mempool Until Committed", "The time a transaction spends in the mempool until it is committed (5m window)", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - TRANSACTION_TIME_SPENT_UNTIL_COMMITTED.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } diff --git a/crates/apollo_dashboard/src/panels/mempool_p2p.rs b/crates/apollo_dashboard/src/panels/mempool_p2p.rs index 5509abbd2df..6ae032e3f63 100644 --- a/crates/apollo_dashboard/src/panels/mempool_p2p.rs +++ b/crates/apollo_dashboard/src/panels/mempool_p2p.rs @@ -26,7 +26,11 @@ fn get_panel_mempool_p2p_num_received_messages() -> Panel { } fn get_panel_mempool_p2p_broadcasted_batch_size() -> Panel { - Panel::from_hist(&MEMPOOL_P2P_BROADCASTED_BATCH_SIZE, PanelType::TimeSeries) + Panel::from_hist( + &MEMPOOL_P2P_BROADCASTED_BATCH_SIZE, + "Mempool P2p Broadcasted Transaction Batch Size", + "The number of transactions in batches broadcast by the mempool p2p component", + ) } fn get_panel_mempool_p2p_network_events_by_type() -> Panel { diff --git a/crates/apollo_dashboard/src/panels/sierra_compiler.rs b/crates/apollo_dashboard/src/panels/sierra_compiler.rs index 8fcaa240c09..89df690b4f3 100644 --- a/crates/apollo_dashboard/src/panels/sierra_compiler.rs +++ b/crates/apollo_dashboard/src/panels/sierra_compiler.rs @@ -4,19 +4,10 @@ use apollo_compile_to_casm::metrics::COMPILATION_DURATION; use crate::dashboard::{Panel, PanelType, Row, Unit, HISTOGRAM_QUANTILES, HISTOGRAM_TIME_RANGE}; fn get_panel_compilation_duration() -> Panel { - Panel::new( + Panel::from_hist( + &COMPILATION_DURATION, "Compile to Casm Compilation Duration", "Server-side compilation of Sierra to Casm duration", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - COMPILATION_DURATION.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } diff --git a/crates/apollo_dashboard/src/panels/storage.rs b/crates/apollo_dashboard/src/panels/storage.rs index b42140ceadd..01adf2369c1 100644 --- a/crates/apollo_dashboard/src/panels/storage.rs +++ b/crates/apollo_dashboard/src/panels/storage.rs @@ -6,39 +6,21 @@ use apollo_storage::metrics::{ SYNC_STORAGE_OPEN_READ_TRANSACTIONS, }; -use crate::dashboard::{Panel, PanelType, Row, Unit, HISTOGRAM_QUANTILES, HISTOGRAM_TIME_RANGE}; +use crate::dashboard::{Panel, PanelType, Row, Unit}; fn get_storage_append_thin_state_diff_latency() -> Panel { - Panel::new( + Panel::from_hist( + &STORAGE_APPEND_THIN_STATE_DIFF_LATENCY, "Append Thin State Diff Latency", "Latency to append thin state diff in storage", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - STORAGE_APPEND_THIN_STATE_DIFF_LATENCY.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } fn get_storage_commit_latency() -> Panel { - Panel::new( + Panel::from_hist( + &STORAGE_COMMIT_LATENCY, "Storage Commit Latency", "Latency to commit changes in storage", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le) (rate({}[{HISTOGRAM_TIME_RANGE}])))", - STORAGE_COMMIT_LATENCY.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::Seconds) } From ecb802966f7f942f1e94a1fd5437d7beeb24c857 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Thu, 18 Sep 2025 08:50:53 +0300 Subject: [PATCH 006/313] apollo_dashboard: update storage usage metric to report seconds (#9360) --- crates/apollo_dashboard/resources/dev_grafana.json | 12 +++++++----- crates/apollo_dashboard/src/panels/gateway.rs | 13 +++++++------ crates/apollo_gateway/src/metrics.rs | 4 ++-- crates/apollo_gateway/src/sync_state_reader.rs | 8 +++++--- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 6bbb1958873..e3f9f44353d 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -580,14 +580,16 @@ "extra_params": {} }, { - "title": "Gateway Validate Stateful Tx Storage Micros", - "description": "Total time spent in storage operations in micros during stateful tx validation", + "title": "Gateway Validate Stateful Tx Storage Access Time", + "description": "Total time spent in storage operations during stateful tx validation", "type": "timeseries", "exprs": [ - "histogram_quantile(0.50, sum by (le) (rate(gateway_validate_stateful_tx_storage_micros_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))", - "histogram_quantile(0.95, sum by (le) (rate(gateway_validate_stateful_tx_storage_micros_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))" + "histogram_quantile(0.50, sum by (le) (rate(gateway_validate_stateful_tx_storage_time_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))", + "histogram_quantile(0.95, sum by (le) (rate(gateway_validate_stateful_tx_storage_time_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))" ], - "extra_params": {} + "extra_params": { + "unit": "s" + } }, { "title": "Gateway Validate Stateful Tx Storage Operations", diff --git a/crates/apollo_dashboard/src/panels/gateway.rs b/crates/apollo_dashboard/src/panels/gateway.rs index 7c066dab821..cce1bc006b9 100644 --- a/crates/apollo_dashboard/src/panels/gateway.rs +++ b/crates/apollo_dashboard/src/panels/gateway.rs @@ -4,8 +4,8 @@ use apollo_gateway::metrics::{ GATEWAY_TRANSACTIONS_FAILED, GATEWAY_TRANSACTIONS_RECEIVED, GATEWAY_TRANSACTIONS_SENT_TO_MEMPOOL, - GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_MICROS, GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_OPERATIONS, + GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_TIME, GATEWAY_VALIDATE_TX_LATENCY, LABEL_NAME_ADD_TX_FAILURE_REASON, LABEL_NAME_SOURCE, @@ -115,12 +115,13 @@ fn get_panel_gateway_transactions_sent_to_mempool() -> Panel { ) } -fn get_panel_gateway_validate_stateful_tx_storage_micros() -> Panel { +fn get_panel_gateway_validate_stateful_tx_storage_time() -> Panel { Panel::from_hist( - &GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_MICROS, - "Gateway Validate Stateful Tx Storage Micros", - "Total time spent in storage operations in micros during stateful tx validation", + &GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_TIME, + "Gateway Validate Stateful Tx Storage Access Time", + "Total time spent in storage operations during stateful tx validation", ) + .with_unit(Unit::Seconds) } fn get_panel_gateway_validate_stateful_tx_storage_operations() -> Panel { @@ -143,7 +144,7 @@ pub(crate) fn get_gateway_row() -> Row { get_panel_gateway_transactions_failure_rate(), get_panel_gateway_add_tx_failure_by_reason(), get_panel_gateway_transactions_sent_to_mempool(), - get_panel_gateway_validate_stateful_tx_storage_micros(), + get_panel_gateway_validate_stateful_tx_storage_time(), get_panel_gateway_validate_stateful_tx_storage_operations(), ], ) diff --git a/crates/apollo_gateway/src/metrics.rs b/crates/apollo_gateway/src/metrics.rs index 127bc992971..5d21145b8de 100644 --- a/crates/apollo_gateway/src/metrics.rs +++ b/crates/apollo_gateway/src/metrics.rs @@ -45,7 +45,7 @@ define_metrics!( LabeledMetricCounter { GATEWAY_ADD_TX_FAILURE, "gateway_add_tx_failure", "Counter of add_tx failures by reason", init = 0 , labels = ADD_TX_FAILURE_LABELS}, MetricHistogram { GATEWAY_ADD_TX_LATENCY, "gateway_add_tx_latency", "Latency of gateway add_tx function in secs" }, MetricHistogram { GATEWAY_VALIDATE_TX_LATENCY, "gateway_validate_tx_latency", "Latency of gateway validate function in secs" }, - MetricHistogram { GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_MICROS, "gateway_validate_stateful_tx_storage_micros", "Total time spent in storage operations in micros during stateful tx validation" }, + MetricHistogram { GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_TIME, "gateway_validate_stateful_tx_storage_time", "Total time spent in storage operations in secs during stateful tx validation" }, MetricHistogram { GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_OPERATIONS, "gateway_validate_stateful_tx_storage_operations", "Total number of storage operations during stateful tx validation"}, }, ); @@ -247,6 +247,6 @@ pub(crate) fn register_metrics() { GATEWAY_ADD_TX_FAILURE.register(); GATEWAY_ADD_TX_LATENCY.register(); GATEWAY_VALIDATE_TX_LATENCY.register(); - GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_MICROS.register(); + GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_TIME.register(); GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_OPERATIONS.register(); } diff --git a/crates/apollo_gateway/src/sync_state_reader.rs b/crates/apollo_gateway/src/sync_state_reader.rs index 6616f99a285..01f95161a48 100644 --- a/crates/apollo_gateway/src/sync_state_reader.rs +++ b/crates/apollo_gateway/src/sync_state_reader.rs @@ -25,8 +25,8 @@ use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; use crate::metrics::{ - GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_MICROS, GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_OPERATIONS, + GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_TIME, }; use crate::state_reader::{MempoolStateReader, StateReaderFactory}; @@ -267,8 +267,10 @@ impl Drop for SharedStateSyncClientMetricWrapper { GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_OPERATIONS .record(self.num_storage_operations.load(Ordering::Relaxed).into_f64()); - GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_MICROS - .record(self.total_time_storage_operations_micros.load(Ordering::Relaxed).into_f64()); + GATEWAY_VALIDATE_STATEFUL_TX_STORAGE_TIME.record( + self.total_time_storage_operations_micros.load(Ordering::Relaxed).into_f64() + / 1_000_000.0, // Histogram buckets are best fit in seconds + ); } } From 02e367435f7e7fb37afea0b5a8d77d313ae3a20b Mon Sep 17 00:00:00 2001 From: ron-starkware Date: Thu, 18 Sep 2025 09:29:25 +0300 Subject: [PATCH 007/313] apollo_dashboard: Add log queries to batcher panels (#9332) --- .../apollo_dashboard/resources/dev_grafana.json | 16 ++++++++++++---- crates/apollo_dashboard/src/panels/batcher.rs | 3 +++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index e3f9f44353d..706694f7f60 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -41,7 +41,9 @@ "exprs": [ "rate(batcher_batched_transactions{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1m])" ], - "extra_params": {} + "extra_params": { + "log_query": "\"BATCHER_FIN_VALIDATOR\"" + } }, { "title": "Sync Diff From Central", @@ -305,7 +307,9 @@ "exprs": [ "batcher_storage_height{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "log_query": "\"Committing block at height\"" + } }, { "title": "Batched Transactions Rate (TPS)", @@ -314,7 +318,9 @@ "exprs": [ "rate(batcher_batched_transactions{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1m])" ], - "extra_params": {} + "extra_params": { + "log_query": "\"BATCHER_FIN_VALIDATOR\"" + } }, { "title": "Proposal Build: Deferred TXs", @@ -381,7 +387,9 @@ "exprs": [ "consensus_num_txs_in_proposal{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "log_query": "\"BATCHER_FIN_PROPOSER\"" + } } ], "collapsed": true diff --git a/crates/apollo_dashboard/src/panels/batcher.rs b/crates/apollo_dashboard/src/panels/batcher.rs index 81231ef031d..846747da277 100644 --- a/crates/apollo_dashboard/src/panels/batcher.rs +++ b/crates/apollo_dashboard/src/panels/batcher.rs @@ -42,6 +42,7 @@ fn get_panel_storage_height() -> Panel { vec![STORAGE_HEIGHT.get_name_with_filter().to_string()], PanelType::Stat, ) + .with_log_query("Committing block at height") } fn get_panel_rejection_reverted_ratio() -> Panel { @@ -77,6 +78,7 @@ pub(crate) fn get_panel_batched_transactions_rate() -> Panel { vec![format!("rate({}[1m])", BATCHED_TRANSACTIONS.get_name_with_filter())], PanelType::TimeSeries, ) + .with_log_query("BATCHER_FIN_VALIDATOR") } fn get_panel_block_close_reasons() -> Panel { @@ -109,6 +111,7 @@ fn get_panel_num_txs_in_proposal() -> Panel { vec![CONSENSUS_NUM_TXS_IN_PROPOSAL.get_name_with_filter().to_string()], PanelType::TimeSeries, ) + .with_log_query("BATCHER_FIN_PROPOSER") } pub(crate) fn get_batcher_row() -> Row { From 6b3a0746745f546b2be4da7734e015c2a833c0be Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 18 Sep 2025 09:40:17 +0300 Subject: [PATCH 008/313] apollo_l1_provider: panic if pending and calling get_txs or validate (#9365) --- crates/apollo_l1_provider/src/l1_provider.rs | 16 ++++++++++++---- .../apollo_l1_provider/src/l1_provider_tests.rs | 14 ++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_provider.rs b/crates/apollo_l1_provider/src/l1_provider.rs index 37ba0c1b4e9..539ba2e1247 100644 --- a/crates/apollo_l1_provider/src/l1_provider.rs +++ b/crates/apollo_l1_provider/src/l1_provider.rs @@ -103,9 +103,13 @@ impl L1Provider { ); Ok(txs) } - ProviderState::Pending | ProviderState::Bootstrap(_) => { - Err(L1ProviderError::OutOfSessionGetTransactions) + ProviderState::Pending => { + panic!( + "get_txs called while in pending state. Panicking in order to restart the \ + provider and bootstrap again." + ); } + ProviderState::Bootstrap(_) => Err(L1ProviderError::OutOfSessionGetTransactions), ProviderState::Validate => Err(L1ProviderError::GetTransactionConsensusBug), } } @@ -128,9 +132,13 @@ impl L1Provider { Ok(self.tx_manager.validate_tx(tx_hash, self.clock.unix_now())) } ProviderState::Propose => Err(L1ProviderError::ValidateTransactionConsensusBug), - ProviderState::Pending | ProviderState::Bootstrap(_) => { - Err(L1ProviderError::OutOfSessionValidate) + ProviderState::Pending => { + panic!( + "validate called while in pending state. Panicking in order to restart the \ + provider and bootstrap again." + ); } + ProviderState::Bootstrap(_) => Err(L1ProviderError::OutOfSessionValidate), } } diff --git a/crates/apollo_l1_provider/src/l1_provider_tests.rs b/crates/apollo_l1_provider/src/l1_provider_tests.rs index 65014144051..f1f3645ada0 100644 --- a/crates/apollo_l1_provider/src/l1_provider_tests.rs +++ b/crates/apollo_l1_provider/src/l1_provider_tests.rs @@ -1,3 +1,4 @@ +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::sync::Arc; use std::time::Duration; @@ -210,7 +211,7 @@ fn process_events_committed_txs() { } #[test] -fn pending_state_errors() { +fn pending_state_panics() { // Setup. let mut l1_provider = L1ProviderContentBuilder::new() .with_state(ProviderState::Pending) @@ -218,14 +219,11 @@ fn pending_state_errors() { .build_into_l1_provider(); // Test. - assert_matches!( - l1_provider.get_txs(1, BlockNumber(0)).unwrap_err(), - L1ProviderError::OutOfSessionGetTransactions - ); + assert!(catch_unwind(AssertUnwindSafe(|| { l1_provider.get_txs(1, BlockNumber(0)) })).is_err()); - assert_matches!( - l1_provider.validate(tx_hash!(1), BlockNumber(0)).unwrap_err(), - L1ProviderError::OutOfSessionValidate + assert!( + catch_unwind(AssertUnwindSafe(|| { l1_provider.validate(tx_hash!(1), BlockNumber(0)) })) + .is_err() ); } From fb68dfd8c418db40f2f9148bedb54801f0f0f2a6 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 18 Sep 2025 11:16:59 +0300 Subject: [PATCH 009/313] apollo_l1_provider: improve logging in cases of base layer problems (#9367) Co-authored-by: Guy Nir --- crates/apollo_l1_provider/src/l1_scraper.rs | 28 +++++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper.rs b/crates/apollo_l1_provider/src/l1_scraper.rs index bcd0948c02c..2afffb95061 100644 --- a/crates/apollo_l1_provider/src/l1_scraper.rs +++ b/crates/apollo_l1_provider/src/l1_scraper.rs @@ -193,6 +193,7 @@ impl L1Scraper { async fn assert_no_l1_reorgs(&self) -> L1ScraperResult<(), B> { let last_processed_l1_block_number = self.last_l1_block_processed.number; + let last_processed_l1_block_hash = self.last_l1_block_processed.hash; let last_block_processed_fresh = self .base_layer .l1_block_at(last_processed_l1_block_number) @@ -203,13 +204,13 @@ impl L1Scraper { L1_MESSAGE_SCRAPER_REORG_DETECTED.increment(1); return Err(L1ScraperError::L1ReorgDetected { reason: format!( - "Last processed L1 block with number {last_processed_l1_block_number} no \ - longer exists." + "Last processed L1 block with number {last_processed_l1_block_number} and \ + hash {last_processed_l1_block_hash} no longer exists." ), }); }; - if last_block_processed_fresh.hash != self.last_l1_block_processed.hash { + if last_block_processed_fresh.hash != last_processed_l1_block_hash { L1_MESSAGE_SCRAPER_REORG_DETECTED.increment(1); return Err(L1ScraperError::L1ReorgDetected { reason: format!( @@ -217,7 +218,7 @@ impl L1Scraper { hash stored, {}", last_block_processed_fresh.hash, last_processed_l1_block_number, - self.last_l1_block_processed.hash, + last_processed_l1_block_hash ), }); } @@ -236,7 +237,7 @@ pub async fn fetch_start_block( .await .map_err(L1ScraperError::BaseLayerError)?; - let latest_l1_block = match latest_l1_block_number { + let latest_l1_block_number = match latest_l1_block_number { Some(latest_l1_block_number) => Ok(latest_l1_block_number), None => Err(L1ScraperError::finality_too_high(finality, base_layer).await), }?; @@ -246,16 +247,18 @@ pub async fn fetch_start_block( // Add 50% safety margin. let safe_blocks_in_interval = blocks_in_interval + blocks_in_interval / 2; - let l1_block_number_rewind = latest_l1_block.saturating_sub(safe_blocks_in_interval); + let l1_block_number_rewind = latest_l1_block_number.saturating_sub(safe_blocks_in_interval); let block_reference_rewind = base_layer .l1_block_at(l1_block_number_rewind) .await .map_err(L1ScraperError::BaseLayerError)? - .expect( - "Rewound L1 block number is between 0 and the verified latest L1 block, so should \ - exist", - ); + .unwrap_or_else(|| { + panic!( + "Rewound L1 block number is between 0 and the verified latest L1 block \ + {latest_l1_block_number}, so should exist", + ) + }); Ok(block_reference_rewind) } @@ -325,7 +328,10 @@ impl SerializeConfig for L1ScraperConfig { pub enum L1ScraperError { #[error("Base layer error: {0}")] BaseLayerError(T::Error), - #[error("Finality too high: {finality:?} > {latest_l1_block_no_finality:?}")] + #[error( + "Could not find block number. Finality {finality:?}, latest block: \ + {latest_l1_block_no_finality:?}" + )] FinalityTooHigh { finality: u64, latest_l1_block_no_finality: L1BlockNumber }, #[error("Failed to calculate hash: {0}")] HashCalculationError(StarknetApiError), From 53d05642f01c2c6fb05d932b8c559d392b6389fe Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Thu, 18 Sep 2025 12:22:04 +0300 Subject: [PATCH 010/313] apollo_l1_provider: scraper log which tx hashes are added/cancelled (#9306) --- crates/apollo_l1_provider/src/l1_scraper.rs | 24 ++++++++++++++++--- .../src/ethereum_base_layer_contract.rs | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper.rs b/crates/apollo_l1_provider/src/l1_scraper.rs index 2afffb95061..354539d3adf 100644 --- a/crates/apollo_l1_provider/src/l1_scraper.rs +++ b/crates/apollo_l1_provider/src/l1_scraper.rs @@ -121,7 +121,7 @@ impl L1Scraper { .await; let l1_events = scraping_result.map_err(L1ScraperError::BaseLayerError)?; - // Used for debug. + // Used for debug. Collect the L1 tx hashes and L1 block timestamps. let l1_messages_info = l1_events .iter() .filter_map(|event| match event { @@ -132,6 +132,7 @@ impl L1Scraper { }) .collect::>(); + // Convert L1 events into Starknet provider events. Includes calculating the L2 tx hash. let events = l1_events .into_iter() .map(|event| { @@ -140,7 +141,7 @@ impl L1Scraper { }) .collect::, _>>()?; - // Used for debug. + // Used for debug. Collect the L2 tx hashes. let l2_hashes = events.iter().filter_map(|event| match event { Event::L1HandlerTransaction { l1_handler_tx, .. } => Some(l1_handler_tx.tx_hash), _ => None, @@ -148,7 +149,7 @@ impl L1Scraper { let formatted_pairs = zip_eq(l1_messages_info, l2_hashes) .map(|((l1_hash, timestamp), l2_hash)| { - format!("L1 hash: {l1_hash:?}, L1 timestamp: {timestamp}, L2 hash: {l2_hash}") + format!("L1 tx hash: {l1_hash:?}, L1 timestamp: {timestamp}, L2 tx hash: {l2_hash}") }) .collect::>(); if formatted_pairs.is_empty() { @@ -156,6 +157,23 @@ impl L1Scraper { } else { debug!("Got Messages to L2: {formatted_pairs:?}"); } + + // Debug: log cancellation started events. + let cancellation_started_events = events + .iter() + .filter_map(|event| match event { + Event::TransactionCancellationStarted { tx_hash, .. } => Some(*tx_hash), + _ => None, + }) + .collect::>(); + let formatted_cancellation_started_events = cancellation_started_events + .iter() + .map(|tx_hash| format!("Cancel tx with L2 hash: {tx_hash}")); + if cancellation_started_events.is_empty() { + debug_every_n!(100, "Got Cancellation Started Events: []"); + } else { + debug!("Got Cancellation Started Events: {formatted_cancellation_started_events:?}"); + } Ok((latest_l1_block, events)) } diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index c393f948a94..d54d961a844 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -169,7 +169,7 @@ impl BaseLayerContract for EthereumBaseLayerContract { // Debugging. let hashes: Vec<_> = matching_logs.iter().filter_map(|log| log.transaction_hash).collect(); - debug!("Got events in {:?}, transaction hashes: {:?}", block_range, hashes); + debug!("Got events in {:?}, L1 tx hashes: {:?}", block_range, hashes); let block_header_futures = matching_logs.into_iter().map(|log| { let block_number = log.block_number.unwrap(); From d71359d4427bf23b4d2e13888b5068a6d2a83174 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Thu, 18 Sep 2025 12:25:47 +0300 Subject: [PATCH 011/313] apollo_dashboard: change grafana overview row (#9366) --- .../resources/dev_grafana.json | 28 +++++++++---------- .../src/dashboard_definitions.rs | 8 +++--- .../apollo_dashboard/src/panels/consensus.rs | 4 +-- crates/apollo_dashboard/src/panels/gateway.rs | 4 +-- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 706694f7f60..da23d4c6e5c 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -3,26 +3,26 @@ "Overview": { "panels": [ { - "title": "Consensus Round", - "description": "The round the node is currently working on", + "title": "Average Block Time", + "description": "Average block time (10m window)", "type": "timeseries", "exprs": [ - "consensus_round{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + "1 / rate(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" ], "extra_params": { - "log_query": "\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"", - "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + "unit": "s" } }, { - "title": "Write Blob Failure by Reason", - "description": "The number of failed blob writes to Cende (10m window)", + "title": "Consensus Round", + "description": "The round the node is currently working on", "type": "timeseries", "exprs": [ - "sum by (cende_write_failure_reason) (increase(cende_write_blob_failure{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m]))" + "consensus_round{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], "extra_params": { - "log_query": "\"CENDE_FAILURE\"" + "log_query": "\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" } }, { @@ -55,15 +55,13 @@ "extra_params": {} }, { - "title": "Transaction Failure Rate by Type", - "description": "The rate of failed transactions vs received transactions by type (over the selected time range)", + "title": "Transactions Failed by Reason", + "description": "The number of transactions failed by reason (over the selected time range)", "type": "stat", "exprs": [ - "(sum by (tx_type) (increase(gateway_transactions_failed{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) / sum by (tx_type) (increase(gateway_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])))" + "sum by (add_tx_failure_reason) (increase(gateway_add_tx_failure{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) > 0" ], - "extra_params": { - "unit": "percentunit" - } + "extra_params": {} } ], "collapsed": false diff --git a/crates/apollo_dashboard/src/dashboard_definitions.rs b/crates/apollo_dashboard/src/dashboard_definitions.rs index 1a64c8dc518..69f5ee5a396 100644 --- a/crates/apollo_dashboard/src/dashboard_definitions.rs +++ b/crates/apollo_dashboard/src/dashboard_definitions.rs @@ -16,10 +16,10 @@ use crate::panels::consensus::{ get_cende_row, get_consensus_p2p_row, get_consensus_row, - get_panel_cende_write_blob_failure, + get_panel_consensus_block_time_avg, get_panel_consensus_round, }; -use crate::panels::gateway::{get_gateway_row, get_panel_gateway_transactions_failure_rate}; +use crate::panels::gateway::{get_gateway_row, get_panel_gateway_add_tx_failure_by_reason}; use crate::panels::http_server::{ get_http_server_row, get_panel_http_server_transactions_received_rate, @@ -48,12 +48,12 @@ fn get_overview_row() -> Row { Row::new( "Overview", vec![ + get_panel_consensus_block_time_avg(), get_panel_consensus_round(), - get_panel_cende_write_blob_failure(), get_panel_http_server_transactions_received_rate(), get_panel_batched_transactions_rate(), get_panel_state_sync_diff_from_central(), - get_panel_gateway_transactions_failure_rate(), + get_panel_gateway_add_tx_failure_by_reason(), ], ) .expand() diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 678cc9df161..8e1c507cee6 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -85,7 +85,7 @@ pub(crate) fn get_panel_consensus_round() -> Panel { .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } -fn get_panel_consensus_block_time_avg() -> Panel { +pub(crate) fn get_panel_consensus_block_time_avg() -> Panel { Panel::new( "Average Block Time", "Average block time (10m window)", @@ -312,7 +312,7 @@ fn get_panel_cende_write_blob_success() -> Panel { ) .with_log_query(query_expression) } -pub(crate) fn get_panel_cende_write_blob_failure() -> Panel { +fn get_panel_cende_write_blob_failure() -> Panel { Panel::new( "Write Blob Failure by Reason", "The number of failed blob writes to Cende (10m window)", diff --git a/crates/apollo_dashboard/src/panels/gateway.rs b/crates/apollo_dashboard/src/panels/gateway.rs index cce1bc006b9..d7ccdeb8164 100644 --- a/crates/apollo_dashboard/src/panels/gateway.rs +++ b/crates/apollo_dashboard/src/panels/gateway.rs @@ -72,7 +72,7 @@ fn get_panel_gateway_validate_tx_latency() -> Panel { .with_unit(Unit::Seconds) } -fn get_panel_gateway_add_tx_failure_by_reason() -> Panel { +pub(crate) fn get_panel_gateway_add_tx_failure_by_reason() -> Panel { Panel::new( "Transactions Failed by Reason", "The number of transactions failed by reason (over the selected time range)", @@ -85,7 +85,7 @@ fn get_panel_gateway_add_tx_failure_by_reason() -> Panel { ) } -pub(crate) fn get_panel_gateway_transactions_failure_rate() -> Panel { +fn get_panel_gateway_transactions_failure_rate() -> Panel { Panel::new( "Transaction Failure Rate by Type", "The rate of failed transactions vs received transactions by type (over the selected time \ From c63c1e5b55d16c9ee8789b19e883b7b378648ab4 Mon Sep 17 00:00:00 2001 From: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> Date: Thu, 18 Sep 2025 12:42:09 +0300 Subject: [PATCH 012/313] apollo_consensus: Add a metric that counts the number of times round has increased (#9374) --- crates/apollo_consensus/src/metrics.rs | 2 ++ crates/apollo_consensus/src/state_machine.rs | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/apollo_consensus/src/metrics.rs b/crates/apollo_consensus/src/metrics.rs index 635b0afab52..546e9b15b98 100644 --- a/crates/apollo_consensus/src/metrics.rs +++ b/crates/apollo_consensus/src/metrics.rs @@ -26,6 +26,7 @@ define_metrics!( MetricCounter { CONSENSUS_INBOUND_STREAM_FINISHED, "consensus_inbound_stream_finished", "The total number of inbound streams finished", init=0 }, // TODO(Matan): remove this metric. MetricCounter { CONSENSUS_ROUND_ABOVE_ZERO, "consensus_round_above_zero", "The number of times the consensus round has increased above zero", init=0 }, + MetricCounter { CONSENSUS_ROUND_ADVANCES, "consensus_round_advances", "The number of times the consensus round has advanced", init=0 }, MetricCounter { CONSENSUS_CONFLICTING_VOTES, "consensus_conflicting_votes", "The number of times consensus has received conflicting votes", init=0 }, LabeledMetricCounter { CONSENSUS_TIMEOUTS, "consensus_timeouts", "The number of times consensus has timed out", init=0, labels = CONSENSUS_TIMEOUT_LABELS }, }, @@ -68,6 +69,7 @@ pub(crate) fn register_metrics() { CONSENSUS_OUTBOUND_STREAM_STARTED.register(); CONSENSUS_OUTBOUND_STREAM_FINISHED.register(); CONSENSUS_ROUND_ABOVE_ZERO.register(); + CONSENSUS_ROUND_ADVANCES.register(); CONSENSUS_CONFLICTING_VOTES.register(); CONSENSUS_TIMEOUTS.register(); } diff --git a/crates/apollo_consensus/src/state_machine.rs b/crates/apollo_consensus/src/state_machine.rs index 35124d85d34..3b414f4cc38 100644 --- a/crates/apollo_consensus/src/state_machine.rs +++ b/crates/apollo_consensus/src/state_machine.rs @@ -18,6 +18,7 @@ use crate::metrics::{ CONSENSUS_NEW_VALUE_LOCKS, CONSENSUS_ROUND, CONSENSUS_ROUND_ABOVE_ZERO, + CONSENSUS_ROUND_ADVANCES, CONSENSUS_TIMEOUTS, LABEL_NAME_TIMEOUT_TYPE, }; @@ -370,9 +371,12 @@ impl StateMachine { LeaderFn: Fn(Round) -> ValidatorId, { CONSENSUS_ROUND.set(round); - // Count how many times consensus advanced above round 0. - if round == 1 { - CONSENSUS_ROUND_ABOVE_ZERO.increment(1); + if round > 0 { + CONSENSUS_ROUND_ADVANCES.increment(1); + // Count how many times consensus advanced above round 0. + if round == 1 { + CONSENSUS_ROUND_ABOVE_ZERO.increment(1); + } } if self.locked_value_round.is_some() { CONSENSUS_HELD_LOCKS.increment(1); From e15752312f9851859032864afeb4b413219577e5 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Thu, 18 Sep 2025 13:04:14 +0300 Subject: [PATCH 013/313] apollo_dashboard: restore consensus round above zero panel (#9377) --- .../resources/dev_grafana.json | 28 +++++++++++++------ .../apollo_dashboard/src/panels/consensus.rs | 19 ++++++++++++- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index da23d4c6e5c..a3f5f918ba9 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -93,25 +93,37 @@ } }, { - "title": "Consensus Height Diff From Sync", - "description": "The difference between the consensus height and the sync height", + "title": "Average Block Time", + "description": "Average block time (10m window)", "type": "timeseries", "exprs": [ - "(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"} - apollo_state_sync_class_manager_marker{cluster=~\"$cluster\", namespace=~\"$namespace\"})" + "1 / rate(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" ], - "extra_params": {} + "extra_params": { + "unit": "s" + } }, { - "title": "Average Block Time", - "description": "Average block time (10m window)", + "title": "Consensus Round Above Zero", + "description": "Occurances where the consensus round was 1, relative to displayed range", "type": "timeseries", "exprs": [ - "1 / rate(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + "consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"} - (consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"} @ start())" ], "extra_params": { - "unit": "s" + "log_query": "\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" } }, + { + "title": "Consensus Height Diff From Sync", + "description": "The difference between the consensus height and the sync height", + "type": "timeseries", + "exprs": [ + "(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"} - apollo_state_sync_class_manager_marker{cluster=~\"$cluster\", namespace=~\"$namespace\"})" + ], + "extra_params": {} + }, { "title": "Decisions Reached By Consensus", "description": "The number of decisions reached by way of consensus (10m window)", diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 8e1c507cee6..ff874ace6a2 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -10,6 +10,7 @@ use apollo_consensus::metrics::{ CONSENSUS_PROPOSALS_RECEIVED, CONSENSUS_PROPOSALS_VALIDATED, CONSENSUS_ROUND, + CONSENSUS_ROUND_ABOVE_ZERO, CONSENSUS_TIMEOUTS, LABEL_NAME_TIMEOUT_TYPE, }; @@ -85,6 +86,21 @@ pub(crate) fn get_panel_consensus_round() -> Panel { .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + +fn get_panel_consensus_round_above_zero() -> Panel { + Panel::new( + "Consensus Round Above Zero", + "Occurances where the consensus round was 1, relative to displayed range", + vec![format!( + "{m} - ({m} @ start())", + m = CONSENSUS_ROUND_ABOVE_ZERO.get_name_with_filter().to_string() + )], + PanelType::TimeSeries, + ) + .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) +} + pub(crate) fn get_panel_consensus_block_time_avg() -> Panel { Panel::new( "Average Block Time", @@ -381,8 +397,9 @@ pub(crate) fn get_consensus_row() -> Row { vec![ get_panel_consensus_block_number(), get_panel_consensus_round(), - get_panel_consensus_block_number_diff_from_sync(), get_panel_consensus_block_time_avg(), + get_panel_consensus_round_above_zero(), + get_panel_consensus_block_number_diff_from_sync(), get_panel_consensus_decisions_reached_by_consensus(), get_panel_consensus_decisions_reached_by_sync(), get_panel_consensus_build_proposal_total(), From d7894f2c872fae2990ea3b6bab01729fb83dc193 Mon Sep 17 00:00:00 2001 From: Idan Shamam <161198342+idan-starkware@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:09:27 +0300 Subject: [PATCH 014/313] deployment: cdk8s fix backend config headers (#9369) --- deployments/sequencer/services/const.py | 1 - 1 file changed, 1 deletion(-) diff --git a/deployments/sequencer/services/const.py b/deployments/sequencer/services/const.py index eb4713c8e9f..0f5e09a3bba 100644 --- a/deployments/sequencer/services/const.py +++ b/deployments/sequencer/services/const.py @@ -40,7 +40,6 @@ class K8SServiceType(str, Enum): BACKEND_CONFIG_HEALTHY_THRESHOLD = 1 BACKEND_CONFIG_UNHEALTHY_THRESHOLD = 10 BACKEND_CONFIG_HEADERS = [ - "X-Client-Region:{client_region}", "X-Client-Region:{client_region}", "X-Client-CityLatLong:{client_city_lat_long}", ] From 7bf9b79b2fa7085f9141271b59e0a2eed54143f1 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:32:01 +0300 Subject: [PATCH 015/313] apollo_batcher: batcher does not panic on l1 provider failures (#9358) --- crates/apollo_batcher/src/batcher.rs | 27 ++++++---- crates/apollo_batcher/src/batcher_test.rs | 52 ++++++++++++------- crates/apollo_batcher/src/metrics.rs | 2 + .../src/transaction_provider.rs | 20 +++++-- crates/apollo_l1_provider_types/src/lib.rs | 1 + 5 files changed, 69 insertions(+), 33 deletions(-) diff --git a/crates/apollo_batcher/src/batcher.rs b/crates/apollo_batcher/src/batcher.rs index 83f6b198b91..925d066c800 100644 --- a/crates/apollo_batcher/src/batcher.rs +++ b/crates/apollo_batcher/src/batcher.rs @@ -63,6 +63,7 @@ use crate::metrics::{ register_metrics, ProposalMetricsHandle, BATCHED_TRANSACTIONS, + BATCHER_L1_PROVIDER_ERRORS, LAST_BATCHED_BLOCK_HEIGHT, LAST_PROPOSED_BLOCK_HEIGHT, LAST_SYNCED_BLOCK_HEIGHT, @@ -220,16 +221,19 @@ impl Batcher { error!("Failed to update gas price in mempool: {}", err); BatcherError::InternalError })?; - self.l1_provider_client + // Ignore errors. If start_block fails, then subsequent calls to l1 provider will fail on + // out of session and l1 provider will restart and bootstrap again. + let _ = self + .l1_provider_client .start_block(SessionState::Propose, propose_block_input.block_info.block_number) .await - .map_err(|err| { + .inspect_err(|err| { error!( "L1 provider is not ready to start proposing block {}: {}. ", propose_block_input.block_info.block_number, err ); - BatcherError::NotReady - })?; + BATCHER_L1_PROVIDER_ERRORS.increment(1); + }); let tx_provider = ProposeTransactionProvider::new( self.mempool_client.clone(), @@ -305,16 +309,19 @@ impl Batcher { validate_block_input.retrospective_block_hash, )?; - self.l1_provider_client + // Ignore errors. If start_block fails, then subsequent calls to l1 provider will fail on + // out of session and l1 provider will restart and bootstrap again. + let _ = self + .l1_provider_client .start_block(SessionState::Validate, validate_block_input.block_info.block_number) .await - .map_err(|err| { + .inspect_err(|err| { error!( "L1 provider is not ready to start validating block {}: {}. ", validate_block_input.block_info.block_number, err ); - BatcherError::NotReady - })?; + BATCHER_L1_PROVIDER_ERRORS.increment(1); + }); // A channel to send the transactions to include in the block being validated. let (input_tx_sender, input_tx_receiver) = @@ -678,9 +685,7 @@ impl Batcher { ); } } - // Rollback the state diff in the storage. - self.storage_writer.revert_block(height); - return Err(BatcherError::InternalError); + BATCHER_L1_PROVIDER_ERRORS.increment(1); } // Notify the mempool of the new block. diff --git a/crates/apollo_batcher/src/batcher_test.rs b/crates/apollo_batcher/src/batcher_test.rs index 7e8590e5098..8cccf1bd3a3 100644 --- a/crates/apollo_batcher/src/batcher_test.rs +++ b/crates/apollo_batcher/src/batcher_test.rs @@ -415,8 +415,20 @@ async fn no_active_height() { #[case::proposer(true)] #[case::validator(false)] #[tokio::test] -async fn l1_handler_provider_not_ready(#[case] proposer: bool) { +async fn ignore_l1_handler_provider_not_ready(#[case] proposer: bool) { let mut deps = MockDependencies::default(); + if proposer { + mock_create_builder_for_propose_block( + &mut deps.block_builder_factory, + vec![], + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + } else { + mock_create_builder_for_validate_block( + &mut deps.block_builder_factory, + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + } deps.l1_provider_client.expect_start_block().returning(|_, _| { // The heights are not important for the test. let err = L1ProviderError::UnexpectedHeight { @@ -429,15 +441,9 @@ async fn l1_handler_provider_not_ready(#[case] proposer: bool) { assert_eq!(batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await, Ok(())); if proposer { - assert_eq!( - batcher.propose_block(propose_block_input(PROPOSAL_ID)).await, - Err(BatcherError::NotReady) - ); + batcher.propose_block(propose_block_input(PROPOSAL_ID)).await.unwrap(); } else { - assert_eq!( - batcher.validate_block(validate_block_input(PROPOSAL_ID)).await, - Err(BatcherError::NotReady) - ); + batcher.validate_block(validate_block_input(PROPOSAL_ID)).await.unwrap(); } } @@ -817,15 +823,23 @@ async fn proposal_startup_failure_allows_new_proposals() { Ok(BlockExecutionArtifacts::create_for_testing()), ); let mut l1_provider_client = MockL1ProviderClient::new(); - let error = L1ProviderClientError::L1ProviderError(L1ProviderError::UnexpectedHeight { - expected_height: BlockNumber(1), - got: BlockNumber(0), - }); - l1_provider_client.expect_start_block().once().return_once(|_, _| Err(error)); - l1_provider_client.expect_start_block().once().return_once(|_, _| Ok(())); + l1_provider_client.expect_start_block().returning(|_, _| Ok(())); + let mut mempool_client = MockMempoolClient::new(); + let expected_gas_price = + propose_block_input(PROPOSAL_ID).block_info.gas_prices.strk_gas_prices.l2_gas_price.get(); + let error = MempoolClientError::ClientError(ClientError::CommunicationFailure( + "Mempool not ready".to_string(), + )); + mempool_client + .expect_update_gas_price() + .with(eq(expected_gas_price)) + .return_once(|_| Err(error)); + mempool_client.expect_update_gas_price().with(eq(expected_gas_price)).return_once(|_| Ok(())); + mempool_client.expect_commit_block().with(eq(CommitBlockArgs::default())).returning(|_| Ok(())); let mut batcher = create_batcher(MockDependencies { block_builder_factory, l1_provider_client, + mempool_client, ..Default::default() }) .await; @@ -835,7 +849,7 @@ async fn proposal_startup_failure_allows_new_proposals() { batcher .propose_block(propose_block_input(ProposalId(0))) .await - .expect_err("Expected to fail because of the first L1ProviderClient error"); + .expect_err("Expected to fail because of the first MempoolClient error"); batcher.validate_block(validate_block_input(ProposalId(1))).await.expect("Expected to succeed"); batcher @@ -1161,7 +1175,7 @@ fn validate_batcher_config_failure() { }) )] #[tokio::test] -async fn decision_reached_return_error_when_l1_commit_block_fails( +async fn decision_reached_return_success_when_l1_commit_block_fails( #[case] l1_error: L1ProviderClientError, ) { let mut mock_dependencies = MockDependencies::default(); @@ -1176,7 +1190,7 @@ async fn decision_reached_return_error_when_l1_commit_block_fails( mock_dependencies.storage_writer.expect_commit_proposal().returning(|_, _| Ok(())); - mock_dependencies.storage_writer.expect_revert_block().returning(|_| ()); + mock_dependencies.mempool_client.expect_commit_block().returning(|_| Ok(())); mock_create_builder_for_propose_block( &mut mock_dependencies.block_builder_factory, @@ -1185,5 +1199,5 @@ async fn decision_reached_return_error_when_l1_commit_block_fails( ); let result = batcher_propose_and_commit_block(mock_dependencies).await; - assert!(result.is_err()); + assert!(result.is_ok()); } diff --git a/crates/apollo_batcher/src/metrics.rs b/crates/apollo_batcher/src/metrics.rs index 2c6fb8b5466..8dae8580534 100644 --- a/crates/apollo_batcher/src/metrics.rs +++ b/crates/apollo_batcher/src/metrics.rs @@ -43,6 +43,7 @@ define_metrics!( MetricCounter { REVERTED_TRANSACTIONS, "batcher_reverted_transactions", "Counter of reverted transactions across all forks", init = 0 }, MetricCounter { SYNCED_TRANSACTIONS, "batcher_synced_transactions", "Counter of synced transactions", init = 0 }, + MetricCounter { BATCHER_L1_PROVIDER_ERRORS, "batcher_l1_provider_errors", "Counter of L1 provider errors", init = 0 }, MetricCounter { PRECONFIRMED_BLOCK_WRITTEN, "batcher_preconfirmed_block_written", "Counter of preconfirmed blocks written to storage", init = 0 }, // Block close reason LabeledMetricCounter { BLOCK_CLOSE_REASON, "batcher_block_close_reason", "Number of blocks closed by reason", init = 0 , labels = BLOCK_CLOSE_REASON_LABELS}, @@ -83,6 +84,7 @@ pub fn register_metrics(storage_height: BlockNumber) { REVERTED_TRANSACTIONS.register(); SYNCED_TRANSACTIONS.register(); + BATCHER_L1_PROVIDER_ERRORS.register(); PRECONFIRMED_BLOCK_WRITTEN.register(); BLOCK_CLOSE_REASON.register(); diff --git a/crates/apollo_batcher/src/transaction_provider.rs b/crates/apollo_batcher/src/transaction_provider.rs index fb34f8324cf..7276230daa2 100644 --- a/crates/apollo_batcher/src/transaction_provider.rs +++ b/crates/apollo_batcher/src/transaction_provider.rs @@ -16,6 +16,8 @@ use starknet_api::consensus_transaction::InternalConsensusTransaction; use starknet_api::transaction::TransactionHash; use thiserror::Error; +use crate::metrics::BATCHER_L1_PROVIDER_ERRORS; + type TransactionProviderResult = Result; #[derive(Clone, Debug, Error)] @@ -89,7 +91,11 @@ impl ProposeTransactionProvider { Ok(self .l1_provider_client .get_txs(n_txs, self.height) - .await? + .await + .inspect_err(|_err| { + BATCHER_L1_PROVIDER_ERRORS.increment(1); + }) + .unwrap_or_default() .into_iter() .map(InternalConsensusTransaction::L1Handler) .collect()) @@ -177,8 +183,16 @@ impl TransactionProvider for ValidateTransactionProvider { for tx in &buffer { if let InternalConsensusTransaction::L1Handler(tx) = tx { - let l1_validation_status = - self.l1_provider_client.validate(tx.tx_hash, self.height).await?; + let l1_validation_status = self + .l1_provider_client + .validate(tx.tx_hash, self.height) + .await + .inspect_err(|_err| { + BATCHER_L1_PROVIDER_ERRORS.increment(1); + }) + .unwrap_or(L1ValidationStatus::Invalid( + L1InvalidValidationStatus::L1ProviderError, + )); if let L1ValidationStatus::Invalid(validation_status) = l1_validation_status { return Err(TransactionProviderError::L1HandlerTransactionValidationFailed { tx_hash: tx.tx_hash, diff --git a/crates/apollo_l1_provider_types/src/lib.rs b/crates/apollo_l1_provider_types/src/lib.rs index 23b804caa8b..578c8de9dde 100644 --- a/crates/apollo_l1_provider_types/src/lib.rs +++ b/crates/apollo_l1_provider_types/src/lib.rs @@ -54,6 +54,7 @@ pub enum InvalidValidationStatus { ConsumedOnL1, // This tx is either never been seen or was seen, consumed, and deleted. NotFound, + L1ProviderError, } #[derive(Serialize, Deserialize, Clone, AsRefStr, EnumDiscriminants)] From ab43f2f8467251f6e7abca4e1f14386b0bf035d9 Mon Sep 17 00:00:00 2001 From: ron-starkware Date: Thu, 18 Sep 2025 14:45:12 +0300 Subject: [PATCH 016/313] apollo_dashboard: Add legend to Class Sizes panel in Grafana (#9339) --- .../resources/dev_grafana.json | 6 ++- crates/apollo_dashboard/src/dashboard.rs | 38 +++++++++++++++++-- .../src/panels/sierra_compiler.rs | 16 ++------ crates/apollo_metrics/src/metrics.rs | 5 +++ 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index a3f5f918ba9..82230031e28 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -939,7 +939,11 @@ "histogram_quantile(0.95, sum by (le, class_object_type) (rate(class_manager_class_sizes_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))" ], "extra_params": { - "unit": "decmbytes" + "unit": "decmbytes", + "legends": [ + "0.50 {{class_object_type}}", + "0.95 {{class_object_type}}" + ] } } ], diff --git a/crates/apollo_dashboard/src/dashboard.rs b/crates/apollo_dashboard/src/dashboard.rs index ae6ceeef850..28fb85992c7 100644 --- a/crates/apollo_dashboard/src/dashboard.rs +++ b/crates/apollo_dashboard/src/dashboard.rs @@ -308,10 +308,11 @@ impl Panel { ) } - pub(crate) fn from_hist( - metric: &MetricHistogram, + fn from_hist_helper( + metric_name_with_filter: impl AsRef, name: impl ToString, description: impl ToString, + sum_by: impl AsRef, ) -> Self { Self::new( name.to_string(), @@ -320,15 +321,44 @@ impl Panel { .iter() .map(|q| { format!( - "histogram_quantile({q:.2}, sum by (le) \ + "histogram_quantile({q:.2}, sum by ({}) \ (rate({}[{HISTOGRAM_TIME_RANGE}])))", - metric.get_name_with_filter(), + sum_by.as_ref(), + metric_name_with_filter.as_ref(), ) }) .collect(), PanelType::TimeSeries, ) } + + pub(crate) fn from_hist( + metric: &MetricHistogram, + name: impl ToString, + description: impl ToString, + ) -> Self { + Self::from_hist_helper(metric.get_name_with_filter(), name, description, "le") + } + + pub(crate) fn from_labeled_hist( + metric: &LabeledMetricHistogram, + name: impl ToString, + description: impl ToString, + ) -> Self { + let group_label = metric.get_label_name(); + Self::from_hist_helper( + metric.get_name_with_filter(), + name, + description, + format!("le, {}", group_label), + ) + .with_legends( + HISTOGRAM_QUANTILES + .iter() + .map(|q| format!("{:.2} {{{{{}}}}}", q, group_label)) + .collect(), + ) + } } #[allow(dead_code)] // TODO(Ron): use in panels diff --git a/crates/apollo_dashboard/src/panels/sierra_compiler.rs b/crates/apollo_dashboard/src/panels/sierra_compiler.rs index 89df690b4f3..10d28e82879 100644 --- a/crates/apollo_dashboard/src/panels/sierra_compiler.rs +++ b/crates/apollo_dashboard/src/panels/sierra_compiler.rs @@ -1,7 +1,7 @@ use apollo_class_manager::metrics::{CLASS_SIZES, N_CLASSES}; use apollo_compile_to_casm::metrics::COMPILATION_DURATION; -use crate::dashboard::{Panel, PanelType, Row, Unit, HISTOGRAM_QUANTILES, HISTOGRAM_TIME_RANGE}; +use crate::dashboard::{Panel, PanelType, Row, Unit}; fn get_panel_compilation_duration() -> Panel { Panel::from_hist( @@ -24,20 +24,10 @@ fn get_panel_n_classes() -> Panel { ) } fn get_panel_class_sizes() -> Panel { - Panel::new( + Panel::from_labeled_hist( + &CLASS_SIZES, "Class Sizes", "Size of the classes in bytes, labeled by type (sierra, casm, deprecated casm)", - HISTOGRAM_QUANTILES - .iter() - .map(|q| { - format!( - "histogram_quantile({q:.2}, sum by (le, class_object_type) \ - (rate({}[{HISTOGRAM_TIME_RANGE}])))", - CLASS_SIZES.get_name_with_filter(), - ) - }) - .collect(), - PanelType::TimeSeries, ) .with_unit(Unit::MB) } diff --git a/crates/apollo_metrics/src/metrics.rs b/crates/apollo_metrics/src/metrics.rs index 6affc51b55e..b6de84e9b06 100644 --- a/crates/apollo_metrics/src/metrics.rs +++ b/crates/apollo_metrics/src/metrics.rs @@ -475,6 +475,11 @@ impl LabeledMetricHistogram { describe_histogram!(self.name, self.description); } + /// Returns the label name used by this labeled histogram. + pub fn get_label_name(&self) -> &'static str { + self.label_permutations[0][0].0 + } + pub fn record(&self, value: T, labels: &[(&'static str, &'static str)]) { histogram!(self.name, labels).record(value.into_f64()); } From 95c7171c483aa4ddb1a7248a233995bd4d730f22 Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Thu, 18 Sep 2025 15:08:29 +0300 Subject: [PATCH 017/313] apollo_l1_provider: improve logging in L1 scraper startup flow (#9373) --- crates/apollo_l1_endpoint_monitor/src/monitor.rs | 15 ++++++++++++--- crates/apollo_l1_provider/src/l1_scraper.rs | 10 ++++++++++ crates/apollo_node/src/components.rs | 3 +-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/crates/apollo_l1_endpoint_monitor/src/monitor.rs b/crates/apollo_l1_endpoint_monitor/src/monitor.rs index d1c34af6058..770433f3c81 100644 --- a/crates/apollo_l1_endpoint_monitor/src/monitor.rs +++ b/crates/apollo_l1_endpoint_monitor/src/monitor.rs @@ -64,8 +64,8 @@ impl L1EndpointMonitor { if self.is_operational(idx).await { warn!( "L1 endpoint {} down; switched to {}", - self.get_node_url(current_l1_endpoint_index), - self.get_node_url(idx) + to_safe_string(self.get_node_url(current_l1_endpoint_index)), + to_safe_string(self.get_node_url(idx)) ); self.current_l1_endpoint_index = idx; @@ -109,7 +109,16 @@ impl L1EndpointMonitor { error!("L1 endpoint {l1_endpoint_url} is not operational: {e}"); false } - Ok(Ok(_)) => { + Ok(Ok(block_number)) => { + // TODO(guyn): remove this once we understand where these low numbers are coming + // from. + if block_number < U64::from(1000) { + warn!( + "L1 endpoint {l1_endpoint_url} is operational, but block number is too \ + low: {block_number}" + ); + } + info_every_n!(1000, "L1 endpoint {l1_endpoint_url} is operational"); true } diff --git a/crates/apollo_l1_provider/src/l1_scraper.rs b/crates/apollo_l1_provider/src/l1_scraper.rs index 354539d3adf..9a771aedf90 100644 --- a/crates/apollo_l1_provider/src/l1_scraper.rs +++ b/crates/apollo_l1_provider/src/l1_scraper.rs @@ -72,6 +72,9 @@ impl L1Scraper { async fn initialize(&mut self) -> L1ScraperResult<(), B> { let (latest_l1_block, events) = self.fetch_events().await?; + debug!("Latest L1 block for initialize: {latest_l1_block:?}"); + debug!("All events scraped during initialize: {events:?}"); + // If this gets too high, send in batches. let initialize_result = self.l1_provider_client.initialize(events).await; handle_client_error(initialize_result)?; @@ -254,6 +257,7 @@ pub async fn fetch_start_block( .latest_l1_block_number(finality) .await .map_err(L1ScraperError::BaseLayerError)?; + debug!("Latest L1 block number: {latest_l1_block_number:?}"); let latest_l1_block_number = match latest_l1_block_number { Some(latest_l1_block_number) => Ok(latest_l1_block_number), @@ -262,10 +266,14 @@ pub async fn fetch_start_block( // Estimate the number of blocks in the interval, to rewind from the latest block. let blocks_in_interval = config.startup_rewind_time_seconds.as_secs() / L1_BLOCK_TIME; + debug!("Blocks in interval: {blocks_in_interval}"); + // Add 50% safety margin. let safe_blocks_in_interval = blocks_in_interval + blocks_in_interval / 2; + debug!("Safe blocks in interval: {safe_blocks_in_interval}"); let l1_block_number_rewind = latest_l1_block_number.saturating_sub(safe_blocks_in_interval); + debug!("L1 block number rewind: {l1_block_number_rewind}"); let block_reference_rewind = base_layer .l1_block_at(l1_block_number_rewind) @@ -277,6 +285,8 @@ pub async fn fetch_start_block( {latest_l1_block_number}, so should exist", ) }); + debug!("Block reference rewind: {block_reference_rewind:?}"); + Ok(block_reference_rewind) } diff --git a/crates/apollo_node/src/components.rs b/crates/apollo_node/src/components.rs index e6f0f216842..2ed4d2074c4 100644 --- a/crates/apollo_node/src/components.rs +++ b/crates/apollo_node/src/components.rs @@ -340,13 +340,12 @@ pub async fn create_node_components( let l1_start_block = fetch_start_block(&base_layer, l1_scraper_config) .await .unwrap_or_else(|err| panic!("Error while initializing the L1 scraper: {err}")); - + debug!("L1 start block: {l1_start_block:?}"); let monitored_base_layer = MonitoredEthereumBaseLayer::new( base_layer, l1_endpoint_monitor_client, base_layer_config.node_url.clone(), ); - Some( L1Scraper::new( l1_scraper_config.clone(), From 8672c1e85f2e13262b8254576d92ec75294741ad Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Thu, 18 Sep 2025 15:28:11 +0300 Subject: [PATCH 018/313] apollo_l1_provider: return error when baselayer returns low values (#9359) --- .../src/l1_gas_price_scraper.rs | 9 +++----- .../src/l1_gas_price_scraper_test.rs | 8 +++---- crates/apollo_l1_provider/src/l1_scraper.rs | 10 +++----- .../src/l1_scraper_tests.rs | 2 +- .../papyrus_base_layer/src/base_layer_test.rs | 10 ++++++-- .../src/ethereum_base_layer_contract.rs | 23 +++++++++++-------- crates/papyrus_base_layer/src/lib.rs | 5 +--- .../src/monitored_base_layer.rs | 5 +--- 8 files changed, 34 insertions(+), 38 deletions(-) diff --git a/crates/apollo_l1_gas_price/src/l1_gas_price_scraper.rs b/crates/apollo_l1_gas_price/src/l1_gas_price_scraper.rs index 1e0d82073ac..55c8def4b70 100644 --- a/crates/apollo_l1_gas_price/src/l1_gas_price_scraper.rs +++ b/crates/apollo_l1_gas_price/src/l1_gas_price_scraper.rs @@ -176,10 +176,8 @@ impl L1GasPriceScraper { &mut self, block_number: &mut L1BlockNumber, ) -> L1GasPriceScraperResult<(), B> { - let Some(last_block_number) = self.latest_l1_block_number().await? else { - // Not enough blocks under current finality. Try again later. - return Ok(()); - }; + let last_block_number = self.latest_l1_block_number().await?; + trace!("Scraping gas prices starting from block {} to {last_block_number}.", *block_number,); info_every_n_sec!( 1, @@ -234,7 +232,7 @@ impl L1GasPriceScraper { Ok(()) } - async fn latest_l1_block_number(&self) -> L1GasPriceScraperResult, B> { + async fn latest_l1_block_number(&self) -> L1GasPriceScraperResult { self.base_layer .latest_l1_block_number(self.config.finality) .await @@ -256,7 +254,6 @@ where let latest = self .latest_l1_block_number() .await - .expect("Failed to get the latest L1 block number at startup") .expect("Failed to get the latest L1 block number at startup"); // If no starting block is provided, the default is to start from diff --git a/crates/apollo_l1_gas_price/src/l1_gas_price_scraper_test.rs b/crates/apollo_l1_gas_price/src/l1_gas_price_scraper_test.rs index c0c756890bf..21bf8ddb32c 100644 --- a/crates/apollo_l1_gas_price/src/l1_gas_price_scraper_test.rs +++ b/crates/apollo_l1_gas_price/src/l1_gas_price_scraper_test.rs @@ -47,7 +47,7 @@ fn setup_scraper( expected_number_of_blocks: usize, ) -> L1GasPriceScraper { let mut mock_contract = MockBaseLayerContract::new(); - mock_contract.expect_latest_l1_block_number().returning(move |_| Ok(Some(end_block))); + mock_contract.expect_latest_l1_block_number().returning(move |_| Ok(end_block)); mock_contract.expect_get_block_header().returning(move |block_number| { if block_number >= end_block { Ok(None) @@ -89,7 +89,7 @@ async fn run_l1_gas_price_scraper_two_blocks() { // Explicitly making the mocks here, so we can customize them for the test. let mut mock_contract = MockBaseLayerContract::new(); // Note the order of the expectation is important! Can only scrape the first blocks first. - mock_contract.expect_latest_l1_block_number().returning(move |_| Ok(Some(END_BLOCK2))); + mock_contract.expect_latest_l1_block_number().returning(move |_| Ok(END_BLOCK2)); mock_contract .expect_get_block_header() .times(usize::try_from(END_BLOCK1 - START_BLOCK + 1).unwrap()) @@ -154,7 +154,7 @@ async fn l1_reorg_gas_price_scraper_error() { // Explicitly making the mocks here, so we can customize them for the test. let mut mock_contract = MockBaseLayerContract::new(); // Note the order of the expectation is important! Can only scrape the first blocks first. - mock_contract.expect_latest_l1_block_number().returning(move |_| Ok(Some(END_BLOCK2))); + mock_contract.expect_latest_l1_block_number().returning(move |_| Ok(END_BLOCK2)); mock_contract .expect_get_block_header() .times(usize::try_from(END_BLOCK1 - START_BLOCK + 1).unwrap()) @@ -234,7 +234,7 @@ async fn l1_short_reorg_gas_price_scraper_is_fine(#[case] finality: u64) { // This expectation just returns the last block number we want (which is end_of_chain-finality). mock_contract .expect_latest_l1_block_number() - .returning(move |finality| Ok(Some(end_of_chain_clone.load(Ordering::SeqCst) - finality))); + .returning(move |finality| Ok(end_of_chain_clone.load(Ordering::SeqCst) - finality)); // This expectation will return the regular chain, or the chain with the reorg (depending on // has_reorg_happened). mock_contract.expect_get_block_header().returning(move |block_number| { diff --git a/crates/apollo_l1_provider/src/l1_scraper.rs b/crates/apollo_l1_provider/src/l1_scraper.rs index 9a771aedf90..0b095545959 100644 --- a/crates/apollo_l1_provider/src/l1_scraper.rs +++ b/crates/apollo_l1_provider/src/l1_scraper.rs @@ -112,6 +112,7 @@ impl L1Scraper { .map_err(L1ScraperError::BaseLayerError)?; let Some(latest_l1_block) = latest_l1_block else { + // TODO(guyn): get rid of finality_too_high, use a better error. return Err( L1ScraperError::finality_too_high(self.config.finality, &self.base_layer).await ); @@ -259,11 +260,6 @@ pub async fn fetch_start_block( .map_err(L1ScraperError::BaseLayerError)?; debug!("Latest L1 block number: {latest_l1_block_number:?}"); - let latest_l1_block_number = match latest_l1_block_number { - Some(latest_l1_block_number) => Ok(latest_l1_block_number), - None => Err(L1ScraperError::finality_too_high(finality, base_layer).await), - }?; - // Estimate the number of blocks in the interval, to rewind from the latest block. let blocks_in_interval = config.startup_rewind_time_seconds.as_secs() / L1_BLOCK_TIME; debug!("Blocks in interval: {blocks_in_interval}"); @@ -392,13 +388,13 @@ impl PartialEq for L1ScraperError { } } +// TODO(guyn): get rid of finality_too_high, use a better error. impl L1ScraperError { pub async fn finality_too_high(finality: u64, base_layer: &B) -> L1ScraperError { let latest_l1_block_number_no_finality = base_layer.latest_l1_block_number(0).await; let latest_l1_block_no_finality = match latest_l1_block_number_no_finality { - Ok(block_number) => block_number - .expect("Latest *L1* block without finality is assumed to always exist."), + Ok(block_number) => block_number, Err(error) => return Self::BaseLayerError(error), }; diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 7b25da0ca46..1ee16afc133 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -577,7 +577,7 @@ async fn provider_crash_should_crash_scraper(mut dummy_base_layer: MockBaseLayer #[fixture] fn dummy_base_layer() -> MockBaseLayerContract { let mut base_layer = MockBaseLayerContract::new(); - base_layer.expect_latest_l1_block_number().return_once(|_| Ok(Some(Default::default()))); + base_layer.expect_latest_l1_block_number().return_once(|_| Ok(Default::default())); base_layer.expect_latest_l1_block().return_once(|_| Ok(Some(Default::default()))); base_layer.expect_events().return_once(|_, _| Ok(Default::default())); base_layer diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index f5cc42d1684..2a73e1a878e 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -14,6 +14,7 @@ use crate::constants::{EventIdentifier, LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER}; use crate::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, EthereumBaseLayerContract, + EthereumBaseLayerError, L1ToL2MessageArgs, Starknet, }; @@ -71,8 +72,13 @@ async fn latest_proved_block_ethereum() { (1000, None), ]; for (scenario, expected) in scenarios { - let latest_block = contract.latest_proved_block(scenario).await.unwrap(); - assert_eq!(latest_block, expected); + let latest_block = contract.latest_proved_block(scenario).await; + match latest_block { + Ok(latest_block) => assert_eq!(latest_block, expected), + Err(e) => { + assert_matches!(e, EthereumBaseLayerError::LatestBlockNumberReturnedTooLow(_, _)) + } + } } } diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index d54d961a844..d8e487bad39 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -144,9 +144,7 @@ impl BaseLayerContract for EthereumBaseLayerContract { &self, finality: u64, ) -> EthereumBaseLayerResult> { - let Some(ethereum_block_number) = self.latest_l1_block_number(finality).await? else { - return Ok(None); - }; + let ethereum_block_number = self.latest_l1_block_number(finality).await?; self.get_proved_block_at(ethereum_block_number).await.map(Some) } @@ -186,13 +184,19 @@ impl BaseLayerContract for EthereumBaseLayerContract { async fn latest_l1_block_number( &self, finality: u64, - ) -> EthereumBaseLayerResult> { + ) -> EthereumBaseLayerResult { let block_number = tokio::time::timeout( self.config.timeout_millis, self.contract.provider().get_block_number(), ) .await??; - Ok(block_number.checked_sub(finality)) + let Some(block_number) = block_number.checked_sub(finality) else { + return Err(EthereumBaseLayerError::LatestBlockNumberReturnedTooLow( + block_number, + finality, + )); + }; + Ok(block_number) } #[instrument(skip(self), err)] @@ -200,11 +204,8 @@ impl BaseLayerContract for EthereumBaseLayerContract { &self, finality: u64, ) -> EthereumBaseLayerResult> { - let Some(block_number) = self.latest_l1_block_number(finality).await? else { - return Ok(None); - }; - - self.l1_block_at(block_number).await + let block_number = self.latest_l1_block_number(finality).await?; + Ok(self.l1_block_at(block_number).await?) } #[instrument(skip(self), err)] @@ -286,6 +287,8 @@ pub enum EthereumBaseLayerError { TypeError(#[from] alloy::sol_types::Error), #[error("{0:?}")] UnhandledL1Event(alloy::primitives::Log), + #[error("Block number is too low: {0}, finality: {1}")] + LatestBlockNumberReturnedTooLow(u64, u64), } impl PartialEq for EthereumBaseLayerError { diff --git a/crates/papyrus_base_layer/src/lib.rs b/crates/papyrus_base_layer/src/lib.rs index 7c76866e61b..4008f9e2fd8 100644 --- a/crates/papyrus_base_layer/src/lib.rs +++ b/crates/papyrus_base_layer/src/lib.rs @@ -66,10 +66,7 @@ pub trait BaseLayerContract { finality: u64, ) -> Result, Self::Error>; - async fn latest_l1_block_number( - &self, - finality: u64, - ) -> Result, Self::Error>; + async fn latest_l1_block_number(&self, finality: u64) -> Result; async fn latest_l1_block(&self, finality: u64) -> Result, Self::Error>; diff --git a/crates/papyrus_base_layer/src/monitored_base_layer.rs b/crates/papyrus_base_layer/src/monitored_base_layer.rs index 5e047eebf13..7c1e1fbf762 100644 --- a/crates/papyrus_base_layer/src/monitored_base_layer.rs +++ b/crates/papyrus_base_layer/src/monitored_base_layer.rs @@ -104,10 +104,7 @@ impl BaseLayerContract for MonitoredBaseLaye .map_err(|err| MonitoredBaseLayerError::BaseLayerContractError(err)) } - async fn latest_l1_block_number( - &self, - finality: u64, - ) -> Result, Self::Error> { + async fn latest_l1_block_number(&self, finality: u64) -> Result { self.get() .await? .latest_l1_block_number(finality) From 74863f2559fba2a2c506a58dee25f45ae3a8e5d0 Mon Sep 17 00:00:00 2001 From: Alon Haramati <91828241+alonh5@users.noreply.github.com> Date: Thu, 18 Sep 2025 15:35:16 +0300 Subject: [PATCH 019/313] apollo_batcher: add storage commitment success log (#9069) --- crates/apollo_batcher/src/batcher.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/apollo_batcher/src/batcher.rs b/crates/apollo_batcher/src/batcher.rs index 925d066c800..6d413db5c24 100644 --- a/crates/apollo_batcher/src/batcher.rs +++ b/crates/apollo_batcher/src/batcher.rs @@ -652,6 +652,7 @@ impl Batcher { error!("Failed to commit proposal to storage: {}", err); BatcherError::InternalError })?; + info!("Successfully committed proposal for block {} to storage.", height); // Notify the L1 provider of the new block. let rejected_l1_handler_tx_hashes = rejected_tx_hashes From 459e105d824bda104fe04df071f57721c602255f Mon Sep 17 00:00:00 2001 From: ron-starkware Date: Thu, 18 Sep 2025 22:29:40 +0300 Subject: [PATCH 020/313] apollo_dashboard: Minimize Grafana JSON file to be under 1MB (#9391) --- deployments/monitoring/src/builders/dashboard_builder.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/deployments/monitoring/src/builders/dashboard_builder.py b/deployments/monitoring/src/builders/dashboard_builder.py index 72715bc213d..19bec0dbe27 100755 --- a/deployments/monitoring/src/builders/dashboard_builder.py +++ b/deployments/monitoring/src/builders/dashboard_builder.py @@ -9,6 +9,8 @@ from common.helpers import EnvironmentName, env_to_gcp_project_name, get_logger from urllib.parse import quote +MAX_ALLOWED_JSON_SIZE = 1024 * 1024 # 1MB + def create_grafana_panel(panel: dict, panel_id: int, y_position: int, x_position: int) -> dict: exprs = panel["exprs"] @@ -236,8 +238,10 @@ def dashboard_builder(args: argparse.Namespace) -> None: if args.out_dir: output_dir = f"{args.out_dir}/dashboards" os.makedirs(output_dir, exist_ok=True) - with open(dashboard_file_name(output_dir, dashboard_name), "w") as f: - json.dump(dashboard, f, indent=4) + json_data = json.dumps(dashboard, indent=1, ensure_ascii=False) + assert len(json_data) < MAX_ALLOWED_JSON_SIZE, "Grafana dashboard JSON is too large" + with open(dashboard_file_name(output_dir, dashboard_name), "w", encoding="utf-8") as f: + f.write(json_data) if not args.dry_run: upload_dashboards_local(dashboard=dashboard) From 8d3962c19c0295fac3594b1ae65d27faea4a8fdb Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Sun, 21 Sep 2025 15:28:50 +0300 Subject: [PATCH 021/313] apollo_l1_provider: panic on wrong height only on commit_block (#9404) * apollo_l1_provider: panic on wrong height only on commit_block * apollo_l1_provider: fix todo --------- Co-authored-by: Shahak Shama --- crates/apollo_l1_provider/src/l1_provider.rs | 23 +++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_provider.rs b/crates/apollo_l1_provider/src/l1_provider.rs index 539ba2e1247..d8dc0013851 100644 --- a/crates/apollo_l1_provider/src/l1_provider.rs +++ b/crates/apollo_l1_provider/src/l1_provider.rs @@ -55,7 +55,7 @@ impl L1Provider { return Err(L1ProviderError::Uninitialized); } - self.validate_height(height); + self.check_height_with_error(height)?; info!("Starting block at height: {height}"); self.state = state.into(); self.tx_manager.start_block(); @@ -87,7 +87,7 @@ impl L1Provider { return Err(L1ProviderError::Uninitialized); } - self.validate_height(height); + self.check_height_with_error(height)?; match self.state { ProviderState::Propose => { @@ -126,7 +126,7 @@ impl L1Provider { return Err(L1ProviderError::Uninitialized); } - self.validate_height(height); + self.check_height_with_error(height)?; match self.state { ProviderState::Validate => { Ok(self.tx_manager.validate_tx(tx_hash, self.clock.unix_now())) @@ -169,7 +169,10 @@ impl L1Provider { return self.bootstrap(committed_txs, height); } - self.validate_height(height); + // If not historical height and not bootstrapping, must go into bootstrap state upon getting + // wrong height. + // TODO(guyn): for now, we go into bootstrap using panic. We should improve this. + self.check_height_with_panic(height); self.apply_commit_block(committed_txs, rejected_txs); self.state = self.state.transition_to_pending(); @@ -257,7 +260,17 @@ impl L1Provider { }) } - fn validate_height(&mut self, height: BlockNumber) { + fn check_height_with_error(&mut self, height: BlockNumber) -> L1ProviderResult<()> { + if height != self.current_height { + return Err(L1ProviderError::UnexpectedHeight { + expected_height: self.current_height, + got: height, + }); + } + Ok(()) + } + + fn check_height_with_panic(&mut self, height: BlockNumber) { if height > self.current_height { // TODO(shahak): Add a way to move to bootstrap mode from any point and move to // bootstrap here instead of panicking. From c729201cc6ce465c7586eca941285bcbecd2e52b Mon Sep 17 00:00:00 2001 From: ron-starkware Date: Sun, 21 Sep 2025 15:34:11 +0300 Subject: [PATCH 022/313] apollo_dashboard: Change block close reason to stat in Grafana (#9394) --- crates/apollo_dashboard/resources/dev_grafana.json | 2 +- crates/apollo_dashboard/src/panels/batcher.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 82230031e28..e2c327f0ae4 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -373,7 +373,7 @@ { "title": "Block Close Reasons", "description": "Number of blocks closed by reason (10m window)", - "type": "timeseries", + "type": "stat", "exprs": [ "sum by (block_close_reason) (increase(batcher_block_close_reason{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m]))" ], diff --git a/crates/apollo_dashboard/src/panels/batcher.rs b/crates/apollo_dashboard/src/panels/batcher.rs index 846747da277..ba15bff3427 100644 --- a/crates/apollo_dashboard/src/panels/batcher.rs +++ b/crates/apollo_dashboard/src/panels/batcher.rs @@ -90,7 +90,7 @@ fn get_panel_block_close_reasons() -> Panel { LABEL_NAME_BLOCK_CLOSE_REASON, BLOCK_CLOSE_REASON.get_name_with_filter() )], - PanelType::TimeSeries, + PanelType::Stat, ) .with_log_query("\"Block builder deadline reached.\" OR \"Block is full.\"") } From 596a333e6017b84814d7f267be66357775339d01 Mon Sep 17 00:00:00 2001 From: ron-starkware Date: Sun, 21 Sep 2025 15:34:20 +0300 Subject: [PATCH 023/313] apollo_dashboard: Add pod name to tokio panel legend (#9395) --- crates/apollo_dashboard/resources/dev_grafana.json | 6 +++++- crates/apollo_dashboard/src/panels/tokio.rs | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index e2c327f0ae4..5d013e2e5bf 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -1192,7 +1192,11 @@ "exprs": [ "tokio_total_busy_duration{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "legends": [ + "{{pod}}" + ] + } }, { "title": "tokio_min_busy_duration", diff --git a/crates/apollo_dashboard/src/panels/tokio.rs b/crates/apollo_dashboard/src/panels/tokio.rs index 9842434a164..55a9de6d385 100644 --- a/crates/apollo_dashboard/src/panels/tokio.rs +++ b/crates/apollo_dashboard/src/panels/tokio.rs @@ -13,6 +13,7 @@ use crate::dashboard::{Panel, PanelType, Row}; fn get_panel_tokio_total_busy_duration_micros() -> Panel { Panel::from_counter(&TOKIO_TOTAL_BUSY_DURATION_MICROS, PanelType::TimeSeries) + .with_legends(vec!["{{pod}}"]) } fn get_panel_tokio_min_busy_duration_micros() -> Panel { Panel::from_counter(&TOKIO_MIN_BUSY_DURATION_MICROS, PanelType::TimeSeries) From 9fa060979ec4cf8a1def1ad0a1f7b605fe133ade Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Sun, 21 Sep 2025 15:47:28 +0300 Subject: [PATCH 024/313] apollo_deployments: add potc mock params (#9396) --- .../{potc2_sepolia.json => potc_mock.json} | 14 ++-- .../resources/deployments/potc2/hybrid_0.json | 11 --- .../resources/deployments/potc2/hybrid_1.json | 11 --- .../resources/deployments/potc2/hybrid_2.json | 11 --- .../deployment_config_hybrid_0.json | 74 +++++++++---------- .../deployment_config_hybrid_1.json | 74 +++++++++---------- .../deployment_config_hybrid_2.json | 74 +++++++++---------- .../deployment_config_override.json | 2 +- .../deployments/potc_mock/hybrid_0.json | 11 +++ .../deployments/potc_mock/hybrid_1.json | 11 +++ .../deployments/potc_mock/hybrid_2.json | 11 +++ .../src/deployment_definitions.rs | 8 +- .../src/deployments/hybrid.rs | 47 ++++++------ 13 files changed, 167 insertions(+), 192 deletions(-) rename crates/apollo_deployments/resources/deployment_inputs/{potc2_sepolia.json => potc_mock.json} (53%) delete mode 100644 crates/apollo_deployments/resources/deployments/potc2/hybrid_0.json delete mode 100644 crates/apollo_deployments/resources/deployments/potc2/hybrid_1.json delete mode 100644 crates/apollo_deployments/resources/deployments/potc2/hybrid_2.json rename crates/apollo_deployments/resources/deployments/{potc2 => potc_mock}/deployment_config_hybrid_0.json (81%) rename crates/apollo_deployments/resources/deployments/{potc2 => potc_mock}/deployment_config_hybrid_1.json (81%) rename crates/apollo_deployments/resources/deployments/{potc2 => potc_mock}/deployment_config_hybrid_2.json (81%) rename crates/apollo_deployments/resources/deployments/{potc2 => potc_mock}/deployment_config_override.json (90%) create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/hybrid_0.json create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/hybrid_1.json create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/hybrid_2.json diff --git a/crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json similarity index 53% rename from crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json rename to crates/apollo_deployments/resources/deployment_inputs/potc_mock.json index 2aa5f47e353..2e12f271062 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json +++ b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json @@ -1,18 +1,18 @@ { - "node_and_validator_ids": [[0, "0x64"], [1,"0x65"], [2,"0x66"]], + "node_and_validator_ids": [[0, "0x64"], [1, "0x65"], [2, "0x66"]], "num_validators": 3, - "http_server_ingress_alternative_name": "potc-mock-sepolia.starknet.io", + "http_server_ingress_alternative_name": "potc-testnet-mock-sepolia.starknet.io", "ingress_domain": "starknet.io", - "secret_name_format": "apollo-potc-2-sepolia-mock-sharp-{}", - "node_namespace_format": "apollo-potc-2-sepolia-mock-sharp-{}", + "secret_name_format": "apollo-potc-mock-{}", + "node_namespace_format": "apollo-potc-mock-{}", "starknet_contract_address": "0xd8A5518cf4AC3ECD3b4cec772478109679a73E78", "chain_id_string": "PRIVATE_SN_POTC_MOCK_SEPOLIA", "eth_fee_token_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - "starknet_gateway_url": "https://feeder.potc-mock-sepolia-fgw.starknet.io/", + "starknet_gateway_url": "https://feeder.potc-testnet-mock-sepolia.starknet.io", "strk_fee_token_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_startup_height_override": null, "state_sync_type": "Central", "p2p_communication_type": "Internal", - "deployment_environment": "Potc2", - "requires_k8s_service_config_params": true + "deployment_environment": "PotcMock", + "requires_k8s_service_config_params": false } diff --git a/crates/apollo_deployments/resources/deployments/potc2/hybrid_0.json b/crates/apollo_deployments/resources/deployments/potc2/hybrid_0.json deleted file mode 100644 index 863c43641ce..00000000000 --- a/crates/apollo_deployments/resources/deployments/potc2/hybrid_0.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "consensus_manager_config.network_config.advertised_multiaddr": "", - "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, - "mempool_p2p_config.network_config.advertised_multiaddr": "", - "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, - "validator_id": "0x64" -} diff --git a/crates/apollo_deployments/resources/deployments/potc2/hybrid_1.json b/crates/apollo_deployments/resources/deployments/potc2/hybrid_1.json deleted file mode 100644 index 1329d149ed3..00000000000 --- a/crates/apollo_deployments/resources/deployments/potc2/hybrid_1.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "consensus_manager_config.network_config.advertised_multiaddr": "", - "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, - "mempool_p2p_config.network_config.advertised_multiaddr": "", - "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, - "validator_id": "0x65" -} diff --git a/crates/apollo_deployments/resources/deployments/potc2/hybrid_2.json b/crates/apollo_deployments/resources/deployments/potc2/hybrid_2.json deleted file mode 100644 index 26f7b7605f7..00000000000 --- a/crates/apollo_deployments/resources/deployments/potc2/hybrid_2.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "consensus_manager_config.network_config.advertised_multiaddr": "", - "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, - "mempool_p2p_config.network_config.advertised_multiaddr": "", - "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, - "validator_id": "0x66" -} diff --git a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_0.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_0.json similarity index 81% rename from crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_0.json rename to crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_0.json index f89eb8c88ea..98b676e0210 100644 --- a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_0.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_0.json @@ -14,32 +14,28 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/monitoring_endpoint_config.json", "app_configs/state_sync_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_0.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_0.json", "services/hybrid/core.json" ], "ingress": null, - "k8s_service_config": { - "type": "LoadBalancer", - "external_dns_name": "sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-0.starknet.io", - "internal": true - }, + "k8s_service_config": null, "autoscale": false, "replicas": 1, "storage": 1000, "toleration": "batcher-8-64", "resources": { "requests": { - "cpu": 50, - "memory": 200 + "cpu": 2, + "memory": 4 }, "limits": { - "cpu": 50, - "memory": 220 + "cpu": 7, + "memory": 14 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-0" + "gcsm_key": "apollo-potc-mock-0" }, "anti_affinity": true, "update_strategy_type": "RollingUpdate", @@ -61,14 +57,14 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/http_server_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_0.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_0.json", "services/hybrid/http_server.json" ], "ingress": { "domain": "starknet.io", "alternative_names": [ - "potc-mock-sepolia.starknet.io" + "potc-testnet-mock-sepolia.starknet.io" ], "internal": false, "rules": [ @@ -95,7 +91,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-0" + "gcsm_key": "apollo-potc-mock-0" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", @@ -114,8 +110,8 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/gateway_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_0.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_0.json", "services/hybrid/gateway.json" ], "ingress": null, @@ -135,7 +131,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-0" + "gcsm_key": "apollo-potc-mock-0" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", @@ -159,8 +155,8 @@ "app_configs/l1_provider_config.json", "app_configs/l1_scraper_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_0.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_0.json", "services/hybrid/l1.json" ], "ingress": null, @@ -171,16 +167,16 @@ "toleration": "apollo-l1-service", "resources": { "requests": { - "cpu": 2, - "memory": 4 + "cpu": 1, + "memory": 2 }, "limits": { - "cpu": 3, - "memory": 12 + "cpu": 2, + "memory": 4 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-0" + "gcsm_key": "apollo-potc-mock-0" }, "anti_affinity": true, "update_strategy_type": "Recreate", @@ -202,32 +198,28 @@ "app_configs/mempool_config.json", "app_configs/mempool_p2p_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_0.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_0.json", "services/hybrid/mempool.json" ], "ingress": null, - "k8s_service_config": { - "type": "LoadBalancer", - "external_dns_name": "sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-0.starknet.io", - "internal": true - }, + "k8s_service_config": null, "autoscale": false, "replicas": 1, "storage": null, "toleration": "apollo-mempool-service", "resources": { "requests": { - "cpu": 2, - "memory": 4 + "cpu": 1, + "memory": 2 }, "limits": { - "cpu": 3, - "memory": 12 + "cpu": 2, + "memory": 4 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-0" + "gcsm_key": "apollo-potc-mock-0" }, "anti_affinity": true, "update_strategy_type": "Recreate", @@ -246,8 +238,8 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/monitoring_endpoint_config.json", "app_configs/sierra_compiler_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_0.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_0.json", "services/hybrid/sierra_compiler.json" ], "ingress": null, @@ -267,7 +259,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-0" + "gcsm_key": "apollo-potc-mock-0" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", diff --git a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_1.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_1.json similarity index 81% rename from crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_1.json rename to crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_1.json index f9f55df8a50..1d06db39980 100644 --- a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_1.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_1.json @@ -14,32 +14,28 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/monitoring_endpoint_config.json", "app_configs/state_sync_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_1.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_1.json", "services/hybrid/core.json" ], "ingress": null, - "k8s_service_config": { - "type": "LoadBalancer", - "external_dns_name": "sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-1.starknet.io", - "internal": true - }, + "k8s_service_config": null, "autoscale": false, "replicas": 1, "storage": 1000, "toleration": "batcher-8-64", "resources": { "requests": { - "cpu": 50, - "memory": 200 + "cpu": 2, + "memory": 4 }, "limits": { - "cpu": 50, - "memory": 220 + "cpu": 7, + "memory": 14 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-1" + "gcsm_key": "apollo-potc-mock-1" }, "anti_affinity": true, "update_strategy_type": "RollingUpdate", @@ -61,14 +57,14 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/http_server_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_1.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_1.json", "services/hybrid/http_server.json" ], "ingress": { "domain": "starknet.io", "alternative_names": [ - "potc-mock-sepolia.starknet.io" + "potc-testnet-mock-sepolia.starknet.io" ], "internal": false, "rules": [ @@ -95,7 +91,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-1" + "gcsm_key": "apollo-potc-mock-1" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", @@ -114,8 +110,8 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/gateway_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_1.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_1.json", "services/hybrid/gateway.json" ], "ingress": null, @@ -135,7 +131,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-1" + "gcsm_key": "apollo-potc-mock-1" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", @@ -159,8 +155,8 @@ "app_configs/l1_provider_config.json", "app_configs/l1_scraper_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_1.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_1.json", "services/hybrid/l1.json" ], "ingress": null, @@ -171,16 +167,16 @@ "toleration": "apollo-l1-service", "resources": { "requests": { - "cpu": 2, - "memory": 4 + "cpu": 1, + "memory": 2 }, "limits": { - "cpu": 3, - "memory": 12 + "cpu": 2, + "memory": 4 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-1" + "gcsm_key": "apollo-potc-mock-1" }, "anti_affinity": true, "update_strategy_type": "Recreate", @@ -202,32 +198,28 @@ "app_configs/mempool_config.json", "app_configs/mempool_p2p_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_1.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_1.json", "services/hybrid/mempool.json" ], "ingress": null, - "k8s_service_config": { - "type": "LoadBalancer", - "external_dns_name": "sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-1.starknet.io", - "internal": true - }, + "k8s_service_config": null, "autoscale": false, "replicas": 1, "storage": null, "toleration": "apollo-mempool-service", "resources": { "requests": { - "cpu": 2, - "memory": 4 + "cpu": 1, + "memory": 2 }, "limits": { - "cpu": 3, - "memory": 12 + "cpu": 2, + "memory": 4 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-1" + "gcsm_key": "apollo-potc-mock-1" }, "anti_affinity": true, "update_strategy_type": "Recreate", @@ -246,8 +238,8 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/monitoring_endpoint_config.json", "app_configs/sierra_compiler_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_1.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_1.json", "services/hybrid/sierra_compiler.json" ], "ingress": null, @@ -267,7 +259,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-1" + "gcsm_key": "apollo-potc-mock-1" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", diff --git a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_2.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_2.json similarity index 81% rename from crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_2.json rename to crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_2.json index 35bc4698f0e..fb254c21b27 100644 --- a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_hybrid_2.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_2.json @@ -14,32 +14,28 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/monitoring_endpoint_config.json", "app_configs/state_sync_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_2.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_2.json", "services/hybrid/core.json" ], "ingress": null, - "k8s_service_config": { - "type": "LoadBalancer", - "external_dns_name": "sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-2.starknet.io", - "internal": true - }, + "k8s_service_config": null, "autoscale": false, "replicas": 1, "storage": 1000, "toleration": "batcher-8-64", "resources": { "requests": { - "cpu": 50, - "memory": 200 + "cpu": 2, + "memory": 4 }, "limits": { - "cpu": 50, - "memory": 220 + "cpu": 7, + "memory": 14 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-2" + "gcsm_key": "apollo-potc-mock-2" }, "anti_affinity": true, "update_strategy_type": "RollingUpdate", @@ -61,14 +57,14 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/http_server_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_2.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_2.json", "services/hybrid/http_server.json" ], "ingress": { "domain": "starknet.io", "alternative_names": [ - "potc-mock-sepolia.starknet.io" + "potc-testnet-mock-sepolia.starknet.io" ], "internal": false, "rules": [ @@ -95,7 +91,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-2" + "gcsm_key": "apollo-potc-mock-2" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", @@ -114,8 +110,8 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/gateway_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_2.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_2.json", "services/hybrid/gateway.json" ], "ingress": null, @@ -135,7 +131,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-2" + "gcsm_key": "apollo-potc-mock-2" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", @@ -159,8 +155,8 @@ "app_configs/l1_provider_config.json", "app_configs/l1_scraper_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_2.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_2.json", "services/hybrid/l1.json" ], "ingress": null, @@ -171,16 +167,16 @@ "toleration": "apollo-l1-service", "resources": { "requests": { - "cpu": 2, - "memory": 4 + "cpu": 1, + "memory": 2 }, "limits": { - "cpu": 3, - "memory": 12 + "cpu": 2, + "memory": 4 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-2" + "gcsm_key": "apollo-potc-mock-2" }, "anti_affinity": true, "update_strategy_type": "Recreate", @@ -202,32 +198,28 @@ "app_configs/mempool_config.json", "app_configs/mempool_p2p_config.json", "app_configs/monitoring_endpoint_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_2.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_2.json", "services/hybrid/mempool.json" ], "ingress": null, - "k8s_service_config": { - "type": "LoadBalancer", - "external_dns_name": "sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-2.starknet.io", - "internal": true - }, + "k8s_service_config": null, "autoscale": false, "replicas": 1, "storage": null, "toleration": "apollo-mempool-service", "resources": { "requests": { - "cpu": 2, - "memory": 4 + "cpu": 1, + "memory": 2 }, "limits": { - "cpu": 3, - "memory": 12 + "cpu": 2, + "memory": 4 } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-2" + "gcsm_key": "apollo-potc-mock-2" }, "anti_affinity": true, "update_strategy_type": "Recreate", @@ -246,8 +238,8 @@ "app_configs/validate_resource_bounds_config.json", "app_configs/monitoring_endpoint_config.json", "app_configs/sierra_compiler_config.json", - "deployments/potc2/deployment_config_override.json", - "deployments/potc2/hybrid_2.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_2.json", "services/hybrid/sierra_compiler.json" ], "ingress": null, @@ -267,7 +259,7 @@ } }, "external_secret": { - "gcsm_key": "apollo-potc-2-sepolia-mock-sharp-2" + "gcsm_key": "apollo-potc-mock-2" }, "anti_affinity": false, "update_strategy_type": "RollingUpdate", diff --git a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json similarity index 90% rename from crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json rename to crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json index d6f9c58404c..a4205b34531 100644 --- a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json @@ -5,7 +5,7 @@ "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, - "starknet_url": "https://feeder.potc-mock-sepolia-fgw.starknet.io/", + "starknet_url": "https://feeder.potc-testnet-mock-sepolia.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, "state_sync_config.p2p_sync_client_config.#is_none": true, diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_0.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_0.json new file mode 100644 index 00000000000..975c81eb4cd --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_0.json @@ -0,0 +1,11 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "validator_id": "0x64" +} diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_1.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_1.json new file mode 100644 index 00000000000..967e3aaeeb2 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_1.json @@ -0,0 +1,11 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "validator_id": "0x65" +} diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_2.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_2.json new file mode 100644 index 00000000000..b5c8059d531 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_2.json @@ -0,0 +1,11 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "validator_id": "0x66" +} diff --git a/crates/apollo_deployments/src/deployment_definitions.rs b/crates/apollo_deployments/src/deployment_definitions.rs index 3d5bf13fc02..8f910594e3e 100644 --- a/crates/apollo_deployments/src/deployment_definitions.rs +++ b/crates/apollo_deployments/src/deployment_definitions.rs @@ -41,7 +41,7 @@ const SIERRA_COMPILER_PORT: u16 = 55007; const STATE_SYNC_PORT: u16 = 55009; pub const DEPLOYMENTS: &[DeploymentFn] = &[ - || load_and_create_hybrid_deployments(POTC2_DEPLOYMENT_INPUTS_PATH), + || load_and_create_hybrid_deployments(POTC_MOCK_DEPLOYMENT_INPUTS_PATH), || load_and_create_hybrid_deployments(MAINNET_DEPLOYMENT_INPUTS_PATH), || load_and_create_hybrid_deployments(INTEGRATION_DEPLOYMENT_INPUTS_PATH), || load_and_create_hybrid_deployments(TESTNET_DEPLOYMENT_INPUTS_PATH), @@ -55,8 +55,8 @@ pub(crate) const DEPLOYMENT_CONFIG_DIR_NAME: &str = "deployments/"; const BASE_APP_CONFIGS_DIR_PATH: &str = "crates/apollo_deployments/resources/app_configs"; -const POTC2_DEPLOYMENT_INPUTS_PATH: &str = - "crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json"; +const POTC_MOCK_DEPLOYMENT_INPUTS_PATH: &str = + "crates/apollo_deployments/resources/deployment_inputs/potc_mock.json"; const MAINNET_DEPLOYMENT_INPUTS_PATH: &str = "crates/apollo_deployments/resources/deployment_inputs/mainnet.json"; const INTEGRATION_DEPLOYMENT_INPUTS_PATH: &str = @@ -129,7 +129,7 @@ impl Display for Environment { #[derive(EnumString, Clone, Display, PartialEq, Debug, Serialize, Deserialize)] #[strum(serialize_all = "snake_case")] pub enum CloudK8sEnvironment { - Potc2, + PotcMock, Mainnet, SepoliaIntegration, SepoliaTestnet, diff --git a/crates/apollo_deployments/src/deployments/hybrid.rs b/crates/apollo_deployments/src/deployments/hybrid.rs index a9ad3c54cd7..87ce6fbe126 100644 --- a/crates/apollo_deployments/src/deployments/hybrid.rs +++ b/crates/apollo_deployments/src/deployments/hybrid.rs @@ -189,7 +189,7 @@ impl ServiceNameInner for HybridNodeServiceName { CloudK8sEnvironment::Mainnet | CloudK8sEnvironment::SepoliaTestnet | CloudK8sEnvironment::StressTest => Some(Toleration::ApolloCoreServiceC2D56), - CloudK8sEnvironment::Potc2 => Some(Toleration::Batcher864), + CloudK8sEnvironment::PotcMock => Some(Toleration::Batcher864), }, HybridNodeServiceName::HttpServer | HybridNodeServiceName::Gateway @@ -255,30 +255,29 @@ impl ServiceNameInner for HybridNodeServiceName { fn get_resources(&self, environment: &Environment) -> Resources { match environment { Environment::CloudK8s(cloud_env) => match cloud_env { - CloudK8sEnvironment::SepoliaIntegration | CloudK8sEnvironment::UpgradeTest => { - match self { - HybridNodeServiceName::Core => { - Resources::new(Resource::new(2, 4), Resource::new(7, 14)) - } - HybridNodeServiceName::HttpServer => { - Resources::new(Resource::new(1, 2), Resource::new(4, 8)) - } - HybridNodeServiceName::Gateway => { - Resources::new(Resource::new(1, 2), Resource::new(2, 4)) - } - HybridNodeServiceName::L1 => { - Resources::new(Resource::new(1, 2), Resource::new(2, 4)) - } - HybridNodeServiceName::Mempool => { - Resources::new(Resource::new(1, 2), Resource::new(2, 4)) - } - HybridNodeServiceName::SierraCompiler => { - Resources::new(Resource::new(1, 2), Resource::new(2, 4)) - } + CloudK8sEnvironment::PotcMock + | CloudK8sEnvironment::SepoliaIntegration + | CloudK8sEnvironment::UpgradeTest => match self { + HybridNodeServiceName::Core => { + Resources::new(Resource::new(2, 4), Resource::new(7, 14)) } - } - CloudK8sEnvironment::Potc2 - | CloudK8sEnvironment::Mainnet + HybridNodeServiceName::HttpServer => { + Resources::new(Resource::new(1, 2), Resource::new(4, 8)) + } + HybridNodeServiceName::Gateway => { + Resources::new(Resource::new(1, 2), Resource::new(2, 4)) + } + HybridNodeServiceName::L1 => { + Resources::new(Resource::new(1, 2), Resource::new(2, 4)) + } + HybridNodeServiceName::Mempool => { + Resources::new(Resource::new(1, 2), Resource::new(2, 4)) + } + HybridNodeServiceName::SierraCompiler => { + Resources::new(Resource::new(1, 2), Resource::new(2, 4)) + } + }, + CloudK8sEnvironment::Mainnet | CloudK8sEnvironment::SepoliaTestnet | CloudK8sEnvironment::StressTest => match self { HybridNodeServiceName::Core => { From 1ea27047a7e76dd463c099b6c4a54358be82da05 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Sun, 21 Sep 2025 15:50:08 +0300 Subject: [PATCH 025/313] apollo_gateway: whitelist classes declared by deploy as always declared (#9031) (#9402) --- .../apollo_gateway/src/sync_state_reader.rs | 149 +++++++++++++++++- .../src/sync_state_reader_test.rs | 21 ++- 2 files changed, 164 insertions(+), 6 deletions(-) diff --git a/crates/apollo_gateway/src/sync_state_reader.rs b/crates/apollo_gateway/src/sync_state_reader.rs index 01f95161a48..c0b9a821019 100644 --- a/crates/apollo_gateway/src/sync_state_reader.rs +++ b/crates/apollo_gateway/src/sync_state_reader.rs @@ -17,10 +17,12 @@ use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; use futures::executor::block_on; +use lazy_static::lazy_static; use starknet_api::block::{BlockHash, BlockInfo, BlockNumber, GasPriceVector, GasPrices}; use starknet_api::contract_class::ContractClass; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::data_availability::L1DataAvailabilityMode; +use starknet_api::felt; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; @@ -123,11 +125,16 @@ impl BlockifierStateReader for SyncStateReader { } fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { - let is_class_declared = self + let mut is_class_declared = self .runtime .block_on(self.state_sync_client.is_class_declared_at(self.block_number, class_hash)) .map_err(|e| StateError::StateReadError(e.to_string()))?; + // TODO(shahak): Remove this once we've resynced all production nodes. + if OLD_DEPLOY_CLASS_HASH_WHITELIST.contains(&class_hash) { + is_class_declared = true; + } + if !is_class_declared { return Err(StateError::UndeclaredClassHash(class_hash)); } @@ -299,3 +306,143 @@ impl StateReaderFactory for SyncStateReaderFactory { ))) } } + +lazy_static! { + pub(crate) static ref OLD_DEPLOY_CLASS_HASH_WHITELIST: [ClassHash; 135] = [ + ClassHash(felt!("00a4e57ac025a86e283b7ef0132a6543305600788b783ba6fb48426703a5abbf")), + ClassHash(felt!("03f43dfee1c6e5c33065a714535e06a8ffd7e76a12bb74ed9093946be6c2d798")), + ClassHash(felt!("0726edb35cc732c1b3661fd837592033bd85ae8dde31533c35711fb0422d8993")), + ClassHash(felt!("07ab58843a19e516c83057cd49beaba917aa9477cab703b3c6ae1ab9d822c4b1")), + ClassHash(felt!("07f1c7e439328634d159aeb68f1b40b74f7a05da3832515561e77aadaf57a591")), + ClassHash(felt!("0157d87bdad1328cbf429826a83545f6ffb6505138983885a75997ee2c49e66b")), + ClassHash(felt!("075da0ac40ebc084e87ba5f22f1c2743a9e7e85d88dc795d0379cd00d04a7072")), + ClassHash(felt!("07b5e991587f0c59db1c4c4ff9b26fa8ec49198ca6d8a82823cc2c6177d918fa")), + ClassHash(felt!("0665d8f3ff5d12d8e1f4bcfea7b54f10eb5fe294cac5a428d6549eba08e00451")), + ClassHash(felt!("07595b4f7d50010ceb00230d8b5656e3c3dd201b6df35d805d3f2988c69a1432")), + ClassHash(felt!("03ec0f1fa8614a821596bae6ecbacca66b52b5c1c92fe1a950656b9a3beaf012")), + ClassHash(felt!("0631217418b8965601291874c906989517fa934babbce7a7ea18a7668c7c6304")), + ClassHash(felt!("05d9a7bdec373b49efef91c6da3d595a96e1a5e8302bc62c7c8ac7df730e751d")), + ClassHash(felt!("020c279bb3d77dce970cf5dc98341251bbc20eb021d029a8fd28020a4bd9c3c1")), + ClassHash(felt!("0733734fa0dab1158bccdfe0df7b0becf3827f908971fac8d39cc73d99ad8645")), + ClassHash(felt!("0784f488f47e20acfc738456581c2c7d34e7a0b74b040a8ab347f24f10c00b6e")), + ClassHash(felt!("04d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f")), + ClassHash(felt!("069236f4ab1d052ca50b7574436e6a6b760503d7973bb7133255a2676c1bdb69")), + ClassHash(felt!("008b12f11b1ea5e43cdf8870be6a0579e920873a83c4b8931a27abc4c032ee64")), + ClassHash(felt!("039547c16c9ca7ab54882da944161eb7b13805e5dbb01dab45d814baada6f282")), + ClassHash(felt!("0626424ef94979b877311ac1be3099b2021977d281e5c8c66acc92b40ba1e1df")), + ClassHash(felt!("057a4fbfcfcde85f3d99ca1053266cb29c513856fd2a758df6774def2101e677")), + ClassHash(felt!("023d98a23d5f542269486edc2b9c0394cc510a9862c3f3ea82fa0798269ee0bc")), + ClassHash(felt!("008d8726481b7b8a4a8f95aa2ce6a18932c33148600c75b1b4fe40c5987c6c9a")), + ClassHash(felt!("04c53698c9a42341e4123632e87b752d6ae470ddedeb8b0063eaa2deea387eeb")), + ClassHash(felt!("066a3ec9166b2b39de4bb5f46dee36998c29d2ae3bc61bd1187fb11fa676555b")), + ClassHash(felt!("046f844ea1a3b3668f81d38b5c1bd55e816e0373802aefe732138628f0133486")), + ClassHash(felt!("04e709a7d569e5b041f46e0d4d654cbf96d8b4749088705892d4e6969dff3e35")), + ClassHash(felt!("029d2cc5f6beac7fef596a256c8bd3a0eb0f83248886599ec80ee72133d747eb")), + ClassHash(felt!("017eddd685efc7966e9ceb26d5ccf58180f802c72f06f1a1bff1c4d74a59c872")), + ClassHash(felt!("03131fa018d520a037686ce3efddeab8f28895662f019ca3ca18a626650f7d1e")), + ClassHash(felt!("06dadf634444dfa550750191a1b8ba77970d0f11bea3df469c968bb59ba73158")), + ClassHash(felt!("002f09c8cc7698d6a220b929b525efd5b3622a7658e9a9e4c8a52d5ed995d6fe")), + ClassHash(felt!("07e35b811e3d4e2678d037b632a0c8a09a46d82185187762c0d429363e3ef9cf")), + ClassHash(felt!("0042477e2f668af48c85770ffc9ececcd39d5aaf077da491a5bdc6204f71bdb6")), + ClassHash(felt!("02c3348ad109f7f3967df6494b3c48741d61675d9a7915b265aa7101a631dc33")), + ClassHash(felt!("04a153d1ef11d0bdff01e51ae866e7a8c66f2e968cfeabcb30793220b5910e2f")), + ClassHash(felt!("07d32ee16204aef3a9e4ed9b8b681fda37ab299e29fe1b21413ce3768d4e4a76")), + ClassHash(felt!("060924bf85cdd22c7e24cf8b6ac45a9a6b753671dfd0da07aae5d6b3c65a05e2")), + ClassHash(felt!("070aa6f103ec0e73e7acb691f0f05208d6b1cd67c309e22f4e2605db109600f1")), + ClassHash(felt!("027f27c5dcec1611d303e65ddb12acc92def6202203c5b3f8762855306d01065")), + ClassHash(felt!("010455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8")), + ClassHash(felt!("008dbcb158b134f80d7cdfc2afe7c1fca21de99865d41b9b17bc3303432e8c51")), + ClassHash(felt!("01cb96b938da26c060d5fd807eef8b580c49490926393a5eeb408a89f84b9b46")), + ClassHash(felt!("04e6d8a7f0b6178e2e8f0789e34925fe425b761b0bb608916b0d86531c65c16d")), + ClassHash(felt!("0167470236540c4537a005a1d1cabc08e7ebb10a6f75c9a1d1171a131e41a95b")), + ClassHash(felt!("033143c31c75a787ebdb16a3d9400e0d1a71fbeac2a067793bf93c289d56b03b")), + ClassHash(felt!("0399f629212fd7f2f06723f84340fddd48720c6a1bc19c159313138520a097d5")), + ClassHash(felt!("05605533726157c4b3aa2213365539cad99273b993bc35e91043a8cae42cd402")), + ClassHash(felt!("026033711f79998aadcaee45eab3d8b7d04d83f2efb3334cf38db1fbd947339e")), + ClassHash(felt!("07c44f58c7a0f03c74f96ba5cfd4e3b1036411d5cca1e65695ef1ae11751414d")), + ClassHash(felt!("07c8296b1c53c8000b10f54c5b2aa6a36dd4a69b1074dafdf7d0215403ae3e27")), + ClassHash(felt!("01ba5d32901bb498ab120297923786da8f3425d2ad518c3ceedf9fa2723a0eaa")), + ClassHash(felt!("02dbfa1499840ded1107c63d3ddf4612e0765ef69d511ddaaebc6bf91bb1388d")), + ClassHash(felt!("034de8f05f757772514aafe058245731ba93796cbcf1274fca6ba1d04eeac950")), + ClassHash(felt!("00d0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3")), + ClassHash(felt!("055dd147f5ac39904b109b7407396529ab6defb8feef46a147e742accd6f8795")), + ClassHash(felt!("011eb881c6330b42c1d6d0d37581c134ab51235850bebbc604ebf96ef8dea5d7")), + ClassHash(felt!("0037150ba6f2ccb3a19a45ebe2de28e85b21dbdcaf77436f4e0cdf686a109989")), + ClassHash(felt!("048498ebae1afc22157322db4bb7814b668c7ee20237cc8be64d934649679da1")), + ClassHash(felt!("07543f8eb21f10b1827a495084697a519274ac9c1a1fbf931bac40133a6b9c15")), + ClassHash(felt!("048a7114e47629575c260b184686018c61c34055fefc53f6c100dedf3bc10eba")), + ClassHash(felt!("00edf4a4a2928afc19b038ab799899e0e179c7abdd86f5f1c0c5dd1b307a6b96")), + ClassHash(felt!("039a43c9b60a8f5f8de4c06a163b3f24bf9e59f1a889c323ba5b5578b1d90d95")), + ClassHash(felt!("0064aaf619d5b32b5496cb17d64ad38f390598442d6ac9a2d72c6280b863efba")), + ClassHash(felt!("0639a9186c8d9daa7c44186e7cf987cc458a46965e2658d27020554f9671677b")), + ClassHash(felt!("071c3c99f5cf76fc19945d4b8b7d34c7c5528f22730d56192b50c6bbfd338a64")), + ClassHash(felt!("078dac186418f94cb1eb2a32ed909a6e81028ce8b40b9ec0fe7f6fe4e11addd8")), + ClassHash(felt!("07d72193cd1a0a4ae7ad8b478bc7c431ce0af2803d20726253eb3e18f13f39f6")), + ClassHash(felt!("03115d29825b1a3563ada334fd4b55b36bef7f9ed01e76abe9fd0d4be616a1a7")), + ClassHash(felt!("0621b53649ddc3170f4c7db984252e9de2fd54c8080686aa9aaf5803194a9179")), + ClassHash(felt!("0750cd490a7cd1572411169eaa8be292325990d33c5d4733655fe6b926985062")), + ClassHash(felt!("071b7f73b5e2b4f81f7cf01d4d1569ccba2921b3fa3170cf11cff3720dfe918e")), + ClassHash(felt!("02895b8c4c21ed47527fa779bab13857247580553dc9f66f0a6f2146110a5a29")), + ClassHash(felt!("05915aa48a8b558dacbab894ff2e0062c6957b0b01ae89b2c609f905b7f4e19d")), + ClassHash(felt!("07122c9477ac445f6bf217176b5bc0e2d059b86f32f914a7500d9fd8f24e38ef")), + ClassHash(felt!("05e5bad04b75726fb33f4f146193ab9640a80d9fbc8f2a569192efb086b72307")), + ClassHash(felt!("031008229e9725331feb1ceff338c0e355139de300935285c2e3b76025c4abd0")), + ClassHash(felt!("026fe8ea36ec7703569cfe4693b05102940bf122647c4dbf0abc0bb919ce27bd")), + ClassHash(felt!("022a7efd343b272e499c4ae2c4250f9d345ec50a1daae97cfced921c99775ff9")), + ClassHash(felt!("014eb6c9903997faff3ad620aed584f2d0dccba5c5a016863c14228b319e09ec")), + ClassHash(felt!("00d245a36e35446ccff2ac0c6bf8d1054c970b3f5f8567113e9985724009be5a")), + ClassHash(felt!("03bcf9bad9f636f13527bde8273473314eac6f428956c03fadae1c247d03633f")), + ClassHash(felt!("00655101fb9a3c803a50de65fe9e347a71300e0f9db058da5b8ddebca2681a93")), + ClassHash(felt!("0142f4510d6a58a01091bc5ac9273535868ef6e5c8ac579ad6970c479e0553f1")), + ClassHash(felt!("06b4ee05bc5d19e932c20e5ffc2c184f1d844627a3bfebba1f0d03a2f811145f")), + ClassHash(felt!("06a1776964b9f991c710bfe910b8b37578b32b26a7dffd1669a1a59ac94bf82f")), + ClassHash(felt!("02073b7903c36c9c126c580da737b5b80bd5d77b856ae2b3906a412bbbf47480")), + ClassHash(felt!("044b511cbb25497a1534b4d821a347563a336a3955024a263786b3f19d639c11")), + ClassHash(felt!("03b2a3daa8c6f39fa07ad9847595f1841325ae7a993d6f1919f364235fd62a4b")), + ClassHash(felt!("049c599d777d52365e0e300a24067a0c420776929d398e760660170cb2212248")), + ClassHash(felt!("02cdf5ac65a41b135969dcefa9d52799a48994d4d3aee24732b78580a9fa7c63")), + ClassHash(felt!("06e26cd8efb04ca3ebb27d7b7ce32b2c6668316f26b8569f5c1cf497f27b259b")), + ClassHash(felt!("05829a410055a7da53295c05b7ce39f1b99c202d49f6194ca000d93d35adf491")), + ClassHash(felt!("07b553907c45d4be5b72a7816068518f1a1e326cef33fb1d244852965da6e8eb")), + ClassHash(felt!("0031da92cf5f54bcb81b447e219e2b791b23f3052d12b6c9abd04ff2e5626576")), + ClassHash(felt!("041efe53a722b4325d7f86b97c24b41eb6d16b98ae8a3f3374a8422033666a3e")), + ClassHash(felt!("01a315bf4e9fb59fe57c20b3d959ede354c12786e315fc4c656a7112659aa31f")), + ClassHash(felt!("07e24e482a41ba9c85e74fa62755f8dc1e378ba451cb9da2e89975d13dfa3117")), + ClassHash(felt!("04d1f4cf4ef520c768a326d34f919227e1f075effda532f57cbaec6a1228db88")), + ClassHash(felt!("00cc97194621de7ad998d64cda4554ef35c4e8931940997b2629e743eaccb4a7")), + ClassHash(felt!("00631071be7e7f42a5445af1a4bd30f97b90495f9cb4a8a82d5a94eb08a25a1f")), + ClassHash(felt!("066cc273d328e53eb56b3788684d22062bbe1a915c04594a476b33225d4ab1f4")), + ClassHash(felt!("074a7ed7f1236225600f355efe70812129658c82c295ff0f8307b3fad4bf09a9")), + ClassHash(felt!("03e44a8ce106126fbe5e777db2ca6faa7f53665e0c3d67b5794d5d95874e7472")), + ClassHash(felt!("078a6a24cd6406b3f170fd99db0d2157618203180d79c5c6807bcf633972180d")), + ClassHash(felt!("00c6529e402abdc91cc51f61ae71df2337bc6c535fd96eb79235b1a32bbc6fdc")), + ClassHash(felt!("06921d057693ea95d25883c8e0ba59d047497c23083384d95cd5937c01ae22f6")), + ClassHash(felt!("04225e15fc63c5b127e47238c9be8a403c1c75488eab215210126bcbdc48aec5")), + ClassHash(felt!("074ddc960b4568092956dade86c2919a6f5c06524beefcb5a0a7b25ee3db250c")), + ClassHash(felt!("02f885b664728291d97d8e4b27df3af8c58b69514fd825782153db9c32009763")), + ClassHash(felt!("07797ede55ea525e24078b973467b40850311f9de31913fa13fc5ef92305d849")), + ClassHash(felt!("068bb00f783b88aeb61551f5383e6b7f1621463cb570e8f63df89e3681045134")), + ClassHash(felt!("02f07cff96aff7147d4434d5cba381b75fe3d77d6b1e7f9fdd94845761afd452")), + ClassHash(felt!("0550a4b8f65f1fc1abd9f93527460c252e5a17fb2af1b5f46c981c7a646b707e")), + ClassHash(felt!("057473cd614625f7bc6998840cd2c62fe4fff39834322ac74c16eb6aa2b8f2d3")), + ClassHash(felt!("03f7a4ce5403d3a7417d9115a0982bf4bf2bc86bbfd881506a2fb466e41a8575")), + ClassHash(felt!("05d26d8883e71933c33db502cc874c6366d536970d1a399ee3a5624c94022cb2")), + ClassHash(felt!("07197021c108b0cc57ae354f5ad02222c4b3d7344664e6dd602a0e2298595434")), + ClassHash(felt!("0228a118243209dfe39069d25be535590435227e4df558cbcc54e70913b515d3")), + ClassHash(felt!("033f02ceeb057e36174b12a640376e5ade0c16a31a20ea129e7601160f85d383")), + ClassHash(felt!("04e840d1641e38c1f32d57ff062804c8666823f541a508b341651c8fa9d942dd")), + ClassHash(felt!("025529e95e8f10bef74fb4adb395652ccba2707d98e7eaa114a234f12385b447")), + ClassHash(felt!("02693dd12b58ce4da887ee9530a79c71bdeb739cf888ae9528f58d513abbd336")), + ClassHash(felt!("0710c5eedefc2c2e2dff5d6c432fda3e1e4af93579a3dbb7ee55cf260fadd543")), + ClassHash(felt!("06d135aff146d54d4dea40cdd0588845788468d1cdc0bddf5138d98567d3a7c3")), + ClassHash(felt!("01d492f0765a73712d0cd6654433945c8ac5b3409862cff41e7260315517747b")), + ClassHash(felt!("055dd2a2cf55321ff7130d68fc941a0d887b19e46eff6eae4a13b1f02bc231f6")), + ClassHash(felt!("0108a32ec851d37c8f15387dadc87dc80c302c5278b24211ea5b227a4bfdc752")), + ClassHash(felt!("071891339979b295508cd61a8477959484b955c08a617cec54ade3ccedf63762")), + ClassHash(felt!("0248339769e0b06b7d259bcaec19756d883c8610770c4f77c750a04f2401ea3b")), + ClassHash(felt!("04c2879de40a4af38083026ebf92c40dc674d7148b2369f2adb1ca155b995c30")), + ClassHash(felt!("05cc0c9569aa4e7845780a3359c88f847003bbf8bede6a55bad96da7b9fb4d50")), + ClassHash(felt!("04572af1cd59b8b91055ebb78df8f1d11c59f5270018b291366ba4585d4cdff0")), + ClassHash(felt!("05109f0f2e1db1a9977f4e59361041fd4b63988aa8bee898becb47f87307cfd4")), + ]; +} diff --git a/crates/apollo_gateway/src/sync_state_reader_test.rs b/crates/apollo_gateway/src/sync_state_reader_test.rs index 82c10468661..efa02316d17 100644 --- a/crates/apollo_gateway/src/sync_state_reader_test.rs +++ b/crates/apollo_gateway/src/sync_state_reader_test.rs @@ -31,7 +31,7 @@ use starknet_api::data_availability::L1DataAvailabilityMode; use starknet_api::{class_hash, contract_address, felt, nonce, storage_key}; use crate::state_reader::MempoolStateReader; -use crate::sync_state_reader::SyncStateReader; +use crate::sync_state_reader::{SyncStateReader, OLD_DEPLOY_CLASS_HASH_WHITELIST}; #[tokio::test] async fn test_get_block_info() { let mut mock_state_sync_client = MockStateSyncClient::new(); @@ -228,28 +228,38 @@ fn assert_eq_state_result( #[case::class_declared( Ok(Some(ContractClass::V1((dummy_casm_contract_class(), SierraVersion::default())))), Ok(true), - Ok(RunnableCompiledClass::V1((dummy_casm_contract_class(), SierraVersion::default()).try_into().unwrap())) + Ok(RunnableCompiledClass::V1((dummy_casm_contract_class(), SierraVersion::default()).try_into().unwrap())), + *DUMMY_CLASS_HASH, )] #[case::class_not_declared_but_in_class_manager( Ok(Some(ContractClass::V1((dummy_casm_contract_class(), SierraVersion::default())))), Ok(false), - Err(StateError::UndeclaredClassHash(*DUMMY_CLASS_HASH)) + Err(StateError::UndeclaredClassHash(*DUMMY_CLASS_HASH)), + *DUMMY_CLASS_HASH, )] #[case::class_not_declared( Ok(None), Ok(false), - Err(StateError::UndeclaredClassHash(*DUMMY_CLASS_HASH)) + Err(StateError::UndeclaredClassHash(*DUMMY_CLASS_HASH)), + *DUMMY_CLASS_HASH, +)] +// TODO(shahak): Put cairo 0 class here to better illustrate the possible scenario. +#[case::class_in_whitelist( + Ok(Some(ContractClass::V1((dummy_casm_contract_class(), SierraVersion::default())))), + Ok(false), + Ok(RunnableCompiledClass::V1((dummy_casm_contract_class(), SierraVersion::default()).try_into().unwrap())), + OLD_DEPLOY_CLASS_HASH_WHITELIST[0], )] #[tokio::test] async fn test_get_compiled_class( #[case] class_manager_client_result: ClassManagerClientResult>, #[case] sync_client_result: StateSyncClientResult, #[case] expected_result: StateResult, + #[case] class_hash: ClassHash, ) { let mut mock_state_sync_client = MockStateSyncClient::new(); let mut mock_class_manager_client = MockClassManagerClient::new(); - let class_hash = *DUMMY_CLASS_HASH; let block_number = BlockNumber(1); mock_class_manager_client @@ -285,6 +295,7 @@ async fn test_get_compiled_class_panics_when_class_exists_in_sync_but_not_in_cla Ok(None), Ok(true), Err(StateError::UndeclaredClassHash(*DUMMY_CLASS_HASH)), + *DUMMY_CLASS_HASH, ) .await; } From 7a47b7227876c3a5e0fb0425d6ece885d8d18b75 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 21 Sep 2025 17:17:36 +0300 Subject: [PATCH 026/313] apollo_dashboard: change overview panel of sync status (#9405) --- crates/apollo_dashboard/resources/dev_grafana.json | 6 +++--- crates/apollo_dashboard/src/dashboard_definitions.rs | 9 +++------ crates/apollo_dashboard/src/panels/consensus.rs | 2 +- crates/apollo_dashboard/src/panels/state_sync.rs | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 5d013e2e5bf..990572a1d25 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -46,11 +46,11 @@ } }, { - "title": "Sync Diff From Central", - "description": "The number of blocks that were not fully synced yet", + "title": "Consensus Height Diff From Sync", + "description": "The difference between the consensus height and the sync height", "type": "timeseries", "exprs": [ - "apollo_central_sync_central_block_marker{cluster=~\"$cluster\", namespace=~\"$namespace\"} - apollo_state_sync_class_manager_marker{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + "(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"} - apollo_state_sync_class_manager_marker{cluster=~\"$cluster\", namespace=~\"$namespace\"})" ], "extra_params": {} }, diff --git a/crates/apollo_dashboard/src/dashboard_definitions.rs b/crates/apollo_dashboard/src/dashboard_definitions.rs index 69f5ee5a396..902fadc6026 100644 --- a/crates/apollo_dashboard/src/dashboard_definitions.rs +++ b/crates/apollo_dashboard/src/dashboard_definitions.rs @@ -16,6 +16,7 @@ use crate::panels::consensus::{ get_cende_row, get_consensus_p2p_row, get_consensus_row, + get_panel_consensus_block_number_diff_from_sync, get_panel_consensus_block_time_avg, get_panel_consensus_round, }; @@ -30,11 +31,7 @@ use crate::panels::mempool::get_mempool_row; use crate::panels::mempool_p2p::get_mempool_p2p_row; use crate::panels::pod_metrics::get_pod_metrics_row; use crate::panels::sierra_compiler::get_compile_to_casm_row; -use crate::panels::state_sync::{ - get_panel_state_sync_diff_from_central, - get_state_sync_p2p_row, - get_state_sync_row, -}; +use crate::panels::state_sync::{get_state_sync_p2p_row, get_state_sync_row}; use crate::panels::storage::get_storage_row; use crate::panels::tokio::get_tokio_row; @@ -52,7 +49,7 @@ fn get_overview_row() -> Row { get_panel_consensus_round(), get_panel_http_server_transactions_received_rate(), get_panel_batched_transactions_rate(), - get_panel_state_sync_diff_from_central(), + get_panel_consensus_block_number_diff_from_sync(), get_panel_gateway_add_tx_failure_by_reason(), ], ) diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index ff874ace6a2..d20c0bff947 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -64,7 +64,7 @@ fn get_panel_consensus_block_number() -> Panel { .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } -fn get_panel_consensus_block_number_diff_from_sync() -> Panel { +pub(crate) fn get_panel_consensus_block_number_diff_from_sync() -> Panel { Panel::new( "Consensus Height Diff From Sync", "The difference between the consensus height and the sync height", diff --git a/crates/apollo_dashboard/src/panels/state_sync.rs b/crates/apollo_dashboard/src/panels/state_sync.rs index f2e7c693bc2..ea643db5844 100644 --- a/crates/apollo_dashboard/src/panels/state_sync.rs +++ b/crates/apollo_dashboard/src/panels/state_sync.rs @@ -40,7 +40,7 @@ fn get_panel_state_sync_body_marker() -> Panel { PanelType::Stat, ) } -pub(crate) fn get_panel_state_sync_diff_from_central() -> Panel { +fn get_panel_state_sync_diff_from_central() -> Panel { Panel::new( "Sync Diff From Central", "The number of blocks that were not fully synced yet", From 29321640fa8465f8282516a132284a3e81af5375 Mon Sep 17 00:00:00 2001 From: ron-starkware Date: Sun, 21 Sep 2025 17:29:03 +0300 Subject: [PATCH 027/313] apollo_dashboard: Show name in Grafana panel when missing (#9397) --- deployments/monitoring/src/builders/dashboard_builder.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/deployments/monitoring/src/builders/dashboard_builder.py b/deployments/monitoring/src/builders/dashboard_builder.py index 19bec0dbe27..25094876013 100755 --- a/deployments/monitoring/src/builders/dashboard_builder.py +++ b/deployments/monitoring/src/builders/dashboard_builder.py @@ -89,9 +89,6 @@ def create_grafana_panel(panel: dict, panel_id: int, y_position: int, x_position } ] }, - "options": { - "showPercentChange": show_percent_change - }, "links": ( [{"url": link, "title": "GCP Logs", "targetBlank": True}] ), @@ -114,6 +111,12 @@ def create_grafana_panel(panel: dict, panel_id: int, y_position: int, x_position if thresholds: grafana_panel["fieldConfig"]["defaults"]["color"] = {"mode": "thresholds"} + if panel["type"] == "stat": + grafana_panel["options"] = { + "textMode": "value_and_name", + "showPercentChange": show_percent_change, + } + return grafana_panel def remove_cluster_and_namespace_from_display_name(): From 71be6473ec0c866caddb56c104cf730d33437290 Mon Sep 17 00:00:00 2001 From: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> Date: Thu, 25 Sep 2025 08:16:43 +0300 Subject: [PATCH 028/313] apollo_mempool: Remove FailedAddTxChecks metric variant, already reported in the GW in detail (#9403) --- crates/apollo_mempool/src/mempool.rs | 17 ++++++--- crates/apollo_mempool/src/mempool_test.rs | 3 +- crates/apollo_mempool/src/metrics.rs | 45 +---------------------- crates/apollo_mempool/src/test_utils.rs | 6 --- 4 files changed, 13 insertions(+), 58 deletions(-) diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index fb11847add7..e4d615693e3 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -15,7 +15,11 @@ use indexmap::IndexSet; use rand::{thread_rng, Rng}; use starknet_api::block::GasPrice; use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::rpc_transaction::{InternalRpcTransaction, InternalRpcTransactionWithoutTxHash}; +use starknet_api::rpc_transaction::{ + InternalRpcTransaction, + InternalRpcTransactionLabelValue, + InternalRpcTransactionWithoutTxHash, +}; use starknet_api::transaction::fields::Tip; use starknet_api::transaction::TransactionHash; use tracing::{debug, info, instrument, trace}; @@ -27,12 +31,13 @@ use crate::metrics::{ metric_count_expired_txs, metric_count_rejected_txs, metric_set_get_txs_size, - MempoolMetricHandle, + LABEL_NAME_TX_TYPE, MEMPOOL_DELAYED_DECLARES_SIZE, MEMPOOL_PENDING_QUEUE_SIZE, MEMPOOL_POOL_SIZE, MEMPOOL_PRIORITY_QUEUE_SIZE, MEMPOOL_TOTAL_SIZE_BYTES, + MEMPOOL_TRANSACTIONS_RECEIVED, TRANSACTION_TIME_SPENT_UNTIL_BATCHED, }; use crate::transaction_pool::TransactionPool; @@ -343,9 +348,6 @@ impl Mempool { err )] pub fn add_tx(&mut self, args: AddTransactionArgs) -> MempoolResult<()> { - let mut metric_handle = MempoolMetricHandle::new(&args.tx.tx); - metric_handle.count_transaction_received(); - // First remove old transactions from the pool. let mut account_nonce_updates = self.remove_expired_txs(); self.add_ready_declares(); @@ -358,7 +360,10 @@ impl Mempool { self.handle_capacity_overflow(&args.tx, args.account_state.nonce)?; } - metric_handle.transaction_inserted(); + MEMPOOL_TRANSACTIONS_RECEIVED.increment( + 1, + &[(LABEL_NAME_TX_TYPE, InternalRpcTransactionLabelValue::from(&args.tx.tx).into())], + ); // May override a removed queued nonce with the received account nonce or the account's // state nonce. diff --git a/crates/apollo_mempool/src/mempool_test.rs b/crates/apollo_mempool/src/mempool_test.rs index 0837889014c..5aa5c69e725 100644 --- a/crates/apollo_mempool/src/mempool_test.rs +++ b/crates/apollo_mempool/src/mempool_test.rs @@ -1234,12 +1234,11 @@ fn metrics_correctness() { commit_block(&mut mempool, [("0x9", 1)], []); let expected_metrics = MempoolMetrics { - txs_received_invoke: 9, + txs_received_invoke: 8, txs_received_declare: 2, txs_received_deploy_account: 0, txs_committed: 2, txs_dropped_expired: 1, - txs_dropped_failed_add_tx_checks: 1, txs_dropped_rejected: 1, txs_dropped_evicted: 1, pool_size: 4, diff --git a/crates/apollo_mempool/src/metrics.rs b/crates/apollo_mempool/src/metrics.rs index 73d198da2b4..b2367adad05 100644 --- a/crates/apollo_mempool/src/metrics.rs +++ b/crates/apollo_mempool/src/metrics.rs @@ -7,10 +7,7 @@ use apollo_infra::metrics::{ }; use apollo_mempool_types::mempool_types::MEMPOOL_REQUEST_LABELS; use apollo_metrics::{define_infra_metrics, define_metrics, generate_permutation_labels}; -use starknet_api::rpc_transaction::{ - InternalRpcTransactionLabelValue, - InternalRpcTransactionWithoutTxHash, -}; +use starknet_api::rpc_transaction::InternalRpcTransactionLabelValue; use strum::{EnumVariantNames, VariantNames}; use strum_macros::{EnumIter, IntoStaticStr}; @@ -45,54 +42,14 @@ generate_permutation_labels! { (LABEL_NAME_DROP_REASON, DropReason), } -enum TransactionStatus { - AddedToMempool, - Dropped, -} - #[derive(IntoStaticStr, EnumIter, EnumVariantNames)] #[strum(serialize_all = "snake_case")] pub enum DropReason { - FailedAddTxChecks, Expired, Rejected, Evicted, } -pub(crate) struct MempoolMetricHandle { - tx_type: InternalRpcTransactionLabelValue, - tx_status: TransactionStatus, -} - -impl MempoolMetricHandle { - pub fn new(tx: &InternalRpcTransactionWithoutTxHash) -> Self { - let tx_type = InternalRpcTransactionLabelValue::from(tx); - Self { tx_type, tx_status: TransactionStatus::Dropped } - } - - fn label(&self) -> Vec<(&'static str, &'static str)> { - vec![(LABEL_NAME_TX_TYPE, self.tx_type.into())] - } - - pub fn count_transaction_received(&self) { - MEMPOOL_TRANSACTIONS_RECEIVED.increment(1, &self.label()); - } - - pub fn transaction_inserted(&mut self) { - self.tx_status = TransactionStatus::AddedToMempool; - } -} - -impl Drop for MempoolMetricHandle { - fn drop(&mut self) { - match self.tx_status { - TransactionStatus::Dropped => MEMPOOL_TRANSACTIONS_DROPPED - .increment(1, &[(LABEL_NAME_DROP_REASON, DropReason::FailedAddTxChecks.into())]), - TransactionStatus::AddedToMempool => {} - } - } -} - pub(crate) fn metric_count_expired_txs(n_txs: usize) { MEMPOOL_TRANSACTIONS_DROPPED.increment( n_txs.try_into().expect("The number of expired_txs should fit u64"), diff --git a/crates/apollo_mempool/src/test_utils.rs b/crates/apollo_mempool/src/test_utils.rs index d16e803c3e7..c993eb79272 100644 --- a/crates/apollo_mempool/src/test_utils.rs +++ b/crates/apollo_mempool/src/test_utils.rs @@ -287,7 +287,6 @@ pub struct MempoolMetrics { pub txs_received_deploy_account: u64, pub txs_committed: u64, pub txs_dropped_expired: u64, - pub txs_dropped_failed_add_tx_checks: u64, pub txs_dropped_rejected: u64, pub txs_dropped_evicted: u64, pub pool_size: u64, @@ -325,11 +324,6 @@ impl MempoolMetrics { self.txs_dropped_expired, &[(LABEL_NAME_DROP_REASON, DropReason::Expired.into())], ); - MEMPOOL_TRANSACTIONS_DROPPED.assert_eq( - metrics, - self.txs_dropped_failed_add_tx_checks, - &[(LABEL_NAME_DROP_REASON, DropReason::FailedAddTxChecks.into())], - ); MEMPOOL_TRANSACTIONS_DROPPED.assert_eq( metrics, self.txs_dropped_rejected, From 434620a89624420f13986a3d71572859a1d9148a Mon Sep 17 00:00:00 2001 From: nimrod-starkware <143319383+nimrod-starkware@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:53:52 +0300 Subject: [PATCH 029/313] starknet_committer: fix flamegraph script (#9408) --- scripts/committer/generate_committer_flamegraph.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) mode change 100644 => 100755 scripts/committer/generate_committer_flamegraph.sh diff --git a/scripts/committer/generate_committer_flamegraph.sh b/scripts/committer/generate_committer_flamegraph.sh old mode 100644 new mode 100755 index 6eee9ead28f..0f558a70a6e --- a/scripts/committer/generate_committer_flamegraph.sh +++ b/scripts/committer/generate_committer_flamegraph.sh @@ -7,7 +7,10 @@ fi # Restore security level in perf_event_paranoid at the end. ORIGINAL_PARANOID=$(echo $(sysctl kernel.perf_event_paranoid) | grep -o '[0-9]$') -trap 'sudo sysctl kernel.perf_event_paranoid=$ORIGINAL_PARANOID' EXIT SIGINT SIGTERM + +# Create temporary file for committer input +TEMP_INPUT_FILE=$(mktemp) +trap 'sudo sysctl kernel.perf_event_paranoid=$ORIGINAL_PARANOID; rm -f "$TEMP_INPUT_FILE"' EXIT SIGINT SIGTERM if ! command -v jq; then cargo install jq @@ -24,4 +27,8 @@ BENCH_INPUT_FILES_PREFIX=$(cat ${ROOT_DIR}/crates/starknet_committer_and_os_cli/ # Lower security level in perf_event_paranoid to 2 to allow cargo to use perf without running on root. sudo sysctl kernel.perf_event_paranoid=2 -gcloud storage cat gs://committer-testing-artifacts/${BENCH_INPUT_FILES_PREFIX}/committer_flow_inputs.json | jq -r .committer_input | CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -p starknet_committer_and_os_cli -- commit +# Download and extract committer input to temporary file +gcloud storage cat gs://committer-testing-artifacts/${BENCH_INPUT_FILES_PREFIX}/committer_flow_inputs.json | jq -r .committer_input > "$TEMP_INPUT_FILE" + +# Run flamegraph with the temporary file as input +CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -p starknet_committer_and_os_cli -- committer commit --input-path "$TEMP_INPUT_FILE" From 3886ca564489761b8dc418ded888c6aa4209192d Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Thu, 25 Sep 2025 15:08:10 +0300 Subject: [PATCH 030/313] apollo_batcher: log the error details when L1 handler tx fails to validate (#9413) --- crates/apollo_batcher/src/block_builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index 51ea4e30b2e..f5bc11ed234 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -87,7 +87,7 @@ pub enum FailOnErrorCause { DeadlineReached, #[error("Transaction failed: {0}")] TransactionFailed(BlockifierTransactionExecutorError), - #[error("L1 Handler transaction validation failed")] + #[error("L1 Handler transaction validation failed: {0}")] L1HandlerTransactionValidationFailed(TransactionProviderError), } From 93947b2208493329ee043aa44a7613fee6cf5c8e Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Thu, 25 Sep 2025 16:09:42 +0300 Subject: [PATCH 031/313] apollo_l1_provider: prevent going back to lower L1 block number (#9423) --- crates/apollo_l1_provider/src/l1_scraper.rs | 9 ++++ .../src/l1_scraper_tests.rs | 54 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/crates/apollo_l1_provider/src/l1_scraper.rs b/crates/apollo_l1_provider/src/l1_scraper.rs index 0b095545959..fa9cc3181be 100644 --- a/crates/apollo_l1_provider/src/l1_scraper.rs +++ b/crates/apollo_l1_provider/src/l1_scraper.rs @@ -117,6 +117,15 @@ impl L1Scraper { L1ScraperError::finality_too_high(self.config.finality, &self.base_layer).await ); }; + // This can happen if, e.g., changing base layers. Should ignore and try scraping again. + if latest_l1_block.number <= self.last_l1_block_processed.number { + warn!( + "Latest L1 block number {} is not greater than the last processed L1 block number \ + {}. Ignoring, will try again on the next interval.", + latest_l1_block.number, self.last_l1_block_processed.number + ); + return Ok((self.last_l1_block_processed, vec![])); + } let scraping_start_number = self.last_l1_block_processed.number + 1; let scraping_result = self diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 1ee16afc133..ff7b1c4a950 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -657,6 +657,60 @@ async fn l1_reorg_block_number(mut dummy_base_layer: MockBaseLayerContract) { ); } +#[tokio::test] +async fn latest_block_number_goes_down() { + // Setup. + const L1_LATEST_BLOCK_NUMBER: u64 = 10; + const L1_BLOCK_HASH: L1BlockHash = L1BlockHash([123; 32]); + const L1_BAD_LATEST_NUMBER: u64 = 5; + + let mut l1_provider_client = MockL1ProviderClient::default(); + l1_provider_client.expect_add_events().returning(|_| Ok(())); + + let mut dummy_base_layer: MockBaseLayerContract = MockBaseLayerContract::new(); + + // This should always be returned, even if we set the "response" to a lower block number. + let expected_block_reference = + L1BlockReference { number: L1_LATEST_BLOCK_NUMBER, hash: L1_BLOCK_HASH }; + + let latest_l1_block_response = Arc::new(Mutex::new(expected_block_reference)); + let latest_l1_block_response_clone = latest_l1_block_response.clone(); + dummy_base_layer + .expect_latest_l1_block() + .times(2) + .returning(move |_| Ok(Some(*latest_l1_block_response_clone.lock().unwrap()))); + + dummy_base_layer.expect_events().times(1).returning(|_, _| Ok(vec![])); + + dummy_base_layer + .expect_l1_block_at() + .returning(move |number| Ok(Some(L1BlockReference { number, hash: L1_BLOCK_HASH }))); + + let mut scraper = L1Scraper::new( + L1ScraperConfig::default(), + Arc::new(l1_provider_client), + dummy_base_layer, + event_identifiers_to_track(), + L1BlockReference { number: 0, hash: L1_BLOCK_HASH }, + ) + .await + .unwrap(); + + // Test. + // can send messages to the provider. + // This should also set the scraper's last_l1_block_processed to block number 10. + assert_eq!(scraper.send_events_to_l1_provider().await, Ok(())); + + // Simulate a base layer returning a lower block number. + latest_l1_block_response.lock().unwrap().number = L1_BAD_LATEST_NUMBER; + + // Make sure we don't hit the reorg error in this scenario. + scraper.assert_no_l1_reorgs().await.unwrap(); + + // Should ignore and try again on the next interval, returning the same block reference. + assert_eq!(scraper.fetch_events().await, Ok((expected_block_reference, vec![]))); +} + #[test] #[ignore = "similar to backlog_happy_flow, only shorter, and sprinkle some start_block/get_txs \ attempts while its bootstrapping (and assert failure on height), then assert that they \ From d10976cc8ad56739e6690e9bd3426d285104cd1c Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Thu, 25 Sep 2025 16:21:24 +0300 Subject: [PATCH 032/313] papyrus_base_layer: avoid printing API keys (#9425) --- .../papyrus_base_layer/src/monitored_base_layer.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/papyrus_base_layer/src/monitored_base_layer.rs b/crates/papyrus_base_layer/src/monitored_base_layer.rs index 7c1e1fbf762..0040d08a014 100644 --- a/crates/papyrus_base_layer/src/monitored_base_layer.rs +++ b/crates/papyrus_base_layer/src/monitored_base_layer.rs @@ -49,13 +49,14 @@ impl MonitoredBaseLayer { /// of an external HTTP call. async fn ensure_operational(&self) -> Result<(), MonitoredBaseLayerError> { let active_l1_endpoint = self.monitor.get_active_l1_endpoint().await; + let current_node_url = self.current_node_url.read().await; match active_l1_endpoint { - Ok(new_node_url) if new_node_url != *self.current_node_url.read().await => { + Ok(new_node_url) if new_node_url != *current_node_url => { info!( "L1 endpoint {} is no longer operational, switching to new operational L1 \ endpoint: {}", - self.current_node_url.read().await, - &new_node_url + to_safe_string(&Url::parse(current_node_url.as_ref()).unwrap()), + to_safe_string(&new_node_url) ); let mut base_layer = self.base_layer.lock().await; @@ -224,3 +225,10 @@ impl std::fmt::Debug for MonitoredBaseLayerE } } } + +// TODO(guyn): this is duplicated code from apollo_l1_endpoint_monitor/src/monitor.rs +// TODO(guyn): when it is moved to apollo_infra_utils, we should import it instead. +fn to_safe_string(url: &Url) -> String { + // We print only the hostnames to avoid leaking the API keys. + url.host().map_or_else(|| "no host in url!".to_string(), |host| host.to_string()) +} From a341d2591df5abb25bab0c7c26cfcc48ef809aeb Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Sun, 28 Sep 2025 13:31:59 +0300 Subject: [PATCH 033/313] apollo_batcher: only propose L1 txs once every N proposals (#9331) --- crates/apollo_batcher/src/batcher.rs | 17 +++++- crates/apollo_batcher/src/batcher_test.rs | 59 ++++++++++++++++++- crates/apollo_batcher/src/config.rs | 8 +++ crates/apollo_batcher/src/test_utils.rs | 9 ++- .../src/transaction_provider.rs | 22 ++++++- .../src/transaction_provider_test.rs | 22 ++++++- .../resources/app_configs/batcher_config.json | 3 +- .../apollo_node/resources/config_schema.json | 5 ++ 8 files changed, 138 insertions(+), 7 deletions(-) diff --git a/crates/apollo_batcher/src/batcher.rs b/crates/apollo_batcher/src/batcher.rs index 6d413db5c24..ceb9f450f0d 100644 --- a/crates/apollo_batcher/src/batcher.rs +++ b/crates/apollo_batcher/src/batcher.rs @@ -79,7 +79,11 @@ use crate::pre_confirmed_block_writer::{ PreconfirmedBlockWriterTrait, }; use crate::pre_confirmed_cende_client::PreconfirmedCendeClientTrait; -use crate::transaction_provider::{ProposeTransactionProvider, ValidateTransactionProvider}; +use crate::transaction_provider::{ + ProposeTransactionProvider, + TxProviderPhase, + ValidateTransactionProvider, +}; use crate::utils::{ deadline_as_instant, proposal_status_from, @@ -128,6 +132,9 @@ pub struct Batcher { /// Each stream is kept until SendProposalContent::Finish/Abort is received, or a new height is /// started. validate_tx_streams: HashMap, + + /// Number of proposals made since coming online. + proposals_counter: u64, } impl Batcher { @@ -157,6 +164,7 @@ impl Batcher { executed_proposals: Arc::new(Mutex::new(HashMap::new())), propose_tx_streams: HashMap::new(), validate_tx_streams: HashMap::new(), + proposals_counter: 0, } } @@ -235,11 +243,17 @@ impl Batcher { BATCHER_L1_PROVIDER_ERRORS.increment(1); }); + let start_phase = if self.proposals_counter % self.config.propose_l1_txs_every == 0 { + TxProviderPhase::L1 + } else { + TxProviderPhase::Mempool + }; let tx_provider = ProposeTransactionProvider::new( self.mempool_client.clone(), self.l1_provider_client.clone(), self.config.max_l1_handler_txs_per_block_proposal, propose_block_input.block_info.block_number, + start_phase, ); // A channel to receive the transactions included in the proposed block. @@ -293,6 +307,7 @@ impl Batcher { propose_block_input.proposal_id ); LAST_PROPOSED_BLOCK_HEIGHT.set_lossy(block_number.0); + self.proposals_counter += 1; Ok(()) } diff --git a/crates/apollo_batcher/src/batcher_test.rs b/crates/apollo_batcher/src/batcher_test.rs index 8cccf1bd3a3..521ec8cc54a 100644 --- a/crates/apollo_batcher/src/batcher_test.rs +++ b/crates/apollo_batcher/src/batcher_test.rs @@ -73,6 +73,7 @@ use crate::pre_confirmed_block_writer::{ MockPreconfirmedBlockWriterTrait, }; use crate::test_utils::{ + test_l1_handler_txs, test_txs, verify_indexed_execution_infos, FakeProposeBlockBuilder, @@ -214,11 +215,12 @@ fn mock_create_builder_for_propose_block( build_block_result: BlockBuilderResult, ) { block_builder_factory.expect_create_block_builder().times(1).return_once( - move |_, _, _, output_content_sender, _, _, _| { + move |_, _, tx_provider, output_content_sender, _, _, _| { let block_builder = FakeProposeBlockBuilder { output_content_sender: output_content_sender.unwrap(), output_txs, build_block_result: Some(build_block_result), + tx_provider, }; Ok((Box::new(block_builder), abort_signal_sender())) }, @@ -690,6 +692,61 @@ async fn propose_block_full_flow() { assert_proposal_metrics(&metrics, 1, 1, 0, 0); } +#[rstest] +#[tokio::test] +async fn multiple_proposals_with_l1_every_n_proposals() { + const N_PROPOSALS: usize = 4; + const PROPOSALS_L1_MODULATOR: usize = 3; + + // Send a regular tx and an l1 handler tx. + let mut expected_streamed_txs = test_txs(0..1); + expected_streamed_txs.extend(test_l1_handler_txs(1..2)); + let mut block_builder_factory = MockBlockBuilderFactoryTrait::new(); + for _ in 0..N_PROPOSALS { + mock_create_builder_for_propose_block( + &mut block_builder_factory, + expected_streamed_txs.clone(), + Ok(BlockExecutionArtifacts::create_for_testing()), + ); + } + + let mut mock_dependencies = MockDependencies { block_builder_factory, ..Default::default() }; + mock_dependencies.storage_writer.expect_revert_block().times(N_PROPOSALS).returning(|_| ()); + + mock_dependencies + .l1_provider_client + .expect_start_block() + .times(N_PROPOSALS) + .returning(|_, _| Ok(())); + + let mut batcher = create_batcher(mock_dependencies).await; + // Only propose L1 txs every PROPOSALS_L1_MODULATOR proposals. + batcher.config.propose_l1_txs_every = PROPOSALS_L1_MODULATOR.try_into().unwrap(); + + for i in 0..N_PROPOSALS { + batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap(); + batcher.propose_block(propose_block_input(PROPOSAL_ID)).await.unwrap(); + let content = batcher + .get_proposal_content(GetProposalContentInput { proposal_id: PROPOSAL_ID }) + .await + .unwrap() + .content; + let txs = assert_matches!(content, GetProposalContent::Txs(txs) => txs); + + if i % PROPOSALS_L1_MODULATOR == 0 { + assert_eq!(txs, expected_streamed_txs); + } else { + assert_eq!(txs, test_txs(0..1)); + } + + batcher.await_active_proposal(DUMMY_FINAL_N_EXECUTED_TXS).await.unwrap(); + batcher + .revert_block(RevertBlockInput { height: INITIAL_HEIGHT.prev().unwrap() }) + .await + .unwrap(); + } +} + #[rstest] #[tokio::test] async fn get_height() { diff --git a/crates/apollo_batcher/src/config.rs b/crates/apollo_batcher/src/config.rs index 3700738a61d..86da97ab951 100644 --- a/crates/apollo_batcher/src/config.rs +++ b/crates/apollo_batcher/src/config.rs @@ -22,6 +22,7 @@ pub struct BatcherConfig { pub contract_class_manager_config: ContractClassManagerConfig, pub max_l1_handler_txs_per_block_proposal: usize, pub pre_confirmed_cende_config: PreconfirmedCendeConfig, + pub propose_l1_txs_every: u64, } impl SerializeConfig for BatcherConfig { @@ -47,6 +48,12 @@ impl SerializeConfig for BatcherConfig { "The maximum number of L1 handler transactions to include in a block proposal.", ParamPrivacyInput::Public, ), + ser_param( + "propose_l1_txs_every", + &self.propose_l1_txs_every, + "Only propose L1 transactions every N proposals.", + ParamPrivacyInput::Public, + ), ]); dump.append(&mut prepend_sub_config_name(self.storage.dump(), "storage")); dump.append(&mut prepend_sub_config_name( @@ -89,6 +96,7 @@ impl Default for BatcherConfig { contract_class_manager_config: ContractClassManagerConfig::default(), max_l1_handler_txs_per_block_proposal: 3, pre_confirmed_cende_config: PreconfirmedCendeConfig::default(), + propose_l1_txs_every: 1, // Default is to propose L1 transactions every proposal. } } } diff --git a/crates/apollo_batcher/src/test_utils.rs b/crates/apollo_batcher/src/test_utils.rs index b54a1c2d3d1..171d3eb221e 100644 --- a/crates/apollo_batcher/src/test_utils.rs +++ b/crates/apollo_batcher/src/test_utils.rs @@ -21,7 +21,7 @@ use crate::block_builder::{ BlockExecutionArtifacts, BlockTransactionExecutionData, }; -use crate::transaction_provider::TransactionProvider; +use crate::transaction_provider::{TransactionProvider, TxProviderPhase}; pub const EXECUTION_INFO_LEN: usize = 10; pub const DUMMY_FINAL_N_EXECUTED_TXS: usize = 12; @@ -58,12 +58,19 @@ pub(crate) struct FakeProposeBlockBuilder { pub output_content_sender: UnboundedSender, pub output_txs: Vec, pub build_block_result: Option>, + pub tx_provider: Box, } #[async_trait] impl BlockBuilderTrait for FakeProposeBlockBuilder { async fn build_block(&mut self) -> BlockBuilderResult { for tx in &self.output_txs { + // Skip L1 txs if the tx_provider was set to mempool phase. + if matches!(tx, InternalConsensusTransaction::L1Handler(_)) + && self.tx_provider.phase() == TxProviderPhase::Mempool + { + continue; + } self.output_content_sender.send(tx.clone()).unwrap(); } diff --git a/crates/apollo_batcher/src/transaction_provider.rs b/crates/apollo_batcher/src/transaction_provider.rs index 7276230daa2..728c49e91b1 100644 --- a/crates/apollo_batcher/src/transaction_provider.rs +++ b/crates/apollo_batcher/src/transaction_provider.rs @@ -48,6 +48,10 @@ pub trait TransactionProvider: Send { /// Once `Some()` is returned for the first time, future calls to this method may return `None`. /// Returns `None` in propose mode ([ProposeTransactionProvider]). async fn get_final_n_executed_txs(&mut self) -> Option; + + // TODO(guyn): remove this after refactoring the batcher tests. + #[cfg(test)] + fn phase(&self) -> TxProviderPhase; } #[derive(Clone)] @@ -61,8 +65,9 @@ pub struct ProposeTransactionProvider { } // Keeps track of whether we need to fetch L1 handler transactions or mempool transactions. +// TODO(guyn): make the phase pub(crate) after refactoring the batcher tests. #[derive(Clone, Debug, PartialEq)] -enum TxProviderPhase { +pub enum TxProviderPhase { L1, Mempool, } @@ -73,13 +78,14 @@ impl ProposeTransactionProvider { l1_provider_client: SharedL1ProviderClient, max_l1_handler_txs_per_block: usize, height: BlockNumber, + start_phase: TxProviderPhase, ) -> Self { Self { mempool_client, l1_provider_client, max_l1_handler_txs_per_block, height, - phase: TxProviderPhase::L1, + phase: start_phase, n_l1handler_txs_so_far: 0, } } @@ -148,6 +154,12 @@ impl TransactionProvider for ProposeTransactionProvider { async fn get_final_n_executed_txs(&mut self) -> Option { None } + + // TODO(guyn): remove this after refactoring the batcher tests. + #[cfg(test)] + fn phase(&self) -> TxProviderPhase { + self.phase.clone() + } } pub struct ValidateTransactionProvider { @@ -208,4 +220,10 @@ impl TransactionProvider for ValidateTransactionProvider { // Return None if the receiver is empty or closed unexpectedly. self.final_n_executed_txs_receiver.try_recv().ok() } + + // TODO(guyn): remove this after refactoring the batcher tests. + #[cfg(test)] + fn phase(&self) -> TxProviderPhase { + panic!("Phase is only relevant to proposing transactions.") + } } diff --git a/crates/apollo_batcher/src/transaction_provider_test.rs b/crates/apollo_batcher/src/transaction_provider_test.rs index d2842cd9171..7d824339098 100644 --- a/crates/apollo_batcher/src/transaction_provider_test.rs +++ b/crates/apollo_batcher/src/transaction_provider_test.rs @@ -19,6 +19,7 @@ use crate::transaction_provider::{ ProposeTransactionProvider, TransactionProvider, TransactionProviderError, + TxProviderPhase, ValidateTransactionProvider, }; @@ -63,15 +64,24 @@ impl MockDependencies { } } - fn propose_tx_provider(self) -> ProposeTransactionProvider { + fn propose_tx_provider_with_phase(self, phase: TxProviderPhase) -> ProposeTransactionProvider { ProposeTransactionProvider::new( Arc::new(self.mempool_client), Arc::new(self.l1_provider_client), MAX_L1_HANDLER_TXS_PER_BLOCK, HEIGHT, + phase, ) } + fn propose_tx_provider(self) -> ProposeTransactionProvider { + self.propose_tx_provider_with_phase(TxProviderPhase::L1) + } + + fn propose_tx_provider_mempool_phase(self) -> ProposeTransactionProvider { + self.propose_tx_provider_with_phase(TxProviderPhase::Mempool) + } + fn validate_tx_provider(self) -> ValidateTransactionProvider { self.validate_tx_provider_with_final_n_executed_txs().0 } @@ -203,6 +213,16 @@ async fn no_more_l1_handler(mut mock_dependencies: MockDependencies) { assert!(data.iter().all(|tx| matches!(tx, InternalConsensusTransaction::RpcTransaction(_)))); } +#[rstest] +#[tokio::test] +async fn provider_in_mempool_phase_no_l1(mut mock_dependencies: MockDependencies) { + mock_dependencies.expect_get_mempool_txs(MAX_TXS_PER_FETCH); + let mut tx_provider = mock_dependencies.propose_tx_provider_mempool_phase(); + let txs = tx_provider.get_txs(MAX_TXS_PER_FETCH).await.unwrap(); + let data = assert_matches!(txs, txs if txs.len() == MAX_TXS_PER_FETCH => txs); + assert!(data.iter().all(|tx| matches!(tx, InternalConsensusTransaction::RpcTransaction(_)))); +} + #[rstest] #[tokio::test] async fn validate_flow(mut mock_dependencies: MockDependencies) { diff --git a/crates/apollo_deployments/resources/app_configs/batcher_config.json b/crates/apollo_deployments/resources/app_configs/batcher_config.json index 67e63493090..c087e7aa50e 100644 --- a/crates/apollo_deployments/resources/app_configs/batcher_config.json +++ b/crates/apollo_deployments/resources/app_configs/batcher_config.json @@ -49,5 +49,6 @@ "batcher_config.storage.mmap_file_config.growth_step": 2147483648, "batcher_config.storage.mmap_file_config.max_object_size": 1073741824, "batcher_config.storage.mmap_file_config.max_size": 1099511627776, - "batcher_config.storage.scope": "StateOnly" + "batcher_config.storage.scope": "StateOnly", + "batcher_config.propose_l1_txs_every": 10 } diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 4301adf572b..0775a346d1b 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -274,6 +274,11 @@ "pointer_target": "recorder_url", "privacy": "Private" }, + "batcher_config.propose_l1_txs_every": { + "description": "Only propose L1 transactions every N proposals.", + "privacy": "Public", + "value": 1 + }, "batcher_config.storage.db_config.chain_id": { "description": "The chain to follow. For more details see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#chain-id.", "pointer_target": "chain_id", From 5de05d977a11676ac176eb37c9b409080edc8a79 Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Sun, 28 Sep 2025 16:00:54 +0300 Subject: [PATCH 034/313] apollo_batcher: proposals_counter=1 to allow system startup before sending L1 txs (#9439) --- crates/apollo_batcher/src/batcher.rs | 3 ++- crates/apollo_batcher/src/batcher_test.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/apollo_batcher/src/batcher.rs b/crates/apollo_batcher/src/batcher.rs index ceb9f450f0d..02c5f06ce45 100644 --- a/crates/apollo_batcher/src/batcher.rs +++ b/crates/apollo_batcher/src/batcher.rs @@ -164,7 +164,8 @@ impl Batcher { executed_proposals: Arc::new(Mutex::new(HashMap::new())), propose_tx_streams: HashMap::new(), validate_tx_streams: HashMap::new(), - proposals_counter: 0, + // Allow the first few proposals to be without L1 txs while system starts up. + proposals_counter: 1, } } diff --git a/crates/apollo_batcher/src/batcher_test.rs b/crates/apollo_batcher/src/batcher_test.rs index 521ec8cc54a..271ddcdbd01 100644 --- a/crates/apollo_batcher/src/batcher_test.rs +++ b/crates/apollo_batcher/src/batcher_test.rs @@ -733,7 +733,7 @@ async fn multiple_proposals_with_l1_every_n_proposals() { .content; let txs = assert_matches!(content, GetProposalContent::Txs(txs) => txs); - if i % PROPOSALS_L1_MODULATOR == 0 { + if (i + 1) % PROPOSALS_L1_MODULATOR == 0 { assert_eq!(txs, expected_streamed_txs); } else { assert_eq!(txs, test_txs(0..1)); From 41527ffa3816b2033b56ef62ff00b08d684c045d Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Tue, 30 Sep 2025 14:21:52 +0300 Subject: [PATCH 035/313] papyrus_base_layer: do not deadlock on reading active L1 endpoint url (#9469) --- crates/papyrus_base_layer/src/monitored_base_layer.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/papyrus_base_layer/src/monitored_base_layer.rs b/crates/papyrus_base_layer/src/monitored_base_layer.rs index 0040d08a014..0451d450719 100644 --- a/crates/papyrus_base_layer/src/monitored_base_layer.rs +++ b/crates/papyrus_base_layer/src/monitored_base_layer.rs @@ -49,13 +49,16 @@ impl MonitoredBaseLayer { /// of an external HTTP call. async fn ensure_operational(&self) -> Result<(), MonitoredBaseLayerError> { let active_l1_endpoint = self.monitor.get_active_l1_endpoint().await; - let current_node_url = self.current_node_url.read().await; + let current_node_url; + { + current_node_url = self.current_node_url.read().await.clone(); + } // Drop the read lock match active_l1_endpoint { - Ok(new_node_url) if new_node_url != *current_node_url => { + Ok(new_node_url) if new_node_url != current_node_url => { info!( "L1 endpoint {} is no longer operational, switching to new operational L1 \ endpoint: {}", - to_safe_string(&Url::parse(current_node_url.as_ref()).unwrap()), + to_safe_string(¤t_node_url), to_safe_string(&new_node_url) ); From 8bc4be6db4c5b42b6bf128573c44d402cd4f02c6 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Sun, 12 Oct 2025 14:42:23 +0300 Subject: [PATCH 036/313] apollo_class_manager: simplify executable contract class size check (#9543) --- crates/apollo_compile_to_casm_types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/apollo_compile_to_casm_types/src/lib.rs b/crates/apollo_compile_to_casm_types/src/lib.rs index 223a35c189c..f81bdf36d21 100644 --- a/crates/apollo_compile_to_casm_types/src/lib.rs +++ b/crates/apollo_compile_to_casm_types/src/lib.rs @@ -57,7 +57,7 @@ impl SerializedClass { } pub fn size(&self) -> RawClassResult { - Ok(serde_json::to_string_pretty(&self.0)?.len()) + Ok(serde_json::to_string(&self.0)?.len()) } fn new(value: serde_json::Value) -> Self { From 2aaaacd677c5a67ace93f5f56e0181c525d634f7 Mon Sep 17 00:00:00 2001 From: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> Date: Wed, 15 Oct 2025 11:26:06 +0300 Subject: [PATCH 037/313] apollo_dashboard: Add a panel for Consensus Round Advanced (#9417) --- crates/apollo_dashboard/resources/dev_grafana.json | 12 ++++++++++++ crates/apollo_dashboard/src/panels/consensus.rs | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 990572a1d25..4383dad23c6 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -92,6 +92,18 @@ "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" } }, + { + "title": "Consensus Round Advanced", + "description": "The number of times the consensus round advanced (counter is increased whenever round > 0) (10m window)", + "type": "timeseries", + "exprs": [ + "increase(consensus_round_advances{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + ], + "extra_params": { + "log_query": "\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } + }, { "title": "Average Block Time", "description": "Average block time (10m window)", diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index d20c0bff947..c8be109e2a6 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -11,6 +11,7 @@ use apollo_consensus::metrics::{ CONSENSUS_PROPOSALS_VALIDATED, CONSENSUS_ROUND, CONSENSUS_ROUND_ABOVE_ZERO, + CONSENSUS_ROUND_ADVANCES, CONSENSUS_TIMEOUTS, LABEL_NAME_TIMEOUT_TYPE, }; @@ -86,6 +87,17 @@ pub(crate) fn get_panel_consensus_round() -> Panel { .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } +pub(crate) fn get_panel_consensus_round_advanced() -> Panel { + Panel::new( + "Consensus Round Advanced", + "The number of times the consensus round advanced (counter is increased whenever round > \ + 0) (10m window)", + vec![format!("increase({}[10m])", CONSENSUS_ROUND_ADVANCES.get_name_with_filter())], + PanelType::TimeSeries, + ) + .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) +} fn get_panel_consensus_round_above_zero() -> Panel { Panel::new( @@ -397,6 +409,7 @@ pub(crate) fn get_consensus_row() -> Row { vec![ get_panel_consensus_block_number(), get_panel_consensus_round(), + get_panel_consensus_round_advanced(), get_panel_consensus_block_time_avg(), get_panel_consensus_round_above_zero(), get_panel_consensus_block_number_diff_from_sync(), From 1a2a524a4c9812f441251b028dcba9f975f265c0 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Wed, 15 Oct 2025 13:00:35 +0300 Subject: [PATCH 038/313] apollo_deployments: config l1 remote connections to fast failures (#9569) --- .../resources/services/hybrid/core.json | 4 ++-- crates/apollo_deployments/src/deployments.rs | 1 + .../apollo_deployments/src/deployments/hybrid.rs | 14 ++++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/crates/apollo_deployments/resources/services/hybrid/core.json b/crates/apollo_deployments/resources/services/hybrid/core.json index c56ee43d586..df25418f58c 100644 --- a/crates/apollo_deployments/resources/services/hybrid/core.json +++ b/crates/apollo_deployments/resources/services/hybrid/core.json @@ -58,7 +58,7 @@ "components.l1_gas_price_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_gas_price_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_gas_price_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_gas_price_provider.remote_client_config.retries": 150, + "components.l1_gas_price_provider.remote_client_config.retries": 2, "components.l1_gas_price_provider.url": "sequencer-l1-service", "components.l1_gas_price_scraper.execution_mode": "Disabled", "components.l1_provider.execution_mode": "Remote", @@ -72,7 +72,7 @@ "components.l1_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_provider.remote_client_config.retries": 150, + "components.l1_provider.remote_client_config.retries": 2, "components.l1_provider.url": "sequencer-l1-service", "components.l1_scraper.execution_mode": "Disabled", "components.mempool.execution_mode": "Remote", diff --git a/crates/apollo_deployments/src/deployments.rs b/crates/apollo_deployments/src/deployments.rs index 04068511e38..634a0673099 100644 --- a/crates/apollo_deployments/src/deployments.rs +++ b/crates/apollo_deployments/src/deployments.rs @@ -3,3 +3,4 @@ pub mod distributed; pub mod hybrid; pub(crate) const IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES: usize = 0; +pub(crate) const RETRIES_FOR_L1_SERVICES: usize = 2; diff --git a/crates/apollo_deployments/src/deployments/hybrid.rs b/crates/apollo_deployments/src/deployments/hybrid.rs index 87ce6fbe126..33befd5e34c 100644 --- a/crates/apollo_deployments/src/deployments/hybrid.rs +++ b/crates/apollo_deployments/src/deployments/hybrid.rs @@ -32,7 +32,7 @@ use crate::deployment_definitions::{ NodeAndValidatorId, ServicePort, }; -use crate::deployments::IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES; +use crate::deployments::{IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES, RETRIES_FOR_L1_SERVICES}; use crate::k8s::{ get_environment_ingress_internal, get_ingress, @@ -693,6 +693,8 @@ impl HybridNodeServiceName { port, ); match self { + // Force new connections when connecting to autoscaled services. This is to ensure + // better load balancing. HybridNodeServiceName::Gateway | HybridNodeServiceName::SierraCompiler => { let remote_client_config_ref = base .remote_client_config @@ -700,11 +702,19 @@ impl HybridNodeServiceName { .expect("Remote client config should be available"); remote_client_config_ref.idle_connections = IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES } + // Fast failures when connecting to the l1 services. + HybridNodeServiceName::L1 => { + let remote_client_config_ref = base + .remote_client_config + .as_mut() + .expect("Remote client config should be available"); + remote_client_config_ref.retries = RETRIES_FOR_L1_SERVICES + } HybridNodeServiceName::Core | HybridNodeServiceName::HttpServer - | HybridNodeServiceName::L1 | HybridNodeServiceName::Mempool => {} }; + base } From e1d7511c8a3e8a1212578a0297a547a1436f7d41 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Wed, 15 Oct 2025 17:17:36 +0300 Subject: [PATCH 039/313] apollo_deployments: increase proposal timeout to 9.1 (#9582) --- .../resources/app_configs/consensus_manager_config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json index 041c2dd6c92..6a560416210 100644 --- a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json +++ b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json @@ -12,7 +12,7 @@ "consensus_manager_config.consensus_manager_config.static_config.sync_retry_interval": 1.0, "consensus_manager_config.consensus_manager_config.static_config.timeouts.precommit_timeout": 1.0, "consensus_manager_config.consensus_manager_config.static_config.timeouts.prevote_timeout": 0.3, - "consensus_manager_config.consensus_manager_config.static_config.timeouts.proposal_timeout": 6.1, + "consensus_manager_config.consensus_manager_config.static_config.timeouts.proposal_timeout": 9.1, "consensus_manager_config.context_config.block_timestamp_window_seconds": 1, "consensus_manager_config.context_config.build_proposal_margin_millis": 1000, "consensus_manager_config.context_config.builder_address": "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", @@ -43,4 +43,4 @@ "consensus_manager_config.stream_handler_config.channel_buffer_capacity": 1000, "consensus_manager_config.stream_handler_config.max_streams": 100, "consensus_manager_config.votes_topic": "consensus_votes" -} \ No newline at end of file +} From fdf746a43e75278de8dd6ba2db5b539887f69384 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 16 Oct 2025 09:51:54 +0300 Subject: [PATCH 040/313] apollo_dashboard: Add a const for round time and use it in alerts that depend on it (#9576) --- crates/apollo_dashboard/src/alert_definitions.rs | 3 +++ .../src/alert_scenarios/block_production_delay.rs | 7 +++---- .../src/alert_scenarios/block_production_halt.rs | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index 4fa119fc81c..81449a923f1 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -95,6 +95,9 @@ use crate::alerts::{ PENDING_DURATION_DEFAULT, }; +/// Alerts that depend on block time can use this value to define their rule. +pub(crate) const BLOCK_TIME_SEC: f64 = 6.0; + pub fn get_dev_alerts_json_path(alert_env_filtering: AlertEnvFiltering) -> String { format!("crates/apollo_dashboard/resources/dev_grafana_alerts_{}.json", alert_env_filtering) } diff --git a/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs b/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs index e439c53d1e4..defceba0c0b 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs @@ -2,6 +2,7 @@ use apollo_consensus::metrics::{CONSENSUS_BLOCK_NUMBER, CONSENSUS_ROUND_ABOVE_ZE use apollo_consensus_manager::metrics::CONSENSUS_NUM_CONNECTED_PEERS; use apollo_consensus_orchestrator::metrics::CENDE_WRITE_BLOB_FAILURE; +use crate::alert_definitions::BLOCK_TIME_SEC; use crate::alerts::{ Alert, AlertComparisonOp, @@ -51,7 +52,6 @@ pub(crate) fn get_consensus_round_above_zero_vec() -> Vec { ] } -/// There were 5 times in the last 30 minutes that the round was larger than zero. fn get_consensus_round_above_zero_multiple_times( alert_env_filtering: AlertEnvFiltering, alert_severity: AlertSeverity, @@ -63,7 +63,7 @@ fn get_consensus_round_above_zero_multiple_times( format!("increase({}[10m])", CONSENSUS_ROUND_ABOVE_ZERO.get_name_with_filter()), vec![AlertCondition { comparison_op: AlertComparisonOp::GreaterThan, - comparison_value: 30.0, + comparison_value: 180.0 / BLOCK_TIME_SEC, logical_op: AlertLogicalOp::And, }], PENDING_DURATION_DEFAULT, @@ -174,7 +174,6 @@ pub(crate) fn get_cende_write_blob_failure_once_alert() -> Alert { ) } -/// Block number progressed slowly (< 10) in the last 2 minutes. fn get_consensus_block_number_progress_is_slow( alert_env_filtering: AlertEnvFiltering, alert_severity: AlertSeverity, @@ -189,7 +188,7 @@ fn get_consensus_block_number_progress_is_slow( ), vec![AlertCondition { comparison_op: AlertComparisonOp::LessThan, - comparison_value: 10.0, + comparison_value: 60.0 / BLOCK_TIME_SEC, logical_op: AlertLogicalOp::And, }], PENDING_DURATION_DEFAULT, 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 71aa03f329c..d5bc3b4c262 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/block_production_halt.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/block_production_halt.rs @@ -4,6 +4,7 @@ use apollo_batcher::metrics::BATCHED_TRANSACTIONS; use apollo_consensus::metrics::{CONSENSUS_BLOCK_NUMBER, CONSENSUS_ROUND}; use apollo_consensus_manager::metrics::CONSENSUS_NUM_CONNECTED_PEERS; +use crate::alert_definitions::BLOCK_TIME_SEC; use crate::alerts::{ Alert, AlertComparisonOp, @@ -185,7 +186,7 @@ fn get_consensus_round_high( format!("max_over_time({}[2m])", CONSENSUS_ROUND.get_name_with_filter()), vec![AlertCondition { comparison_op: AlertComparisonOp::GreaterThan, - comparison_value: 20.0, + comparison_value: 120.0 / BLOCK_TIME_SEC, logical_op: AlertLogicalOp::And, }], PENDING_DURATION_DEFAULT, From b1c3907d596d742001171cf5762dfe1423db370e Mon Sep 17 00:00:00 2001 From: dorimedini-starkware Date: Thu, 16 Oct 2025 10:15:38 +0300 Subject: [PATCH 041/313] release: bump starknet-types-core to 0.2.3 (#9585) Signed-off-by: Dori Medini --- Cargo.lock | 14 ++++++++------ Cargo.toml | 2 +- .../resources/reader/declare_v3.json | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc04a7a1d7c..e56924d9348 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7716,9 +7716,9 @@ dependencies = [ [[package]] name = "lambdaworks-crypto" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce8f59622ed408c318c9b5eca17f1a1154159e3738b5c4d5a22a0dd3700c906" +checksum = "58b1a1c1102a5a7fbbda117b79fb3a01e033459c738a3c1642269603484fd1c1" dependencies = [ "lambdaworks-math", "rand 0.8.5", @@ -7730,11 +7730,13 @@ dependencies = [ [[package]] name = "lambdaworks-math" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "405d65a26831650ba348a503a2881ed7a0483ef3ec17f66e0fc8e2f9c97fc7ca" +checksum = "018a95aa873eb49896a858dee0d925c33f3978d073c64b08dd4f2c9b35a017c6" dependencies = [ "getrandom 0.2.15", + "num-bigint 0.4.6", + "num-traits", "rand 0.8.5", "serde", "serde_json", @@ -12020,9 +12022,9 @@ dependencies = [ [[package]] name = "starknet-types-core" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c043ab183b1cb1daab10d592719d27f283e7ef7e7ac8accd243b4e70b4e1c0d8" +checksum = "ab92594a86ac627dd4c8d3350362cc8035e55c548c27c71dfa4c9fc6b3b6ab1a" dependencies = [ "blake2", "digest 0.10.7", diff --git a/Cargo.toml b/Cargo.toml index f4db0ee56ee..a14b1bd817f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -297,7 +297,7 @@ sizeof_internal = { path = "crates/sizeof/sizeof_internal" } socket2 = "0.5.8" starknet-core = "0.16.0" starknet-crypto = "0.8.1" -starknet-types-core = "0.2.1" +starknet-types-core = "=0.2.3" starknet_api = { path = "crates/starknet_api", version = "0.15.0-rc.4" } starknet_committer.path = "crates/starknet_committer" starknet_committer_and_os_cli.path = "crates/starknet_committer_and_os_cli" diff --git a/crates/apollo_starknet_client/resources/reader/declare_v3.json b/crates/apollo_starknet_client/resources/reader/declare_v3.json index 55d422c8f31..7925feb4fa8 100644 --- a/crates/apollo_starknet_client/resources/reader/declare_v3.json +++ b/crates/apollo_starknet_client/resources/reader/declare_v3.json @@ -1,7 +1,7 @@ { "account_deployment_data": [], "class_hash": "0x6f6742127e27687640c7aaf566b9dc892c4493973076cb96fdeb418ae77c192", - "compiled_class_hash": "0xcbbcfda1dea5cc48d3c7ebefd50ecc4aaefabe7e5596fdef4f60cded0ea0b24", + "compiled_class_hash": "0x4bbcfda1dea5cb38d3c7ebefd50ecc4aaefabe7e5596fdef4f60cded0ea0b23", "fee_data_availability_mode": 0, "nonce": "0x0", "nonce_data_availability_mode": 0, From 44e0f9604a37a977fca2d3b6081a5448058bac92 Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Thu, 16 Oct 2025 11:28:35 +0300 Subject: [PATCH 042/313] apollo_consensus_orchestrator: allow overriding of gas prices (#9584) --- config/papyrus/default_config.json | 35 ++++++-- .../src/build_proposal_test.rs | 15 +--- .../src/config.rs | 46 +++++++--- .../src/sequencer_consensus_context.rs | 32 ++----- .../src/sequencer_consensus_context_test.rs | 87 +++++++++++++++--- .../src/utils.rs | 89 +++++++++++++------ .../src/validate_proposal_test.rs | 15 +--- .../app_configs/consensus_manager_config.json | 7 +- .../apollo_node/resources/config_schema.json | 35 ++++++-- ...fig__config_test__dump_default_config.snap | 41 +++++++-- 10 files changed, 282 insertions(+), 120 deletions(-) diff --git a/config/papyrus/default_config.json b/config/papyrus/default_config.json index dca8b8cfa88..4cbb0b556fa 100644 --- a/config/papyrus/default_config.json +++ b/config/papyrus/default_config.json @@ -159,11 +159,6 @@ "pointer_target": "chain_id", "privacy": "Public" }, - "context.constant_l2_gas_price": { - "description": "If true, sets STRK gas price to its minimum price from the versioned constants.", - "privacy": "Public", - "value": false - }, "context.l1_da_mode": { "description": "The data availability mode, true: Blob, false: Calldata.", "privacy": "Public", @@ -204,6 +199,36 @@ "privacy": "Public", "value": 1 }, + "context.override_l1_data_gas_price": { + "description": "Replace the L1 data gas price with this value.", + "privacy": "Public", + "value": 0 + }, + "context.override_l1_data_gas_price.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "context.override_l1_gas_price": { + "description": "Replace the L1 gas price with this value.", + "privacy": "Public", + "value": 0 + }, + "context.override_l1_gas_price.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "context.override_l2_gas_price": { + "description": "Replace the L2 gas price with this value.", + "privacy": "Public", + "value": 0 + }, + "context.override_l2_gas_price.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, "context.proposal_buffer_size": { "description": "The buffer size for streaming outbound proposals.", "privacy": "Public", diff --git a/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs b/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs index ebe64805042..7f9a0928df3 100644 --- a/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs +++ b/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs @@ -20,7 +20,6 @@ use apollo_state_sync_types::errors::StateSyncError; use assert_matches::assert_matches; use blockifier::abi::constants::STORED_BLOCK_HASH_BUFFER; use futures::channel::mpsc; -use num_rational::Ratio; use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; use starknet_api::core::{ClassHash, ContractAddress}; use starknet_api::data_availability::L1DataAvailabilityMode; @@ -39,7 +38,7 @@ use crate::test_utils::{ STATE_DIFF_COMMITMENT, TIMEOUT, }; -use crate::utils::{GasPriceParams, StreamSender}; +use crate::utils::{make_gas_price_params, GasPriceParams, StreamSender}; struct TestProposalBuildArguments { pub deps: TestDeps, @@ -89,17 +88,7 @@ fn create_proposal_build_arguments() -> (TestProposalBuildArguments, mpsc::Recei let stream_sender = StreamSender { proposal_sender }; let context_config = ContextConfig::default(); - let gas_price_params = GasPriceParams { - min_l1_gas_price_wei: GasPrice(context_config.min_l1_gas_price_wei), - max_l1_gas_price_wei: GasPrice(context_config.max_l1_gas_price_wei), - min_l1_data_gas_price_wei: GasPrice(context_config.min_l1_data_gas_price_wei), - max_l1_data_gas_price_wei: GasPrice(context_config.max_l1_data_gas_price_wei), - l1_data_gas_price_multiplier: Ratio::new( - context_config.l1_data_gas_price_multiplier_ppt, - 1000, - ), - l1_gas_tip_wei: GasPrice(context_config.l1_gas_tip_wei), - }; + let gas_price_params = make_gas_price_params(&context_config); let valid_proposals = Arc::new(Mutex::new(BuiltProposals::new())); let proposal_id = ProposalId(1); let cende_write_success = AbortOnDropHandle::new(tokio::spawn(async { true })); diff --git a/crates/apollo_consensus_orchestrator/src/config.rs b/crates/apollo_consensus_orchestrator/src/config.rs index 6f6aecf93b9..a048bc69892 100644 --- a/crates/apollo_consensus_orchestrator/src/config.rs +++ b/crates/apollo_consensus_orchestrator/src/config.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use std::time::Duration; use apollo_config::converters::deserialize_milliseconds_to_duration; -use apollo_config::dumping::{ser_param, SerializeConfig}; +use apollo_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; use apollo_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; use starknet_api::core::{ChainId, ContractAddress}; @@ -52,13 +52,17 @@ pub struct ContextConfig { pub l1_data_gas_price_multiplier_ppt: u128, /// This additional gas is added to the L1 gas price. pub l1_gas_tip_wei: u128, - /// If true, sets STRK gas price to its minimum price from the versioned constants. - pub constant_l2_gas_price: bool, + /// If given, will override the L2 gas price. + pub override_l2_gas_price: Option, + /// If given, will override the L1 gas price. + pub override_l1_gas_price: Option, + /// If given, will override the L1 data gas price. + pub override_l1_data_gas_price: Option, } impl SerializeConfig for ContextConfig { fn dump(&self) -> BTreeMap { - BTreeMap::from_iter([ + let mut dump = BTreeMap::from_iter([ ser_param( "proposal_buffer_size", &self.proposal_buffer_size, @@ -147,13 +151,29 @@ impl SerializeConfig for ContextConfig { "This additional gas is added to the L1 gas price.", ParamPrivacyInput::Public, ), - ser_param( - "constant_l2_gas_price", - &self.constant_l2_gas_price, - "If true, sets STRK gas price to its minimum price from the versioned constants.", - ParamPrivacyInput::Public, - ), - ]) + ]); + dump.extend(ser_optional_param( + &self.override_l2_gas_price, + 0, + "override_l2_gas_price", + "Replace the L2 gas price with this value.", + ParamPrivacyInput::Public, + )); + dump.extend(ser_optional_param( + &self.override_l1_gas_price, + 0, + "override_l1_gas_price", + "Replace the L1 gas price with this value.", + ParamPrivacyInput::Public, + )); + dump.extend(ser_optional_param( + &self.override_l1_data_gas_price, + 0, + "override_l1_data_gas_price", + "Replace the L1 data gas price with this value.", + ParamPrivacyInput::Public, + )); + dump } } @@ -174,7 +194,9 @@ impl Default for ContextConfig { max_l1_data_gas_price_wei: ETH_FACTOR, l1_data_gas_price_multiplier_ppt: 135, l1_gas_tip_wei: GWEI_FACTOR, - constant_l2_gas_price: false, + override_l2_gas_price: None, + override_l1_gas_price: None, + override_l1_data_gas_price: None, } } } diff --git a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs index 8fb95ec4fe9..73f8b959653 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -44,7 +44,6 @@ use apollo_time::time::Clock; use async_trait::async_trait; use futures::channel::{mpsc, oneshot}; use futures::SinkExt; -use num_rational::Ratio; use starknet_api::block::{ BlockHeaderWithoutHash, BlockNumber, @@ -73,7 +72,7 @@ use crate::metrics::{ CONSENSUS_L2_GAS_PRICE, }; use crate::orchestrator_versioned_constants::VersionedConstants; -use crate::utils::{convert_to_sn_api_block_info, GasPriceParams, StreamSender}; +use crate::utils::{convert_to_sn_api_block_info, make_gas_price_params, StreamSender}; use crate::validate_proposal::{ validate_proposal, BlockInfoValidation, @@ -252,17 +251,7 @@ impl ConsensusContext for SequencerConsensusContext { info!(?proposal_init, ?timeout, %proposal_id, "Start building proposal"); let cancel_token = CancellationToken::new(); let cancel_token_clone = cancel_token.clone(); - let gas_price_params = GasPriceParams { - min_l1_gas_price_wei: GasPrice(self.config.min_l1_gas_price_wei), - max_l1_gas_price_wei: GasPrice(self.config.max_l1_gas_price_wei), - min_l1_data_gas_price_wei: GasPrice(self.config.min_l1_data_gas_price_wei), - max_l1_data_gas_price_wei: GasPrice(self.config.max_l1_data_gas_price_wei), - l1_data_gas_price_multiplier: Ratio::new( - self.config.l1_data_gas_price_multiplier_ppt, - 1000, - ), - l1_gas_tip_wei: GasPrice(self.config.l1_gas_tip_wei), - }; + let gas_price_params = make_gas_price_params(&self.config); let args = ProposalBuildArguments { deps: self.deps.clone(), batcher_timeout: timeout - self.config.build_proposal_margin_millis, @@ -470,8 +459,9 @@ impl ConsensusContext for SequencerConsensusContext { .collect(); let gas_target = VersionedConstants::latest_constants().gas_target; - if self.config.constant_l2_gas_price { - self.l2_gas_price = VersionedConstants::latest_constants().min_gas_price; + if let Some(override_value) = self.config.override_l2_gas_price { + info!("Overriding L2 gas price to {override_value}"); + self.l2_gas_price = GasPrice(override_value); } else { self.l2_gas_price = calculate_next_base_gas_price(self.l2_gas_price, l2_gas_used, gas_target); @@ -697,17 +687,7 @@ impl SequencerConsensusContext { let cancel_token = CancellationToken::new(); let cancel_token_clone = cancel_token.clone(); - let gas_price_params = GasPriceParams { - min_l1_gas_price_wei: GasPrice(self.config.min_l1_gas_price_wei), - max_l1_gas_price_wei: GasPrice(self.config.max_l1_gas_price_wei), - min_l1_data_gas_price_wei: GasPrice(self.config.min_l1_data_gas_price_wei), - max_l1_data_gas_price_wei: GasPrice(self.config.max_l1_data_gas_price_wei), - l1_data_gas_price_multiplier: Ratio::new( - self.config.l1_data_gas_price_multiplier_ppt, - 1000, - ), - l1_gas_tip_wei: GasPrice(self.config.l1_gas_tip_wei), - }; + let gas_price_params = make_gas_price_params(&self.config); let args = ProposalValidateArguments { deps: self.deps.clone(), block_info_validation, 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 74456e907ad..51d506ff71e 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs @@ -44,6 +44,7 @@ use crate::test_utils::{ TIMEOUT, TX_BATCH, }; +use crate::utils::{apply_fee_transformations, make_gas_price_params}; #[tokio::test] async fn cancelled_proposal_aborts() { @@ -786,14 +787,26 @@ async fn oracle_fails_on_second_block(#[case] l1_oracle_failure: bool) { assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); } +// L2 gas is a bit above the minimum gas price. +const ODDLY_SPECIFIC_L2_GAS_PRICE: GasPrice = GasPrice(9999999999); +const ODDLY_SPECIFIC_L1_GAS_PRICE: GasPrice = GasPrice(1234567890); +const ODDLY_SPECIFIC_L1_DATA_GAS_PRICE: GasPrice = GasPrice(987654321); + #[rstest] -#[case::constant_l2_gas_price_true(true, GasAmount::default())] -#[case::constant_l2_gas_price_false(false, VersionedConstants::latest_constants().max_block_size)] +#[case::dont_override_prices(None, None, None)] +#[case::override_l2_gas_price(Some(ODDLY_SPECIFIC_L2_GAS_PRICE.0), None, None)] +#[case::override_l1_gas_price(None, Some(ODDLY_SPECIFIC_L1_GAS_PRICE.0), None)] +#[case::override_l1_data_gas_price(None, None, Some(ODDLY_SPECIFIC_L1_DATA_GAS_PRICE.0))] +#[case::override_all_prices(Some(ODDLY_SPECIFIC_L2_GAS_PRICE.0), Some(ODDLY_SPECIFIC_L1_GAS_PRICE.0), Some(ODDLY_SPECIFIC_L1_DATA_GAS_PRICE.0))] #[tokio::test] -async fn constant_l2_gas_price_behavior( - #[case] constant_l2_gas_price: bool, - #[case] mock_l2_gas_used: GasAmount, +async fn override_prices_behavior( + #[case] override_l2_gas_price: Option, + #[case] override_l1_gas_price: Option, + #[case] override_l1_data_gas_price: Option, ) { + // Use high gas usage to ensure the L2 gas price is high. + let mock_l2_gas_used = VersionedConstants::latest_constants().max_block_size; + let (mut deps, _network) = create_test_and_network_deps(); let recorder = PrometheusBuilder::new().build_recorder(); @@ -801,7 +814,7 @@ async fn constant_l2_gas_price_behavior( // Setup dependencies and mocks. deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len()); - + deps.l1_gas_price_provider.expect_get_eth_to_fri_rate().returning(|_| Ok(ETH_TO_FRI_RATE)); deps.batcher.expect_decision_reached().times(1).return_once(move |_| { Ok(DecisionReachedResponse { state_diff: ThinStateDiff::default(), @@ -813,10 +826,23 @@ async fn constant_l2_gas_price_behavior( deps.state_sync_client.expect_add_new_block().times(1).return_once(|_| Ok(())); deps.cende_ambassador.expect_prepare_blob_for_next_height().times(1).return_once(|_| Ok(())); - let context_config = ContextConfig { constant_l2_gas_price, ..Default::default() }; + let context_config = ContextConfig { + override_l2_gas_price, + override_l1_gas_price, + override_l1_data_gas_price, + ..Default::default() + }; let mut context = deps.build_context(); context.config = context_config; + let min_gas_price = VersionedConstants::latest_constants().min_gas_price.0; + let gas_price_params = make_gas_price_params(&context.config); + let mut expected_l1_prices = PriceInfo { + base_fee_per_gas: GasPrice(TEMP_ETH_GAS_FEE_IN_WEI), + blob_fee: GasPrice(TEMP_ETH_BLOB_GAS_FEE_IN_WEI), + }; + apply_fee_transformations(&mut expected_l1_prices, &gas_price_params); + // Run proposal and decision logic. let _fin_receiver = context.build_proposal(ProposalInit::default(), TIMEOUT).await.await; context @@ -824,20 +850,53 @@ async fn constant_l2_gas_price_behavior( .await .unwrap(); - let min_gas_price = VersionedConstants::latest_constants().min_gas_price.0; let actual_l2_gas_price = context.l2_gas_price.0; + let actual_l1_gas_price = context.previous_block_info.clone().unwrap().l1_gas_price_wei.0; + let actual_l1_data_gas_price = + context.previous_block_info.clone().unwrap().l1_data_gas_price_wei.0; - if constant_l2_gas_price { + if let Some(override_l2_gas_price) = override_l2_gas_price { + // In this case the L2 gas price must match the given override. assert_eq!( - actual_l2_gas_price, min_gas_price, - "Expected L2 gas price to match constant min_gas_price" + actual_l2_gas_price, override_l2_gas_price, + "Expected L2 gas price ({}) to match override_l2_gas_price ({})", + actual_l2_gas_price, override_l2_gas_price ); } else { + // In this case the regular L2 gas calculation takes place, and gives a higher price. assert!( actual_l2_gas_price > min_gas_price, - "Expected L2 gas price > min ({}) due to high usage (EIP-1559), but got {}", - min_gas_price, - actual_l2_gas_price + "Expected L2 gas price ({}) > minimum l2 gas price ({}) due to high usage (EIP-1559)", + actual_l2_gas_price, + min_gas_price + ); + } + + if let Some(override_l1_gas_price) = override_l1_gas_price { + assert_eq!( + actual_l1_gas_price, override_l1_gas_price, + "Expected L1 gas price ({}) to match input l1 gas price ({})", + actual_l1_gas_price, override_l1_gas_price + ); + } else { + assert_eq!( + actual_l1_gas_price, expected_l1_prices.base_fee_per_gas.0, + "Expected L1 gas price ({}) to match input l1 gas price ({})", + actual_l1_gas_price, expected_l1_prices.base_fee_per_gas.0 + ); + } + + if let Some(override_l1_data_gas_price) = override_l1_data_gas_price { + assert_eq!( + actual_l1_data_gas_price, override_l1_data_gas_price, + "Expected L1 data gas price ({}) to match input l1 data gas price ({})", + actual_l1_data_gas_price, override_l1_data_gas_price + ); + } else { + assert_eq!( + actual_l1_data_gas_price, expected_l1_prices.blob_fee.0, + "Expected L1 data gas price ({}) to match input l1 data gas price ({})", + actual_l1_data_gas_price, expected_l1_prices.blob_fee.0 ); } } diff --git a/crates/apollo_consensus_orchestrator/src/utils.rs b/crates/apollo_consensus_orchestrator/src/utils.rs index 2468bef733b..3c35231a724 100644 --- a/crates/apollo_consensus_orchestrator/src/utils.rs +++ b/crates/apollo_consensus_orchestrator/src/utils.rs @@ -28,6 +28,7 @@ use starknet_api::StarknetApiError; use tracing::{info, warn}; use crate::build_proposal::BuildProposalError; +use crate::config::ContextConfig; use crate::metrics::CONSENSUS_L1_GAS_PRICE_PROVIDER_ERROR; use crate::validate_proposal::ValidateProposalError; @@ -41,6 +42,7 @@ impl StreamSender { } } +#[derive(Debug)] pub(crate) struct GasPriceParams { pub min_l1_gas_price_wei: GasPrice, pub max_l1_gas_price_wei: GasPrice, @@ -48,6 +50,8 @@ pub(crate) struct GasPriceParams { pub min_l1_data_gas_price_wei: GasPrice, pub l1_data_gas_price_multiplier: Ratio, pub l1_gas_tip_wei: GasPrice, + pub override_l1_gas_price: Option, + pub override_l1_data_gas_price: Option, } impl From for BuildProposalError { @@ -82,6 +86,8 @@ pub(crate) async fn get_oracle_rate_and_prices( l1_gas_price_provider_client.get_eth_to_fri_rate(timestamp), l1_gas_price_provider_client.get_price_info(BlockTimestamp(timestamp)) ); + let mut return_values; + if price_info.is_err() { warn!("Failed to get l1 gas price from provider: {:?}", price_info); CONSENSUS_L1_GAS_PRICE_PROVIDER_ERROR.increment(1); @@ -91,39 +97,57 @@ pub(crate) async fn get_oracle_rate_and_prices( } if let (Ok(eth_to_strk_rate), Ok(mut price_info)) = (eth_to_strk_rate, price_info) { + // Both L1 prices and rate are Ok, so we can use them. info!("eth_to_strk_rate: {eth_to_strk_rate}, l1 gas price: {price_info:?}"); apply_fee_transformations(&mut price_info, gas_price_params); - return (eth_to_strk_rate, price_info); + return_values = (eth_to_strk_rate, price_info); + } else { + // One or both have failed, need to use previous block info (or default values) + match previous_block_info { + Some(block_info) => { + let prev_l1_gas_price = PriceInfo { + base_fee_per_gas: block_info.l1_gas_price_wei, + blob_fee: block_info.l1_data_gas_price_wei, + }; + info!( + "Using values from previous block info. eth_to_strk_rate: {}, l1 gas price: \ + {:?}", + block_info.eth_to_fri_rate, prev_l1_gas_price + ); + return_values = (block_info.eth_to_fri_rate, prev_l1_gas_price); + } + None => { + let l1_gas_price = PriceInfo { + base_fee_per_gas: gas_price_params.min_l1_gas_price_wei, + blob_fee: gas_price_params.min_l1_data_gas_price_wei, + }; + info!( + "No previous block info available, using default values. eth_to_strk_rate: \ + {}, l1 gas price: {:?}", + DEFAULT_ETH_TO_FRI_RATE, l1_gas_price + ); + return_values = (DEFAULT_ETH_TO_FRI_RATE, l1_gas_price); + } + } } - match previous_block_info { - Some(block_info) => { - let prev_l1_gas_price = PriceInfo { - base_fee_per_gas: block_info.l1_gas_price_wei, - blob_fee: block_info.l1_data_gas_price_wei, - }; - info!( - "Using values from previous block info. eth_to_strk_rate: {}, l1 gas price: {:?}", - block_info.eth_to_fri_rate, prev_l1_gas_price - ); - (block_info.eth_to_fri_rate, prev_l1_gas_price) - } - None => { - let l1_gas_price = PriceInfo { - base_fee_per_gas: gas_price_params.min_l1_gas_price_wei, - blob_fee: gas_price_params.min_l1_data_gas_price_wei, - }; - info!( - "No previous block info available, using default values. eth_to_strk_rate: {}, l1 \ - gas price: {:?}", - DEFAULT_ETH_TO_FRI_RATE, l1_gas_price - ); - (DEFAULT_ETH_TO_FRI_RATE, l1_gas_price) - } + // If there is an override to L1 gas price or data gas price, apply it here: + if let Some(override_value) = gas_price_params.override_l1_gas_price { + info!("Overriding L1 gas price to {override_value}"); + return_values.1.base_fee_per_gas = override_value; } + if let Some(override_value) = gas_price_params.override_l1_data_gas_price { + info!("Overriding L1 data gas price to {override_value}"); + return_values.1.blob_fee = override_value; + } + + return_values } -fn apply_fee_transformations(price_info: &mut PriceInfo, gas_price_params: &GasPriceParams) { +pub(crate) fn apply_fee_transformations( + price_info: &mut PriceInfo, + gas_price_params: &GasPriceParams, +) { price_info.base_fee_per_gas = price_info .base_fee_per_gas .saturating_add(gas_price_params.l1_gas_tip_wei) @@ -213,3 +237,16 @@ pub(crate) fn truncate_to_executed_txs( executed_content } + +pub(crate) fn make_gas_price_params(config: &ContextConfig) -> GasPriceParams { + GasPriceParams { + min_l1_gas_price_wei: GasPrice(config.min_l1_gas_price_wei), + max_l1_gas_price_wei: GasPrice(config.max_l1_gas_price_wei), + min_l1_data_gas_price_wei: GasPrice(config.min_l1_data_gas_price_wei), + max_l1_data_gas_price_wei: GasPrice(config.max_l1_data_gas_price_wei), + l1_data_gas_price_multiplier: Ratio::new(config.l1_data_gas_price_multiplier_ppt, 1000), + l1_gas_tip_wei: GasPrice(config.l1_gas_tip_wei), + override_l1_gas_price: config.override_l1_gas_price.map(GasPrice), + override_l1_data_gas_price: config.override_l1_data_gas_price.map(GasPrice), + } +} diff --git a/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs b/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs index d05a88e3a88..0a4b54c15ec 100644 --- a/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs +++ b/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs @@ -15,7 +15,6 @@ use apollo_protobuf::consensus::{ProposalFin, ProposalPart, TransactionBatch}; use assert_matches::assert_matches; use futures::channel::mpsc; use futures::SinkExt; -use num_rational::Ratio; use rstest::rstest; use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; use starknet_api::core::StateDiffCommitment; @@ -35,7 +34,7 @@ use crate::test_utils::{ TIMEOUT, TX_BATCH, }; -use crate::utils::GasPriceParams; +use crate::utils::{make_gas_price_params, GasPriceParams}; use crate::validate_proposal::{ validate_proposal, within_margin, @@ -89,17 +88,7 @@ fn create_proposal_validate_arguments() let valid_proposals = Arc::new(Mutex::new(BuiltProposals::new())); let (content_sender, content_receiver) = mpsc::channel(CHANNEL_SIZE); let context_config = ContextConfig::default(); - let gas_price_params = GasPriceParams { - min_l1_gas_price_wei: GasPrice(context_config.min_l1_gas_price_wei), - max_l1_gas_price_wei: GasPrice(context_config.max_l1_gas_price_wei), - min_l1_data_gas_price_wei: GasPrice(context_config.min_l1_data_gas_price_wei), - max_l1_data_gas_price_wei: GasPrice(context_config.max_l1_data_gas_price_wei), - l1_data_gas_price_multiplier: Ratio::new( - context_config.l1_data_gas_price_multiplier_ppt, - 1000, - ), - l1_gas_tip_wei: GasPrice(context_config.l1_gas_tip_wei), - }; + let gas_price_params = make_gas_price_params(&context_config); let cancel_token = CancellationToken::new(); ( diff --git a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json index 6a560416210..8a8353953ac 100644 --- a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json +++ b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json @@ -16,7 +16,12 @@ "consensus_manager_config.context_config.block_timestamp_window_seconds": 1, "consensus_manager_config.context_config.build_proposal_margin_millis": 1000, "consensus_manager_config.context_config.builder_address": "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", - "consensus_manager_config.context_config.constant_l2_gas_price": false, + "consensus_manager_config.context_config.override_l2_gas_price": 0, + "consensus_manager_config.context_config.override_l1_gas_price": 0, + "consensus_manager_config.context_config.override_l1_data_gas_price": 0, + "consensus_manager_config.context_config.override_l2_gas_price.#is_none": true, + "consensus_manager_config.context_config.override_l1_gas_price.#is_none": true, + "consensus_manager_config.context_config.override_l1_data_gas_price.#is_none": true, "consensus_manager_config.context_config.l1_da_mode": true, "consensus_manager_config.context_config.l1_data_gas_price_multiplier_ppt": 135, "consensus_manager_config.context_config.l1_gas_tip_wei": 1000000000, diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 0775a346d1b..87e49581e4a 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -1489,11 +1489,6 @@ "pointer_target": "chain_id", "privacy": "Public" }, - "consensus_manager_config.context_config.constant_l2_gas_price": { - "description": "If true, sets STRK gas price to its minimum price from the versioned constants.", - "privacy": "Public", - "value": false - }, "consensus_manager_config.context_config.l1_da_mode": { "description": "The data availability mode, true: Blob, false: Calldata.", "privacy": "Public", @@ -1534,6 +1529,36 @@ "privacy": "Public", "value": 1 }, + "consensus_manager_config.context_config.override_l1_data_gas_price": { + "description": "Replace the L1 data gas price with this value.", + "privacy": "Public", + "value": 0 + }, + "consensus_manager_config.context_config.override_l1_data_gas_price.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "consensus_manager_config.context_config.override_l1_gas_price": { + "description": "Replace the L1 gas price with this value.", + "privacy": "Public", + "value": 0 + }, + "consensus_manager_config.context_config.override_l1_gas_price.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "consensus_manager_config.context_config.override_l2_gas_price": { + "description": "Replace the L2 gas price with this value.", + "privacy": "Public", + "value": 0 + }, + "consensus_manager_config.context_config.override_l2_gas_price.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, "consensus_manager_config.context_config.proposal_buffer_size": { "description": "The buffer size for streaming outbound proposals.", "privacy": "Public", diff --git a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap index c8d5785ad9e..8135712f321 100644 --- a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap +++ b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap @@ -191,11 +191,6 @@ expression: dumped_default_config "value": "SN_MAIN", "privacy": "Public" }, - "context.constant_l2_gas_price": { - "description": "If true, sets STRK gas price to its minimum price from the versioned constants.", - "value": false, - "privacy": "Public" - }, "context.l1_da_mode": { "description": "The data availability mode, true: Blob, false: Calldata.", "value": true, @@ -250,6 +245,42 @@ expression: dumped_default_config }, "privacy": "Public" }, + "context.override_l1_data_gas_price": { + "description": "Replace the L1 data gas price with this value.", + "value": { + "$serde_json::private::Number": "0" + }, + "privacy": "Public" + }, + "context.override_l1_data_gas_price.#is_none": { + "description": "Flag for an optional field.", + "value": true, + "privacy": "TemporaryValue" + }, + "context.override_l1_gas_price": { + "description": "Replace the L1 gas price with this value.", + "value": { + "$serde_json::private::Number": "0" + }, + "privacy": "Public" + }, + "context.override_l1_gas_price.#is_none": { + "description": "Flag for an optional field.", + "value": true, + "privacy": "TemporaryValue" + }, + "context.override_l2_gas_price": { + "description": "Replace the L2 gas price with this value.", + "value": { + "$serde_json::private::Number": "0" + }, + "privacy": "Public" + }, + "context.override_l2_gas_price.#is_none": { + "description": "Flag for an optional field.", + "value": true, + "privacy": "TemporaryValue" + }, "context.proposal_buffer_size": { "description": "The buffer size for streaming outbound proposals.", "value": { From b80806805c3fa247ac72eb74277e548508f28a26 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Thu, 16 Oct 2025 11:40:14 +0300 Subject: [PATCH 043/313] apollo_infra: change tracing format (#9589) --- crates/apollo_infra/Cargo.toml | 2 +- crates/apollo_infra/src/trace_util.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/apollo_infra/Cargo.toml b/crates/apollo_infra/Cargo.toml index cef3288c080..a49efe1af34 100644 --- a/crates/apollo_infra/Cargo.toml +++ b/crates/apollo_infra/Cargo.toml @@ -27,7 +27,7 @@ time = { workspace = true, features = ["macros"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tower = { workspace = true, features = ["limit", "util"] } tracing.workspace = true -tracing-subscriber = { workspace = true, features = ["env-filter", "time"] } +tracing-subscriber = { workspace = true, features = ["env-filter", "json", "time"] } validator.workspace = true [dev-dependencies] diff --git a/crates/apollo_infra/src/trace_util.rs b/crates/apollo_infra/src/trace_util.rs index e32e9e1cea4..3d0ff8907e6 100644 --- a/crates/apollo_infra/src/trace_util.rs +++ b/crates/apollo_infra/src/trace_util.rs @@ -14,14 +14,14 @@ pub static PID: std::sync::LazyLock = std::sync::LazyLock::new(std::process pub async fn configure_tracing() { TRACING_INITIALIZED .get_or_init(|| async { - // Use default time formatting with subsecond precision limited to three digits. + // Use default time formatting with sub-second precision limited to three digits. let time_format = format_description!( "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z" ); let timer = UtcTime::new(time_format); let fmt_layer = fmt::layer() - .compact() + .json() .with_timer(timer) .with_target(false) // No module name. // Instead, file name and line number. From 0ea1fd6971ccda9caa2fbf8fb708ef5525816aa9 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 16 Oct 2025 11:41:26 +0300 Subject: [PATCH 044/313] ci: add limit to the regression in the committer benchmark (#9523) --- .github/workflows/committer_ci.yml | 12 +++- .../benches/bench_split_and_prepare_post.sh | 55 ++++++++++++++++++- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/.github/workflows/committer_ci.yml b/.github/workflows/committer_ci.yml index 3bf3c9c6696..beb628b9358 100644 --- a/.github/workflows/committer_ci.yml +++ b/.github/workflows/committer_ci.yml @@ -129,9 +129,9 @@ jobs: gcloud storage cp -r gs://committer-testing-artifacts/$NEW_BENCH_INPUT_FILES_PREFIX/* ./crates/starknet_committer_and_os_cli/test_inputs # Benchmark the new code, splitting the benchmarks, and prepare the results for posting a comment. - - run: bash ./crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh benchmarks_list.txt bench_new.txt + - run: bash ./crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh benchmarks_list.txt benchmark_comment_body.txt - - run: echo BENCHES_RESULT=$(cat bench_new.txt) >> $GITHUB_ENV + - run: echo BENCHES_RESULT=$(cat benchmark_comment_body.txt) >> $GITHUB_ENV # Comment with a link to the workflow (or update existing comment on rerun). - name: Find Comment @@ -164,3 +164,11 @@ jobs: comment-id: ${{ steps.find-benchmark-comment.outputs.comment-id }} edit-mode: replace body: ${{ env.BENCHES_RESULT }} + + # Fail the job if benchmarks exceeded the threshold (after posting the comment). + - name: Check benchmark results + run: | + if grep -q "CI WILL FAIL" benchmark_comment_body.txt; then + echo "Benchmarks exceeded the regression threshold. See the PR comment for details." + exit 1 + fi diff --git a/crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh b/crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh index c766b72f668..caf4e54ee48 100644 --- a/crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh +++ b/crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh @@ -1,29 +1,80 @@ #!/bin/env bash +# +# This script runs benchmarks, compares them to the baseline, and prepares results for posting. +# It will mark the CI to fail if any benchmark regresses by more than the threshold. +# +# Usage: bench_split_and_prepare_post.sh +# benchmarks_list: File containing list of benchmark names (one per line) +# benchmark_results: Output file for formatted results (used for PR comments) set -e benchmarks_list=${1} benchmark_results=${2} -# Benchmark the new code, splitting the benchmarks +# 8% threshold for acceptable regression. +threshold=8.0 + +# ============================================================================ +# Step 1: Run benchmarks. +# ============================================================================ +# Run each benchmark individually and save output to separate files. # TODO(Aner): split the output file instead. cat ${benchmarks_list} | while read line; do cargo bench -p starknet_committer_and_os_cli $line > ${line}.txt; + # Keep only the benchmark output, remove everything before the benchmark name. sed -i '/'"${line}"'/,$!d' ${line}.txt; done -# Prepare the results for posting comment. +# ============================================================================ +# Step 2: Analyze results and check thresholds +# ============================================================================ echo "Benchmark movements: " > ${benchmark_results} +has_major_regression=false + cat ${benchmarks_list} | while read line; do + # Parse the percentage change and check against threshold. + # Find the line that contains the percent change summary printed by Criterion. + # Typical format (note the leading spaces): + # " change: [-2.3% -1.2% +0.1%]" + # Semantics: [lower_bound point_estimate upper_bound] + change_line=$(grep "change:" ${line}.txt || true) + if [ -n "$change_line" ]; then + # Steps to extract the point estimate (the SECOND number inside the brackets): + # 1) Split the line by whitespace and take field 3 using awk + # Fields: $1="change:" $2="[-2.3%" $3="-1.2%" $4="+0.1%]" + # 2) Strip '%' and any leading '+' so it's a clean float for bc + # Examples: "+6.4%" -> "6.4"; "-2.0%" -> "-2.0" + change_pct=$(echo "$change_line" | awk '{print $3}' | tr -d '%+') + if [ -n "$change_pct" ]; then + # fail if point estimate > threshold. + if awk -v x="$change_pct" -v y="$threshold" 'BEGIN { exit(!(x > y)) }'; then + if [ "$has_major_regression" = false ]; then + echo "" >> ${benchmark_results} + echo "---" >> ${benchmark_results} + echo "❌ **CI WILL FAIL: Benchmarks exceeded ${threshold}% regression threshold**" >> ${benchmark_results} + echo "" >> ${benchmark_results} + has_major_regression=true + fi + echo "ERROR: ${line} regressed by ${change_pct}%, exceeding ${threshold}% threshold!" >> ${benchmark_results} + fi + fi + fi + + # Check if this benchmark regressed. if grep -q "regressed" ${line}.txt; then echo "**${line} performance regressed!**" >> ${benchmark_results}; cat ${line}.txt >> ${benchmark_results}; + + # Check if this benchmark improved. elif grep -q "improved" ${line}.txt; then echo "_${line} performance improved_ :smiley_cat:" >> ${benchmark_results}; cat ${line}.txt >> ${benchmark_results}; fi; done + +# If no significant changes were detected. if ! (grep -q "regressed" ${benchmark_results} || grep -q "improved" ${benchmark_results}); then echo "No major performance changes detected." >> ${benchmark_results}; fi From 542e2633d86bf4f843cf953a723da9c1a4a8bb41 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 16 Oct 2025 11:47:53 +0300 Subject: [PATCH 045/313] mempool_test_utils: update valid l2 gas max amount to fit os upper limit (#9583) --- crates/mempool_test_utils/src/starknet_api_test_utils.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index 0fc79834036..d77e41270dd 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -47,7 +47,8 @@ use crate::{COMPILED_CLASS_HASH_OF_CONTRACT_CLASS, CONTRACT_CLASS_FILE, TEST_FIL pub const VALID_L1_GAS_MAX_AMOUNT: u64 = 203484; pub const VALID_L1_GAS_MAX_PRICE_PER_UNIT: u128 = 100000000000000; -pub const VALID_L2_GAS_MAX_AMOUNT: u64 = 500000 * 200000; // Enough to declare the test class. +// Enough to declare the test class, but under the OS's upper limit. +pub const VALID_L2_GAS_MAX_AMOUNT: u64 = 1_100_000_000; pub const VALID_L2_GAS_MAX_PRICE_PER_UNIT: u128 = 100000000000000; pub const VALID_L1_DATA_GAS_MAX_AMOUNT: u64 = 203484; pub const VALID_L1_DATA_GAS_MAX_PRICE_PER_UNIT: u128 = 100000000000000; From 98c9aeb2efcd221b1a6f0d068d41b3f0b779b1ea Mon Sep 17 00:00:00 2001 From: itamar-starkware Date: Thu, 16 Oct 2025 12:29:47 +0300 Subject: [PATCH 046/313] apollo_integration_tests: use multi threads tokio runtime on flow tests (#9500) --- crates/apollo_integration_tests/tests/bootstrap_declare.rs | 3 ++- crates/apollo_integration_tests/tests/end_to_end_flow_test.rs | 3 ++- .../apollo_integration_tests/tests/test_custom_cairo0_txs.rs | 3 ++- .../apollo_integration_tests/tests/test_custom_cairo1_txs.rs | 3 ++- crates/apollo_integration_tests/tests/test_many.rs | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/apollo_integration_tests/tests/bootstrap_declare.rs b/crates/apollo_integration_tests/tests/bootstrap_declare.rs index f0bf0caa12e..d922825d497 100644 --- a/crates/apollo_integration_tests/tests/bootstrap_declare.rs +++ b/crates/apollo_integration_tests/tests/bootstrap_declare.rs @@ -17,7 +17,8 @@ fn create_bootstrap_declare_scenario() -> Vec { /// Bootstrap declare txs are unique: they are sent from a special address and do not increment its /// nonce. As a result, they are not removed from the mempool upon successful execution, and will /// only be removed after being rejected during a subsequent attempt. -#[tokio::test] +/// The test uses 3 threads: 1 for the test's main thread and 2 for the sequencers. +#[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn bootstrap_declare() { end_to_end_flow( TestIdentifier::EndToEndFlowTestBootstrapDeclare, diff --git a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs index 630c7a8493a..45759d86571 100644 --- a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs +++ b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs @@ -16,7 +16,8 @@ use crate::common::{end_to_end_flow, test_single_tx, TestScenario}; mod common; -#[tokio::test] +/// Number of threads is 3 = Num of sequencer + 1 for the test thread. +#[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn test_end_to_end_flow() { end_to_end_flow( TestIdentifier::EndToEndFlowTest, diff --git a/crates/apollo_integration_tests/tests/test_custom_cairo0_txs.rs b/crates/apollo_integration_tests/tests/test_custom_cairo0_txs.rs index 2dbed33fe96..7fc6e215992 100644 --- a/crates/apollo_integration_tests/tests/test_custom_cairo0_txs.rs +++ b/crates/apollo_integration_tests/tests/test_custom_cairo0_txs.rs @@ -20,7 +20,8 @@ mod common; const CUSTOM_CAIRO_0_INVOKE_TX_COUNT: usize = 9; -#[tokio::test] +/// The test uses 3 threads: 1 for the test's main thread and 2 for the sequencers. +#[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn custom_cairo0_txs() { end_to_end_flow( TestIdentifier::EndToEndFlowTestCustomCairo0Txs, diff --git a/crates/apollo_integration_tests/tests/test_custom_cairo1_txs.rs b/crates/apollo_integration_tests/tests/test_custom_cairo1_txs.rs index c3a70126c36..7247ec74fb1 100644 --- a/crates/apollo_integration_tests/tests/test_custom_cairo1_txs.rs +++ b/crates/apollo_integration_tests/tests/test_custom_cairo1_txs.rs @@ -26,7 +26,8 @@ mod common; const CUSTOM_INVOKE_TX_COUNT: usize = 16; /// Test a wide range of different kinds of invoke transactions. -#[tokio::test] +/// Number of threads is 3 = Num of sequencer + 1 for the test thread. +#[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn custom_cairo1_txs() { end_to_end_flow( TestIdentifier::EndToEndFlowTestCustomSyscallInvokeTxs, diff --git a/crates/apollo_integration_tests/tests/test_many.rs b/crates/apollo_integration_tests/tests/test_many.rs index ca8b98e4a60..24612161ef2 100644 --- a/crates/apollo_integration_tests/tests/test_many.rs +++ b/crates/apollo_integration_tests/tests/test_many.rs @@ -10,7 +10,8 @@ use crate::common::{end_to_end_flow, TestScenario}; mod common; /// This test checks that at least one block is full. -#[tokio::test] +/// The test uses 3 threads: 1 for the test's main thread and 2 for the sequencers. +#[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn many_txs_fill_at_least_one_block() { end_to_end_flow( TestIdentifier::EndToEndFlowTestManyTxs, From 587f1fcbd9134e51fea83db695905f18ec0c1b1d Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 16 Oct 2025 12:40:56 +0300 Subject: [PATCH 047/313] apollo_gateway: add max l2 gas amount stateless check (#9572) --- .../resources/app_configs/gateway_config.json | 1 + crates/apollo_gateway/src/config.rs | 11 +++++- crates/apollo_gateway/src/errors.rs | 17 ++++++-- crates/apollo_gateway/src/metrics.rs | 3 ++ .../src/stateless_transaction_validator.rs | 7 ++++ .../stateless_transaction_validator_test.rs | 39 ++++++++++++++++++- .../apollo_node/resources/config_schema.json | 5 +++ 7 files changed, 76 insertions(+), 7 deletions(-) diff --git a/crates/apollo_deployments/resources/app_configs/gateway_config.json b/crates/apollo_deployments/resources/app_configs/gateway_config.json index 04c0a0aca28..85090d37eca 100644 --- a/crates/apollo_deployments/resources/app_configs/gateway_config.json +++ b/crates/apollo_deployments/resources/app_configs/gateway_config.json @@ -9,6 +9,7 @@ "gateway_config.stateless_tx_validator_config.max_calldata_length": 5000, "gateway_config.stateless_tx_validator_config.max_contract_bytecode_size": 81920, "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, + "gateway_config.stateless_tx_validator_config.max_l2_gas_amount": 1100000000, "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 7, "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 0, diff --git a/crates/apollo_gateway/src/config.rs b/crates/apollo_gateway/src/config.rs index cb98678ed9e..e8b92733b60 100644 --- a/crates/apollo_gateway/src/config.rs +++ b/crates/apollo_gateway/src/config.rs @@ -108,8 +108,10 @@ where pub struct StatelessTransactionValidatorConfig { // If true, ensures that at least one resource bound (L1, L2, or L1 data) is greater than zero. pub validate_resource_bounds: bool, - // TODO(AlonH): Remove this field and use the one from the versioned constants. + // TODO(AlonH): Remove the `min_gas_price` field from this struct and use the one from the + // versioned constants. pub min_gas_price: u128, + pub max_l2_gas_amount: u64, pub max_calldata_length: usize, pub max_signature_length: usize, @@ -125,6 +127,7 @@ impl Default for StatelessTransactionValidatorConfig { StatelessTransactionValidatorConfig { validate_resource_bounds: true, min_gas_price: 3_000_000_000, + max_l2_gas_amount: 1_100_000_000, max_calldata_length: 4000, max_signature_length: 4000, max_contract_bytecode_size: 81920, @@ -175,6 +178,12 @@ impl SerializeConfig for StatelessTransactionValidatorConfig { "Minimum gas price for transactions.", ParamPrivacyInput::Public, ), + ser_param( + "max_l2_gas_amount", + &self.max_l2_gas_amount, + "Maximum allowed L2 gas amount for transactions.", + ParamPrivacyInput::Public, + ), ]); vec![ members, diff --git a/crates/apollo_gateway/src/errors.rs b/crates/apollo_gateway/src/errors.rs index 9d6ec7ce0a5..553ffa0fb5c 100644 --- a/crates/apollo_gateway/src/errors.rs +++ b/crates/apollo_gateway/src/errors.rs @@ -13,6 +13,7 @@ use reqwest::StatusCode; use serde_json::{Error as SerdeError, Value}; use starknet_api::block::GasPrice; use starknet_api::executable_transaction::ValidateCompiledClassHashError; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::AllResourceBounds; use starknet_api::StarknetApiError; use thiserror::Error; @@ -76,6 +77,11 @@ pub enum StatelessTransactionValidatorError { "Max gas price is too low: {gas_price:?}, minimum required gas price: {min_gas_price:?}." )] MaxGasPriceTooLow { gas_price: GasPrice, min_gas_price: u128 }, + #[error( + "Max gas amount is too high: {gas_amount:?}, maximum allowed gas amount: \ + {max_gas_amount:?}." + )] + MaxGasAmountTooHigh { gas_amount: GasAmount, max_gas_amount: u64 }, } impl From for GatewaySpecError { @@ -96,7 +102,8 @@ impl From for GatewaySpecError { | StatelessTransactionValidatorError::SignatureTooLong { .. } | StatelessTransactionValidatorError::StarknetApiError(..) | StatelessTransactionValidatorError::ZeroResourceBounds { .. } - | StatelessTransactionValidatorError::MaxGasPriceTooLow { .. } => { + | StatelessTransactionValidatorError::MaxGasPriceTooLow { .. } + | StatelessTransactionValidatorError::MaxGasAmountTooHigh { .. } => { GatewaySpecError::ValidationFailure { data: e.to_string() } } } @@ -134,7 +141,6 @@ impl From for StarknetError { "StarknetErrorCode.ENTRY_POINTS_NOT_UNIQUELY_SORTED".to_string(), ) } - StatelessTransactionValidatorError::InvalidDataAvailabilityMode { .. } => // Error does not exist in deprecated GW. { @@ -142,7 +148,6 @@ impl From for StarknetError { "StarknetErrorCode.INVALID_DATA_AVAILABILITY_MODE".to_string(), ) } - StatelessTransactionValidatorError::InvalidSierraVersion(..) => // Error does not exist in deprecated GW. { @@ -150,12 +155,16 @@ impl From for StarknetError { "StarknetErrorCode.INVALID_SIERRA_VERSION".to_string(), ) } + StatelessTransactionValidatorError::MaxGasAmountTooHigh { .. } => { + StarknetErrorCode::UnknownErrorCode( + "StarknetErrorCode.MAX_GAS_AMOUNT_TOO_HIGH".to_string(), + ) + } StatelessTransactionValidatorError::NonEmptyField { .. } => // Error does not exist in deprecated GW. { StarknetErrorCode::UnknownErrorCode("StarknetErrorCode.NON_EMPTY_FIELD".to_string()) } - StatelessTransactionValidatorError::SignatureTooLong { .. } => { StarknetErrorCode::UnknownErrorCode( "StarknetErrorCode.SIGNATURE_TOO_LONG".to_string(), diff --git a/crates/apollo_gateway/src/metrics.rs b/crates/apollo_gateway/src/metrics.rs index 5d21145b8de..942c9525ac6 100644 --- a/crates/apollo_gateway/src/metrics.rs +++ b/crates/apollo_gateway/src/metrics.rs @@ -90,6 +90,7 @@ pub enum GatewayAddTxFailureReason { NonEmptyField, SignatureTooLong, StarknetApiError, + MaxGasAmountTooHigh, NonceTooLarge, BlockedTransactionType, InternalError, @@ -218,6 +219,8 @@ fn map_starknet_error_to_gateway_add_tx_failure_reason( GatewayAddTxFailureReason::SignatureTooLong } else if s.contains("STARKNET_API_ERROR") { GatewayAddTxFailureReason::StarknetApiError + } else if s.contains("MAX_GAS_AMOUNT_TOO_HIGH") { + GatewayAddTxFailureReason::MaxGasAmountTooHigh } else if s.contains("NONCE_TOO_LARGE") { GatewayAddTxFailureReason::NonceTooLarge } else if s.contains("InternalError") { diff --git a/crates/apollo_gateway/src/stateless_transaction_validator.rs b/crates/apollo_gateway/src/stateless_transaction_validator.rs index a51c8969f30..a6e6b4e1c0c 100644 --- a/crates/apollo_gateway/src/stateless_transaction_validator.rs +++ b/crates/apollo_gateway/src/stateless_transaction_validator.rs @@ -65,6 +65,13 @@ impl StatelessTransactionValidator { }); } + if resource_bounds.l2_gas.max_amount.0 > self.config.max_l2_gas_amount { + return Err(StatelessTransactionValidatorError::MaxGasAmountTooHigh { + gas_amount: resource_bounds.l2_gas.max_amount, + max_gas_amount: self.config.max_l2_gas_amount, + }); + } + Ok(()) } diff --git a/crates/apollo_gateway/src/stateless_transaction_validator_test.rs b/crates/apollo_gateway/src/stateless_transaction_validator_test.rs index ae19f8006ff..5d94faaf71a 100644 --- a/crates/apollo_gateway/src/stateless_transaction_validator_test.rs +++ b/crates/apollo_gateway/src/stateless_transaction_validator_test.rs @@ -6,6 +6,7 @@ use rstest::rstest; use starknet_api::block::GasPrice; use starknet_api::core::{EntryPointSelector, L2_ADDRESS_UPPER_BOUND}; use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::execution_resources::GasAmount; use starknet_api::rpc_transaction::EntryPointByType; use starknet_api::state::{EntryPoint, SierraContractClass}; use starknet_api::test_utils::declare::rpc_declare_tx; @@ -43,10 +44,11 @@ static DEFAULT_VALIDATOR_CONFIG_FOR_TESTING: LazyLock Date: Thu, 16 Oct 2025 12:45:10 +0300 Subject: [PATCH 048/313] starknet_committer_and_os_cli: compute_blob_commmitments (#9591) --- .../src/kzg_cli.rs | 1 + .../src/kzg_cli/run_kzg_cli.rs | 36 ++++++++ .../starknet_committer_and_os_cli/src/lib.rs | 1 + .../starknet_committer_and_os_cli/src/main.rs | 6 ++ .../hints/hint_implementation/kzg/utils.rs | 83 ++++++++++++++++++- 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 crates/starknet_committer_and_os_cli/src/kzg_cli.rs create mode 100644 crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs diff --git a/crates/starknet_committer_and_os_cli/src/kzg_cli.rs b/crates/starknet_committer_and_os_cli/src/kzg_cli.rs new file mode 100644 index 00000000000..30525d0e6d7 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/kzg_cli.rs @@ -0,0 +1 @@ +pub mod run_kzg_cli; diff --git a/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs b/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs new file mode 100644 index 00000000000..828243ac2c8 --- /dev/null +++ b/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs @@ -0,0 +1,36 @@ +use clap::{Parser, Subcommand}; +use starknet_os::hints::hint_implementation::kzg::utils::{ + compute_blob_commitments, + SerializableBlobs, +}; +use tracing::info; + +use crate::shared_utils::read::{load_input, write_to_file}; +use crate::shared_utils::types::IoArgs; + +#[derive(Parser, Debug)] +pub struct KzgCliCommand { + #[clap(subcommand)] + command: Command, +} + +#[derive(Debug, Subcommand)] +enum Command { + ComputeBlobCommitments { + #[clap(flatten)] + io_args: IoArgs, + }, +} + +pub fn run_kzg_cli(kzg_command: KzgCliCommand) { + info!("Starting KZG CLI with command: \n{:?}", kzg_command); + match kzg_command.command { + Command::ComputeBlobCommitments { io_args: IoArgs { input_path, output_path } } => { + let raw_blobs: Vec> = load_input(input_path); + let blobs = compute_blob_commitments(raw_blobs) + .unwrap_or_else(|error| panic!("Failed to calculate blob commitments: {error}")); + let serializable_blobs = SerializableBlobs::from(blobs); + write_to_file(&output_path, &serializable_blobs); + } + }; +} diff --git a/crates/starknet_committer_and_os_cli/src/lib.rs b/crates/starknet_committer_and_os_cli/src/lib.rs index b1c73f78349..027abffabcd 100644 --- a/crates/starknet_committer_and_os_cli/src/lib.rs +++ b/crates/starknet_committer_and_os_cli/src/lib.rs @@ -1,5 +1,6 @@ pub mod block_hash_cli; pub mod committer_cli; +pub mod kzg_cli; pub mod os_cli; pub mod shared_utils; pub mod tracing_utils; diff --git a/crates/starknet_committer_and_os_cli/src/main.rs b/crates/starknet_committer_and_os_cli/src/main.rs index d43d6cec7fc..de41354bfdc 100644 --- a/crates/starknet_committer_and_os_cli/src/main.rs +++ b/crates/starknet_committer_and_os_cli/src/main.rs @@ -7,6 +7,7 @@ use starknet_committer_and_os_cli::committer_cli::run_committer_cli::{ run_committer_cli, CommitterCliCommand, }; +use starknet_committer_and_os_cli::kzg_cli::run_kzg_cli::{run_kzg_cli, KzgCliCommand}; use starknet_committer_and_os_cli::os_cli::run_os_cli::{run_os_cli, OsCliCommand}; use starknet_committer_and_os_cli::tracing_utils::configure_tracing; use tracing::info; @@ -28,6 +29,8 @@ enum CommitterOrOsCommand { Committer(CommitterCliCommand), /// Run BlockHash CLI. BlockHash(BlockHashCliCommand), + /// Run KZG CLI. + Kzg(KzgCliCommand), /// Run OS CLI. OS(OsCliCommand), } @@ -55,5 +58,8 @@ async fn main() { CommitterOrOsCommand::BlockHash(command) => { run_block_hash_cli(command).await; } + CommitterOrOsCommand::Kzg(command) => { + run_kzg_cli(command); + } } } diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs index af365d365ea..78aa0803da4 100644 --- a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs @@ -4,9 +4,11 @@ use std::sync::LazyLock; use ark_bls12_381::Fr; use ark_ff::{BigInteger, PrimeField}; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; -use c_kzg::{Blob, KzgCommitment, KzgSettings, BYTES_PER_FIELD_ELEMENT}; +use c_kzg::{Blob, KzgCommitment, KzgProof, KzgSettings, BYTES_PER_FIELD_ELEMENT}; use num_bigint::{BigInt, BigUint, ParseBigIntError}; use num_traits::{Num, Signed, Zero}; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use starknet_types_core::felt::Felt; use crate::hints::error::OsHintError; @@ -157,3 +159,82 @@ pub fn split_bigint3(num: BigInt) -> Result<[Felt; 3], OsHintError> { Ok([d0, d1, Felt::from(d2)]) } + +/// Structure to hold blob data, commitments, proofs, and versioned hashes. +pub struct Blobs { + pub blobs: Vec>, + pub commitments: Vec, + pub proofs: Vec, + pub versioned_hashes: Vec<[u8; 32]>, +} + +/// Serializable structure to hold blob data, commitments, proofs, and versioned hashes. +/// All cryptographic objects are converted to byte arrays for easy serialization. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct SerializableBlobs { + pub blobs: Vec>, + pub commitments: Vec>, // 48 bytes each + pub proofs: Vec>, // 48 bytes each + pub versioned_hashes: Vec>, // 32 bytes each +} +impl From for SerializableBlobs { + fn from(Blobs { blobs, commitments, proofs, versioned_hashes }: Blobs) -> Self { + Self { + blobs, + commitments: commitments + .into_iter() + .map(|commitment| commitment.to_bytes().as_ref().to_vec()) + .collect(), + proofs: proofs.into_iter().map(|proof| proof.to_bytes().as_ref().to_vec()).collect(), + versioned_hashes: versioned_hashes.into_iter().map(|hash| hash.to_vec()).collect(), + } + } +} + +/// Computes a versioned hash from a KZG commitment. +fn kzg_to_versioned_hash(commitment: &KzgCommitment) -> [u8; 32] { + const BLOB_COMMITMENT_VERSION_KZG: u8 = 0x01; + + // Get commitment bytes (48 bytes). + let commitment_bytes = commitment.to_bytes(); + + // Compute SHA256 of the commitment. + let mut hasher = Sha256::new(); + hasher.update(commitment_bytes.as_ref()); + let mut hash = hasher.finalize(); + hash[0] = BLOB_COMMITMENT_VERSION_KZG; + + hash.into() +} + +/// Computes KZG commitments, proofs, and versioned hashes for a list of raw blobs. +/// +/// For each blob, computes the KZG commitment and the corresponding KZG proof that is used +/// to verify the commitment. Returns the internal `Blobs` structure with native KZG types. +pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result { + let mut blobs = Vec::new(); + let mut commitments = Vec::new(); + let mut proofs = Vec::new(); + let mut versioned_hashes = Vec::new(); + + for raw_blob in raw_blobs.iter() { + // Convert raw blob bytes to Blob. + let blob = Blob::from_bytes(raw_blob)?; + + // Compute KZG commitment. + let commitment = blob_to_kzg_commitment(&blob)?; + + // Compute KZG proof. + let proof = KzgProof::compute_blob_kzg_proof(&blob, &commitment.to_bytes(), &KZG_SETTINGS)?; + + // Compute versioned hash. + let versioned_hash = kzg_to_versioned_hash(&commitment); + + blobs.push(raw_blob.clone()); + commitments.push(commitment); + proofs.push(proof); + versioned_hashes.push(versioned_hash); + } + + Ok(Blobs { blobs, commitments, proofs, versioned_hashes }) +} From 6d1d857c20c0b5a7542ccc809c9c2fb1cca7d055 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 16 Oct 2025 12:54:57 +0300 Subject: [PATCH 049/313] apollo_rpc: fix typo in apollo rpc (#9540) From efae364e5f89dba7f28d437d3ce8c4e01b491616 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 16 Oct 2025 13:38:22 +0300 Subject: [PATCH 050/313] apollo_batcher: add a metric for number of transactions per block (#9592) --- crates/apollo_batcher/src/batcher.rs | 2 ++ crates/apollo_batcher/src/metrics.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/crates/apollo_batcher/src/batcher.rs b/crates/apollo_batcher/src/batcher.rs index 02c5f06ce45..09f69b03c96 100644 --- a/crates/apollo_batcher/src/batcher.rs +++ b/crates/apollo_batcher/src/batcher.rs @@ -67,6 +67,7 @@ use crate::metrics::{ LAST_BATCHED_BLOCK_HEIGHT, LAST_PROPOSED_BLOCK_HEIGHT, LAST_SYNCED_BLOCK_HEIGHT, + NUM_TRANSACTION_IN_BLOCK, REJECTED_TRANSACTIONS, REVERTED_BLOCKS, REVERTED_TRANSACTIONS, @@ -633,6 +634,7 @@ impl Batcher { BATCHED_TRANSACTIONS.increment(n_txs); REJECTED_TRANSACTIONS.increment(n_rejected_txs); REVERTED_TRANSACTIONS.increment(n_reverted_count); + NUM_TRANSACTION_IN_BLOCK.record_lossy(n_txs); Ok(DecisionReachedResponse { state_diff, diff --git a/crates/apollo_batcher/src/metrics.rs b/crates/apollo_batcher/src/metrics.rs index 8dae8580534..17bf589e6b6 100644 --- a/crates/apollo_batcher/src/metrics.rs +++ b/crates/apollo_batcher/src/metrics.rs @@ -42,6 +42,7 @@ define_metrics!( MetricCounter { REJECTED_TRANSACTIONS, "batcher_rejected_transactions", "Counter of rejected transactions", init = 0 }, MetricCounter { REVERTED_TRANSACTIONS, "batcher_reverted_transactions", "Counter of reverted transactions across all forks", init = 0 }, MetricCounter { SYNCED_TRANSACTIONS, "batcher_synced_transactions", "Counter of synced transactions", init = 0 }, + MetricHistogram { NUM_TRANSACTION_IN_BLOCK, "batcher_num_transaction_in_block", "Number of transactions in a block"}, MetricCounter { BATCHER_L1_PROVIDER_ERRORS, "batcher_l1_provider_errors", "Counter of L1 provider errors", init = 0 }, MetricCounter { PRECONFIRMED_BLOCK_WRITTEN, "batcher_preconfirmed_block_written", "Counter of preconfirmed blocks written to storage", init = 0 }, @@ -87,6 +88,7 @@ pub fn register_metrics(storage_height: BlockNumber) { BATCHER_L1_PROVIDER_ERRORS.register(); PRECONFIRMED_BLOCK_WRITTEN.register(); BLOCK_CLOSE_REASON.register(); + NUM_TRANSACTION_IN_BLOCK.register(); // Blockifier's metrics CALLS_RUNNING_NATIVE.register(); From 3f056229d5f19d73226e3f96828972fa8842d6be Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 16 Oct 2025 14:28:36 +0300 Subject: [PATCH 051/313] apollo_dashboard: Add an alert for when we have too many empty blocks (#9593) --- .../resources/dev_grafana_alerts_mainnet.json | 28 ++++++++++ .../resources/dev_grafana_alerts_testnet.json | 28 ++++++++++ .../apollo_dashboard/src/alert_definitions.rs | 2 + .../src/alert_scenarios/transaction_delays.rs | 55 +++++++++++++++++++ 4 files changed, 113 insertions(+) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json index 04eaf4fb029..3e91c072ccf 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json @@ -1316,6 +1316,34 @@ "severity": "p4", "observer_applicable": "false" }, + { + "name": "high_empty_blocks_ratio", + "title": "High ratio of empty blocks", + "ruleGroup": "batcher", + "expr": "sum(increase(batcher_num_transaction_in_block_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\", le=\"0.001\"}[120s])) / clamp_min(sum(increase(batcher_num_transaction_in_block_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}[120s])), 1)", + "conditions": [ + { + "evaluator": { + "params": [ + 0.3 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "30s", + "intervalSec": 30, + "severity": "p1", + "observer_applicable": "false" + }, { "name": "l1_gas_price_provider_insufficient_history", "title": "L1 gas price provider insufficient history", diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json index c8b1ff501c1..83502e3a9b0 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json @@ -1400,6 +1400,34 @@ "severity": "p4", "observer_applicable": "false" }, + { + "name": "high_empty_blocks_ratio", + "title": "High ratio of empty blocks", + "ruleGroup": "batcher", + "expr": "sum(increase(batcher_num_transaction_in_block_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\", le=\"0.001\"}[300s])) / clamp_min(sum(increase(batcher_num_transaction_in_block_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}[300s])), 1)", + "conditions": [ + { + "evaluator": { + "params": [ + 0.6 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "30s", + "intervalSec": 30, + "severity": "p2", + "observer_applicable": "false" + }, { "name": "l1_gas_price_provider_insufficient_history", "title": "L1 gas price provider insufficient history", diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index 81449a923f1..092b6605b72 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -70,6 +70,7 @@ use crate::alert_scenarios::tps::{ get_mempool_add_tx_idle, }; use crate::alert_scenarios::transaction_delays::{ + get_high_empty_blocks_ratio_alert_vec, get_http_server_avg_add_tx_latency_alert_vec, get_http_server_p95_add_tx_latency_alert_vec, get_mempool_p2p_peer_down_vec, @@ -563,6 +564,7 @@ pub fn get_apollo_alerts(alert_env_filtering: AlertEnvFiltering) -> Alerts { alerts.append(&mut get_http_server_internal_error_ratio_vec()); alerts.append(&mut get_gateway_low_successful_transaction_rate_vec()); alerts.append(&mut get_http_server_p95_add_tx_latency_alert_vec()); + alerts.append(&mut get_high_empty_blocks_ratio_alert_vec()); alerts.append(&mut get_l1_gas_price_provider_insufficient_history_alert_vec()); alerts.append(&mut get_l1_gas_price_scraper_success_count_alert_vec()); alerts.append(&mut get_l1_message_scraper_no_successes_alert_vec()); diff --git a/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs b/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs index ff51a821d45..a03bca2923a 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs @@ -1,3 +1,4 @@ +use apollo_batcher::metrics::NUM_TRANSACTION_IN_BLOCK; use apollo_http_server::metrics::HTTP_SERVER_ADD_TX_LATENCY; use apollo_mempool_p2p::metrics::MEMPOOL_P2P_NUM_CONNECTED_PEERS; @@ -130,3 +131,57 @@ pub(crate) fn get_http_server_p95_add_tx_latency_alert_vec() -> Vec { ), ] } + +fn get_high_empty_blocks_ratio_alert( + alert_env_filtering: AlertEnvFiltering, + alert_severity: AlertSeverity, + ratio: f64, + time_window_seconds: u64, +) -> Alert { + // Our histogram buckets are static and the smallest bucket is 0.001. + let zero_bucket = format!( + "{}, le=\"0.001\"}}", + NUM_TRANSACTION_IN_BLOCK + .get_name_with_filter() + .strip_suffix("}") + .expect("Metric name with filter should end with }") + ); + let total_count = NUM_TRANSACTION_IN_BLOCK.get_name_count_with_filter(); + + Alert::new( + "high_empty_blocks_ratio", + "High ratio of empty blocks", + AlertGroup::Batcher, + format!( + "sum(increase({zero_bucket}[{}s])) / clamp_min(sum(increase({total_count}[{}s])), 1)", + time_window_seconds, time_window_seconds + ), + vec![AlertCondition { + comparison_op: AlertComparisonOp::GreaterThan, + comparison_value: ratio, + logical_op: AlertLogicalOp::And, + }], + PENDING_DURATION_DEFAULT, + EVALUATION_INTERVAL_SEC_DEFAULT, + alert_severity, + ObserverApplicability::NotApplicable, + alert_env_filtering, + ) +} + +pub(crate) fn get_high_empty_blocks_ratio_alert_vec() -> Vec { + vec![ + get_high_empty_blocks_ratio_alert( + AlertEnvFiltering::MainnetStyleAlerts, + AlertSeverity::Sos, + 0.3, + 120, + ), + get_high_empty_blocks_ratio_alert( + AlertEnvFiltering::TestnetStyleAlerts, + AlertSeverity::Regular, + 0.6, + 300, + ), + ] +} From 859ceda31d451e30d6b4cd8d5744ab2837f98fec Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 16 Oct 2025 14:38:04 +0300 Subject: [PATCH 052/313] apollo_dashboard: add a graph for average number of transactions per block (#9600) --- crates/apollo_dashboard/resources/dev_grafana.json | 10 ++++++++++ crates/apollo_dashboard/src/panels/blockifier.rs | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 4383dad23c6..0f645581ff3 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -915,6 +915,16 @@ "extra_params": { "unit": "percentunit" } + }, + { + "title": "Transactions Per Block", + "description": "The number of transactions per block", + "type": "timeseries", + "exprs": [ + "histogram_quantile(0.50, sum by (le) (rate(batcher_num_transaction_in_block_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))", + "histogram_quantile(0.95, sum by (le) (rate(batcher_num_transaction_in_block_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))" + ], + "extra_params": {} } ], "collapsed": true diff --git a/crates/apollo_dashboard/src/panels/blockifier.rs b/crates/apollo_dashboard/src/panels/blockifier.rs index 6f6fdc8ab65..74b74584c10 100644 --- a/crates/apollo_dashboard/src/panels/blockifier.rs +++ b/crates/apollo_dashboard/src/panels/blockifier.rs @@ -1,3 +1,4 @@ +use apollo_batcher::metrics::NUM_TRANSACTION_IN_BLOCK; use blockifier::metrics::{ BLOCKIFIER_METRIC_RATE_DURATION, CALLS_RUNNING_NATIVE, @@ -47,6 +48,14 @@ fn get_panel_native_execution_ratio() -> Panel { ) } +fn get_panel_transactions_per_block() -> Panel { + Panel::from_hist( + &NUM_TRANSACTION_IN_BLOCK, + "Transactions Per Block", + "The number of transactions per block", + ) +} + pub(crate) fn get_blockifier_row() -> Row { Row::new( "Blockifier", @@ -55,6 +64,7 @@ pub(crate) fn get_blockifier_row() -> Row { get_panel_blockifier_state_reader_native_class_returned_ratio(), get_panel_native_compilation_error(), get_panel_native_execution_ratio(), + get_panel_transactions_per_block(), ], ) } From 7a53ee9e83ed533fa9cf20709b522498a550309a Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 16 Oct 2025 14:42:53 +0300 Subject: [PATCH 053/313] apollo_dashboard: change the block time for alerts from 6 to 9 seconds (#9588) --- .../resources/dev_grafana_alerts_mainnet.json | 6 +++--- .../resources/dev_grafana_alerts_testnet.json | 6 +++--- crates/apollo_dashboard/src/alert_definitions.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json index 3e91c072ccf..8f5426a0b23 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json @@ -849,7 +849,7 @@ { "evaluator": { "params": [ - 10.0 + 6.666666666666667 ], "type": "lt" }, @@ -1017,7 +1017,7 @@ { "evaluator": { "params": [ - 30.0 + 20.0 ], "type": "gt" }, @@ -1045,7 +1045,7 @@ { "evaluator": { "params": [ - 20.0 + 13.333333333333334 ], "type": "gt" }, diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json index 83502e3a9b0..ff60cf18448 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json @@ -877,7 +877,7 @@ { "evaluator": { "params": [ - 10.0 + 6.666666666666667 ], "type": "lt" }, @@ -1101,7 +1101,7 @@ { "evaluator": { "params": [ - 30.0 + 20.0 ], "type": "gt" }, @@ -1129,7 +1129,7 @@ { "evaluator": { "params": [ - 20.0 + 13.333333333333334 ], "type": "gt" }, diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index 092b6605b72..bacf38a73e3 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -97,7 +97,7 @@ use crate::alerts::{ }; /// Alerts that depend on block time can use this value to define their rule. -pub(crate) const BLOCK_TIME_SEC: f64 = 6.0; +pub(crate) const BLOCK_TIME_SEC: f64 = 9.0; pub fn get_dev_alerts_json_path(alert_env_filtering: AlertEnvFiltering) -> String { format!("crates/apollo_dashboard/resources/dev_grafana_alerts_{}.json", alert_env_filtering) From 4dae10e844c37b1c5c0d562a19e16a4b11f5e471 Mon Sep 17 00:00:00 2001 From: ron-starkware Date: Thu, 16 Oct 2025 15:53:19 +0300 Subject: [PATCH 054/313] apollo_class_manager: Write classes atomically using temp dir (#9532) --- .../src/class_manager_test.rs | 8 ++- .../apollo_class_manager/src/class_storage.rs | 46 ++++++++++------ .../src/class_storage_test.rs | 54 ++++++++++++++----- crates/apollo_class_manager/src/lib.rs | 13 ++++- .../src/state_reader.rs | 2 +- 5 files changed, 89 insertions(+), 34 deletions(-) diff --git a/crates/apollo_class_manager/src/class_manager_test.rs b/crates/apollo_class_manager/src/class_manager_test.rs index df4c8d3cd4e..e039121e1f1 100644 --- a/crates/apollo_class_manager/src/class_manager_test.rs +++ b/crates/apollo_class_manager/src/class_manager_test.rs @@ -12,12 +12,16 @@ use starknet_api::felt; use starknet_api::state::SierraContractClass; use crate::class_manager::ClassManager; -use crate::class_storage::{create_tmp_dir, FsClassStorage}; +use crate::class_storage::FsClassStorage; impl ClassManager { fn new_for_testing(compiler: MockSierraCompilerClient, config: ClassManagerConfig) -> Self { + let persistent_root = tempfile::tempdir().unwrap(); + let class_hash_storage_path_prefix = tempfile::tempdir().unwrap(); + std::fs::create_dir_all(persistent_root.path()).unwrap(); + std::fs::create_dir_all(class_hash_storage_path_prefix.path()).unwrap(); let storage = - FsClassStorage::new_for_testing(&create_tmp_dir().unwrap(), &create_tmp_dir().unwrap()); + FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); ClassManager::new(config, Arc::new(compiler), storage) } diff --git a/crates/apollo_class_manager/src/class_storage.rs b/crates/apollo_class_manager/src/class_storage.rs index 9e279f90d54..c3832a9b2c1 100644 --- a/crates/apollo_class_manager/src/class_storage.rs +++ b/crates/apollo_class_manager/src/class_storage.rs @@ -319,6 +319,7 @@ impl From for CachedClassStorageError impl FsClassStorage { pub fn new(config: FsClassStorageConfig) -> FsClassStorageResult { let class_hash_storage = ClassHashStorage::new(config.class_hash_storage_config)?; + std::fs::create_dir_all(&config.persistent_root)?; Ok(Self { persistent_root: config.persistent_root, class_hash_storage }) } @@ -370,6 +371,29 @@ impl FsClassStorage { concat_deprecated_executable_filename(&self.get_persistent_dir(class_id)) } + fn create_tmp_dir( + &self, + class_id: ClassId, + ) -> FsClassStorageResult<(tempfile::TempDir, PathBuf)> { + // Compute the final persistent directory for this `class_id` + let persistent_dir = self.get_persistent_dir(class_id); + let parent_dir = persistent_dir + .parent() + .expect("Class persistent dir should have a parent") + .to_path_buf(); + std::fs::create_dir_all(&parent_dir)?; + // Create a temporary directory under the parent of the final persistent directory to ensure + // `rename` will be atomic. + let tmp_root = tempfile::tempdir_in(&parent_dir)?; + // Get the leaf directory name of the final persistent directory. + let leaf = persistent_dir.file_name().expect("Class dir leaf should exist"); + // Create the temporary directory under the temporary root. + let tmp_dir = tmp_root.path().join(leaf); + // Returning `TempDir` since without it the handle would drop immediately and the temp + // directory would be removed before writes/rename. + Ok((tmp_root, tmp_dir)) + } + fn mark_class_id_as_existent( &mut self, class_id: ClassId, @@ -380,6 +404,7 @@ impl FsClassStorage { .set_executable_class_hash_v2(class_id, executable_class_hash_v2)?) } + #[allow(dead_code)] fn write_class( &self, class_id: ClassId, @@ -393,6 +418,7 @@ impl FsClassStorage { Ok(()) } + #[allow(dead_code)] fn write_deprecated_class( &self, class_id: ClassId, @@ -404,9 +430,6 @@ impl FsClassStorage { Ok(()) } - // TODO(Elin): restore use of `write_[deprecated_]class_atomically`, but tmpdir - // should be located inside the PVC to prevent linking errors. - #[allow(dead_code)] fn write_class_atomically( &self, class_id: ClassId, @@ -414,8 +437,7 @@ impl FsClassStorage { executable_class: RawExecutableClass, ) -> FsClassStorageResult<()> { // Write classes to a temporary directory. - let tmp_dir = create_tmp_dir()?; - let tmp_dir = tmp_dir.path().join(self.get_class_dir(class_id)); + let (_tmp_root, tmp_dir) = self.create_tmp_dir(class_id)?; class.write_to_file(concat_sierra_filename(&tmp_dir))?; executable_class.write_to_file(concat_executable_filename(&tmp_dir))?; @@ -426,15 +448,13 @@ impl FsClassStorage { Ok(()) } - #[allow(dead_code)] fn write_deprecated_class_atomically( &self, class_id: ClassId, class: RawExecutableClass, ) -> FsClassStorageResult<()> { // Write class to a temporary directory. - let tmp_dir = create_tmp_dir()?; - let tmp_dir = tmp_dir.path().join(self.get_class_dir(class_id)); + 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. @@ -460,7 +480,7 @@ impl ClassStorage for FsClassStorage { return Ok(()); } - self.write_class(class_id, class, executable_class)?; + self.write_class_atomically(class_id, class, executable_class)?; self.mark_class_id_as_existent(class_id, executable_class_hash)?; Ok(()) @@ -513,7 +533,7 @@ impl ClassStorage for FsClassStorage { return Ok(()); } - self.write_deprecated_class(class_id, class)?; + self.write_deprecated_class_atomically(class_id, class)?; Ok(()) } @@ -555,9 +575,3 @@ fn concat_executable_filename(path: &Path) -> PathBuf { fn concat_deprecated_executable_filename(path: &Path) -> PathBuf { path.join("deprecated_casm") } - -// Creates a tmp directory and returns a owned representation of it. -// As long as the returned directory object is lived, the directory is not deleted. -pub(crate) fn create_tmp_dir() -> FsClassStorageResult { - Ok(tempfile::tempdir()?) -} diff --git a/crates/apollo_class_manager/src/class_storage_test.rs b/crates/apollo_class_manager/src/class_storage_test.rs index ae157d1dcde..5d7a6694c6f 100644 --- a/crates/apollo_class_manager/src/class_storage_test.rs +++ b/crates/apollo_class_manager/src/class_storage_test.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use apollo_class_manager_config::config::{CachedClassStorageConfig, ClassHashDbConfig}; use apollo_class_manager_types::CachedClassStorageError; use apollo_compile_to_casm_types::{RawClass, RawExecutableClass}; @@ -8,7 +10,6 @@ use starknet_api::felt; use starknet_api::state::SierraContractClass; use crate::class_storage::{ - create_tmp_dir, CachedClassStorage, ClassHashStorage, ClassHashStorageConfig, @@ -42,14 +43,15 @@ impl FsClassStorage { class_hash_storage_path_prefix: &tempfile::TempDir, ) -> Self { let class_hash_storage = ClassHashStorage::new_for_testing(class_hash_storage_path_prefix); + std::fs::create_dir_all(persistent_root.path()).unwrap(); Self { persistent_root: persistent_root.path().to_path_buf(), class_hash_storage } } } #[test] fn fs_storage() { - let persistent_root = create_tmp_dir().unwrap(); - let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + 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); @@ -84,8 +86,8 @@ fn fs_storage() { #[test] fn fs_storage_deprecated_class_api() { - let persistent_root = create_tmp_dir().unwrap(); - let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + 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); @@ -105,13 +107,39 @@ fn fs_storage_deprecated_class_api() { storage.set_deprecated_class(class_id, executable_class).unwrap(); } +#[test] +fn temp_dir_location_and_atomic_write_layout() { + let persistent_root = tempfile::tempdir().unwrap(); + let class_hash_storage_path_prefix = tempfile::tempdir().unwrap(); + let storage = + FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); + + let class_id = ClassHash(felt!("0x1234")); + let persistent_dir = storage.persistent_root.join({ + let hex = hex::encode(class_id.to_bytes_be()); + let (a, b) = (&hex[..2], &hex[2..4]); + PathBuf::from(a).join(b).join(hex) + }); + + // Create tmp dir via the atomic writer and ensure it resides under parent_dir. + let class = RawClass::try_from(SierraContractClass::default()).unwrap(); + let executable_class = + RawExecutableClass::try_from(ContractClass::test_casm_contract_class()).unwrap(); + storage.write_class_atomically(class_id, class.clone(), executable_class.clone()).unwrap(); + + // After atomic write and rename, the persistent dir should exist and contain the files. + assert!(persistent_dir.exists()); + assert!(persistent_dir.join("sierra").exists()); + assert!(persistent_dir.join("casm").exists()); +} + #[test] fn fs_storage_nonexistent_persistent_root_is_created() { - let parent_dir = create_tmp_dir().unwrap(); + let parent_dir = tempfile::tempdir().unwrap(); let nonexistent_root = parent_dir.path().join("nonexistent_root"); assert!(!nonexistent_root.exists()); - let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let class_hash_storage_path_prefix = tempfile::tempdir().unwrap(); let class_hash_storage = ClassHashStorage::new_for_testing(&class_hash_storage_path_prefix); let mut storage = FsClassStorage { persistent_root: nonexistent_root.clone(), class_hash_storage }; @@ -138,8 +166,8 @@ fn fs_storage_nonexistent_persistent_root_is_created() { // TODO(Elin): should this flow return an error? #[test] fn fs_storage_partial_write_only_atomic_marker() { - let persistent_root = create_tmp_dir().unwrap(); - let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + 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); @@ -156,8 +184,8 @@ fn fs_storage_partial_write_only_atomic_marker() { #[test] fn fs_storage_partial_write_no_atomic_marker() { - let persistent_root = create_tmp_dir().unwrap(); - let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let persistent_root = tempfile::tempdir().unwrap(); + let class_hash_storage_path_prefix = tempfile::tempdir().unwrap(); let storage = FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); @@ -239,8 +267,8 @@ fn cached_storage_cairo1_get_executable_and_hash() { #[test] fn cached_storage_cairo0_get_executable_and_no_hash() { - let persistent_root = create_tmp_dir().unwrap(); - let class_hash_storage_path_prefix = create_tmp_dir().unwrap(); + let persistent_root = tempfile::tempdir().unwrap(); + let class_hash_storage_path_prefix = tempfile::tempdir().unwrap(); let mut fs_storage = FsClassStorage::new_for_testing(&persistent_root, &class_hash_storage_path_prefix); diff --git a/crates/apollo_class_manager/src/lib.rs b/crates/apollo_class_manager/src/lib.rs index 8ecc078777a..3947c4eee0f 100644 --- a/crates/apollo_class_manager/src/lib.rs +++ b/crates/apollo_class_manager/src/lib.rs @@ -1,10 +1,19 @@ pub mod class_manager; -pub mod class_storage; +mod class_storage; pub mod communication; pub mod metrics; +// Re-export selected items from the now-private class_storage module. +pub use class_storage::{ + CachedClassStorage, + ClassHashStorage, + ClassHashStorageError, + ClassStorage, + FsClassStorage, + FsClassStorageError, +}; + use crate::class_manager::ClassManager as GenericClassManager; -use crate::class_storage::FsClassStorage; pub struct FsClassManager(pub GenericClassManager); diff --git a/crates/apollo_integration_tests/src/state_reader.rs b/crates/apollo_integration_tests/src/state_reader.rs index 3c7a102aac7..7ee4c0a6aea 100644 --- a/crates/apollo_integration_tests/src/state_reader.rs +++ b/crates/apollo_integration_tests/src/state_reader.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; -use apollo_class_manager::class_storage::{ClassStorage, FsClassStorage}; use apollo_class_manager::test_utils::FsClassStorageBuilderForTesting; +use apollo_class_manager::{ClassStorage, FsClassStorage}; use apollo_class_manager_config::config::FsClassStorageConfig; use apollo_storage::body::BodyStorageWriter; use apollo_storage::class::ClassStorageWriter; From d799682667c9df3061bf002a320e927aa174b418 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 16 Oct 2025 18:30:04 +0300 Subject: [PATCH 055/313] apollo_compile_to_casm_types: add method that calculates size of serializable efficiently (#9587) --- Cargo.lock | 1 + .../apollo_compile_to_casm_types/Cargo.toml | 1 + .../apollo_compile_to_casm_types/src/lib.rs | 30 ++++++++++++++++++- .../apollo_compile_to_casm_types/src/test.rs | 18 +++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 crates/apollo_compile_to_casm_types/src/test.rs diff --git a/Cargo.lock b/Cargo.lock index f52704d9e33..fe7baf77b35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1029,6 +1029,7 @@ dependencies = [ "apollo_metrics", "apollo_proc_macros", "async-trait", + "expect-test", "mockall", "serde", "serde_json", diff --git a/crates/apollo_compile_to_casm_types/Cargo.toml b/crates/apollo_compile_to_casm_types/Cargo.toml index 79d88aaee01..8dd8a82b543 100644 --- a/crates/apollo_compile_to_casm_types/Cargo.toml +++ b/crates/apollo_compile_to_casm_types/Cargo.toml @@ -25,4 +25,5 @@ strum_macros.workspace = true thiserror.workspace = true [dev-dependencies] +expect-test.workspace = true mockall.workspace = true diff --git a/crates/apollo_compile_to_casm_types/src/lib.rs b/crates/apollo_compile_to_casm_types/src/lib.rs index 7d35e1632f5..fd0cc50198c 100644 --- a/crates/apollo_compile_to_casm_types/src/lib.rs +++ b/crates/apollo_compile_to_casm_types/src/lib.rs @@ -20,6 +20,10 @@ use strum::{EnumVariantNames, VariantNames}; use strum_macros::{AsRefStr, EnumDiscriminants, EnumIter, IntoStaticStr}; use thiserror::Error; +#[cfg(test)] +#[path = "test.rs"] +pub mod test; + pub type SierraCompilerResult = Result; pub type SierraCompilerClientResult = Result; @@ -48,6 +52,30 @@ pub enum RawClassError { WriteError(#[from] serde_json::Error), } +struct CounterWriter { + size_counter: usize, +} + +impl std::io::Write for CounterWriter { + fn write(&mut self, buf: &[u8]) -> Result { + self.size_counter += buf.len(); + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<(), std::io::Error> { + Ok(()) + } +} + +fn size_of_serialized(value: &T) -> Result +where + T: ?Sized + Serialize, +{ + let mut counter = CounterWriter { size_counter: 0 }; + serde_json::to_writer(&mut counter, value)?; + Ok(counter.size_counter) +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct SerializedClass(Arc, std::marker::PhantomData); @@ -57,7 +85,7 @@ impl SerializedClass { } pub fn size(&self) -> RawClassResult { - Ok(serde_json::to_string_pretty(&*self.0)?.len()) + Ok(size_of_serialized(&self.0)?) } fn new(value: serde_json::Value) -> Self { diff --git a/crates/apollo_compile_to_casm_types/src/test.rs b/crates/apollo_compile_to_casm_types/src/test.rs new file mode 100644 index 00000000000..35e505d5973 --- /dev/null +++ b/crates/apollo_compile_to_casm_types/src/test.rs @@ -0,0 +1,18 @@ +use expect_test::expect; + +use crate::size_of_serialized; + +#[test] +fn test_size_of_serialized() { + let value = serde_json::json!({ + "a": 1, + "b": "hello", + "c": [1, 2, 3], + }); + + let size = size_of_serialized(&value).unwrap(); + let serialized_size = serde_json::to_vec(&value).unwrap().len(); + + assert_eq!(size, serialized_size); + expect!["31"].assert_eq(&size.to_string()); +} From 9552005d09da3f1317f32bdee05bedb456d746c1 Mon Sep 17 00:00:00 2001 From: ron-starkware Date: Sat, 18 Oct 2025 13:43:43 +0300 Subject: [PATCH 056/313] apollo_compile_to_casm: Add audited_libfunc_only config for the compiler (#9579) --- .../src/compile_test.rs | 10 ++++---- crates/apollo_compile_to_casm/src/compiler.rs | 3 +-- .../resources/deployment_inputs/mainnet.json | 1 + .../deployment_inputs/potc2_sepolia.json | 1 + .../sepolia_integration.json | 1 + .../deployment_inputs/sepolia_testnet.json | 1 + .../deployment_inputs/stress_test.json | 1 + .../deployment_inputs/upgrade_test.json | 1 + .../mainnet/deployment_config_override.json | 1 + .../potc2/deployment_config_override.json | 1 + .../deployment_config_override.json | 1 + .../deployment_config_override.json | 1 + .../deployment_config_override.json | 1 + .../testing/deployment_config_override.json | 1 + .../deployment_config_override.json | 1 + .../apollo_deployments/src/config_override.rs | 4 ++++ .../src/deployment_definitions.rs | 1 + .../src/deployment_definitions/testing.rs | 1 + .../src/deployments/hybrid.rs | 1 + .../apollo_node/resources/config_schema.json | 5 ++++ .../src/config.rs | 24 ++++++++++++++----- 21 files changed, 50 insertions(+), 12 deletions(-) diff --git a/crates/apollo_compile_to_casm/src/compile_test.rs b/crates/apollo_compile_to_casm/src/compile_test.rs index dbc612d50ba..dac185cb80c 100644 --- a/crates/apollo_compile_to_casm/src/compile_test.rs +++ b/crates/apollo_compile_to_casm/src/compile_test.rs @@ -25,6 +25,7 @@ use crate::{RawClass, SierraCompiler}; const SIERRA_COMPILATION_CONFIG: SierraCompilationConfig = SierraCompilationConfig { max_bytecode_size: DEFAULT_MAX_BYTECODE_SIZE, max_memory_usage: None, + audited_libfuncs_only: false, }; fn compiler() -> SierraToCasmCompiler { @@ -75,6 +76,7 @@ fn test_max_bytecode_size() { let compiler = SierraToCasmCompiler::new(SierraCompilationConfig { max_bytecode_size: expected_casm_bytecode_length, max_memory_usage: None, + audited_libfuncs_only: false, }); let casm_contract_class = compiler .compile(contract_class.clone()) @@ -85,6 +87,7 @@ fn test_max_bytecode_size() { let compiler = SierraToCasmCompiler::new(SierraCompilationConfig { max_bytecode_size: expected_casm_bytecode_length - 1, max_memory_usage: None, + audited_libfuncs_only: false, }); let result = compiler.compile(contract_class); assert_matches!(result, Err(CompilationUtilError::CompilationError(string)) @@ -139,16 +142,14 @@ fn test_max_memory_usage() { let contract_class = get_test_contract(); // Compile the contract class without any memory usage limit to get the expected output. - let compiler = SierraToCasmCompiler::new(SierraCompilationConfig { - max_bytecode_size: DEFAULT_MAX_BYTECODE_SIZE, - max_memory_usage: None, - }); + let compiler = compiler(); let expected_executable_class = compiler.compile(contract_class.clone()).unwrap(); // Positive flow. let compiler = SierraToCasmCompiler::new(SierraCompilationConfig { max_bytecode_size: DEFAULT_MAX_BYTECODE_SIZE, max_memory_usage: Some(DEFAULT_MAX_MEMORY_USAGE), + audited_libfuncs_only: false, }); let executable_class = compiler.compile(contract_class.clone()).unwrap(); assert_eq!(executable_class, expected_executable_class); @@ -157,6 +158,7 @@ fn test_max_memory_usage() { let compiler = SierraToCasmCompiler::new(SierraCompilationConfig { max_bytecode_size: DEFAULT_MAX_BYTECODE_SIZE, max_memory_usage: Some(8 * 1024 * 1024), + audited_libfuncs_only: false, }); let compilation_result = compiler.compile(contract_class); assert_matches!(compilation_result, Err(CompilationUtilError::CompilationError(string)) diff --git a/crates/apollo_compile_to_casm/src/compiler.rs b/crates/apollo_compile_to_casm/src/compiler.rs index 91d2e12a8b7..638dadbb3e4 100644 --- a/crates/apollo_compile_to_casm/src/compiler.rs +++ b/crates/apollo_compile_to_casm/src/compiler.rs @@ -33,9 +33,8 @@ impl SierraToCasmCompiler { "--add-pythonic-hints", "--max-bytecode-size", &self.config.max_bytecode_size.to_string(), - // TODO(Shahak, Elin): Fix this in a safe way. "--allowed-libfuncs-list-name", - "audited", + if self.config.audited_libfuncs_only { "audited" } else { "all" }, ]; let resource_limits = ResourceLimits::new(None, None, self.config.max_memory_usage); diff --git a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json index 69cbbf56e2e..66948b03a4a 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json @@ -14,5 +14,6 @@ "state_sync_type": "Central", "p2p_communication_type": "External", "deployment_environment": "Mainnet", + "audited_libfuncs_only": true, "requires_k8s_service_config_params": true } diff --git a/crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json b/crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json index 2aa5f47e353..96dc24e09a0 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json +++ b/crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json @@ -14,5 +14,6 @@ "state_sync_type": "Central", "p2p_communication_type": "Internal", "deployment_environment": "Potc2", + "audited_libfuncs_only": true, "requires_k8s_service_config_params": true } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json index 279292daccf..f2d3cb29b46 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json @@ -14,5 +14,6 @@ "state_sync_type": "Central", "p2p_communication_type": "Internal", "deployment_environment": "SepoliaIntegration", + "audited_libfuncs_only": false, "requires_k8s_service_config_params": false } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json index 25448baaa91..9a869887218 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json @@ -14,5 +14,6 @@ "state_sync_type": "Central", "p2p_communication_type": "External", "deployment_environment": "SepoliaTestnet", + "audited_libfuncs_only": true, "requires_k8s_service_config_params": true } diff --git a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json index 221e08a36a1..92627daa0d4 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json @@ -14,5 +14,6 @@ "state_sync_type": "Central", "p2p_communication_type": "Internal", "deployment_environment": "StressTest", + "audited_libfuncs_only": false, "requires_k8s_service_config_params": false } diff --git a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json index b8e9a5965aa..d64ee6e6e58 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json @@ -14,5 +14,6 @@ "state_sync_type": "Central", "p2p_communication_type": "External", "deployment_environment": "UpgradeTest", + "audited_libfuncs_only": false, "requires_k8s_service_config_params": true } diff --git a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json index 2fef1d06018..9a3443d574a 100644 --- a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json @@ -9,6 +9,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-mainnet-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-mainnet-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-mainnet.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, diff --git a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json index 9fef1f01c7d..c5ca2569df3 100644 --- a/crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json @@ -9,6 +9,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.potc-mock-sepolia-fgw.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json index a0f3bee17bd..62f5c97be7e 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json @@ -9,6 +9,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://feeder.integration-sepolia.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json index c8a6ba0f72c..8d7ad7dd994 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json @@ -9,6 +9,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-alpha-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-alpha-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-sepolia.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, diff --git a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json index 8be398a9f19..01e37d39e4c 100644 --- a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json @@ -9,6 +9,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-stresstest-dev-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-stresstest-dev-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-stresstest-dev-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "http://feeder-gateway.starknet-0-14-0-stress-test-05:9713/", "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, diff --git a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json index de56a2431ca..c978d861773 100644 --- a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json @@ -9,6 +9,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": false, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://integration-sepolia.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": true, "state_sync_config.network_config.#is_none": false, diff --git a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json index d0f239e9a6a..2acd0efb7c5 100644 --- a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json @@ -9,6 +9,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-test-0.sw-dev.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-test-1.sw-dev.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-test-2.sw-dev.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-test-10.sw-dev.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-test-11.sw-dev.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-test-12.sw-dev.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://feeder.sn-mainnet-test-upgrade.gateway-proxy.sw-dev.io/", "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index 810b4af72ed..95a6ac42f15 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -132,6 +132,8 @@ pub struct DeploymentConfigOverride { l1_provider_config_provider_startup_height_override_is_none: bool, #[serde(rename = "consensus_manager_config.context_config.num_validators")] consensus_manager_config_context_config_num_validators: usize, + #[serde(rename = "sierra_compiler_config.audited_libfuncs_only")] + sierra_compiler_config_audited_libfuncs_only: bool, #[serde(flatten)] state_sync_config: StateSyncConfig, #[serde(flatten, with = "consensus_prefix")] @@ -153,6 +155,7 @@ impl DeploymentConfigOverride { state_sync_type: StateSyncType, consensus_p2p_bootstrap_config: PeerToPeerBootstrapConfig, mempool_p2p_bootstrap_config: PeerToPeerBootstrapConfig, + sierra_compiler_config_audited_libfuncs_only: bool, ) -> Self { let ( l1_provider_config_provider_startup_height_override, @@ -171,6 +174,7 @@ impl DeploymentConfigOverride { l1_provider_config_provider_startup_height_override, l1_provider_config_provider_startup_height_override_is_none, consensus_manager_config_context_config_num_validators, + sierra_compiler_config_audited_libfuncs_only, state_sync_config: state_sync_type.get_state_sync_config(), consensus_p2p_bootstrap_config, mempool_p2p_bootstrap_config, diff --git a/crates/apollo_deployments/src/deployment_definitions.rs b/crates/apollo_deployments/src/deployment_definitions.rs index e2e5ea0e7bc..79980cb3b30 100644 --- a/crates/apollo_deployments/src/deployment_definitions.rs +++ b/crates/apollo_deployments/src/deployment_definitions.rs @@ -87,6 +87,7 @@ pub struct DeploymentInputs { pub p2p_communication_type: P2PCommunicationType, pub deployment_environment: Environment, pub requires_k8s_service_config_params: bool, + pub audited_libfuncs_only: bool, } impl DeploymentInputs { diff --git a/crates/apollo_deployments/src/deployment_definitions/testing.rs b/crates/apollo_deployments/src/deployment_definitions/testing.rs index 5d78e8c5dcd..9c31be2d4dc 100644 --- a/crates/apollo_deployments/src/deployment_definitions/testing.rs +++ b/crates/apollo_deployments/src/deployment_definitions/testing.rs @@ -36,6 +36,7 @@ fn testing_deployment_config_override() -> DeploymentConfigOverride { StateSyncType::P2P, PeerToPeerBootstrapConfig::new(None), PeerToPeerBootstrapConfig::new(None), + false, ) } diff --git a/crates/apollo_deployments/src/deployments/hybrid.rs b/crates/apollo_deployments/src/deployments/hybrid.rs index c5527e02437..dcca954f754 100644 --- a/crates/apollo_deployments/src/deployments/hybrid.rs +++ b/crates/apollo_deployments/src/deployments/hybrid.rs @@ -871,6 +871,7 @@ fn hybrid_deployments(inputs: &DeploymentInputs) -> Vec { inputs.state_sync_type.clone(), consensus_p2p_bootstrap_config.clone(), mempool_p2p_bootstrap_config.clone(), + inputs.audited_libfuncs_only, ), &inputs.node_namespace_format, &inputs.ingress_domain, diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 7c5fb58bd72..94b7ea6534e 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -2304,6 +2304,11 @@ "privacy": "TemporaryValue", "value": false }, + "sierra_compiler_config.audited_libfuncs_only": { + "description": "If true, restrict to audited libfuncs. Otherwise allow all.", + "privacy": "Public", + "value": true + }, "starknet_url": { "description": "URL for communicating with Starknet.", "privacy": "TemporaryValue", diff --git a/crates/apollo_sierra_compilation_config/src/config.rs b/crates/apollo_sierra_compilation_config/src/config.rs index b70e8516811..da1025f5012 100644 --- a/crates/apollo_sierra_compilation_config/src/config.rs +++ b/crates/apollo_sierra_compilation_config/src/config.rs @@ -8,6 +8,7 @@ use validator::Validate; // TODO(Noa): Reconsider the default values. pub const DEFAULT_MAX_BYTECODE_SIZE: usize = 80 * 1024; pub const DEFAULT_MAX_MEMORY_USAGE: u64 = 5 * 1024 * 1024 * 1024; +pub const DEFAULT_AUDITED_LIBFUNCS_ONLY: bool = true; #[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] pub struct SierraCompilationConfig { @@ -15,6 +16,8 @@ pub struct SierraCompilationConfig { pub max_bytecode_size: usize, /// Compilation process’s virtual memory (address space) byte limit. pub max_memory_usage: Option, + /// If true, compile with audited libfuncs only; if false, allow all libfuncs. + pub audited_libfuncs_only: bool, } impl Default for SierraCompilationConfig { @@ -22,18 +25,27 @@ impl Default for SierraCompilationConfig { Self { max_bytecode_size: DEFAULT_MAX_BYTECODE_SIZE, max_memory_usage: Some(DEFAULT_MAX_MEMORY_USAGE), + audited_libfuncs_only: DEFAULT_AUDITED_LIBFUNCS_ONLY, } } } impl SerializeConfig for SierraCompilationConfig { fn dump(&self) -> BTreeMap { - let mut dump = BTreeMap::from([ser_param( - "max_bytecode_size", - &self.max_bytecode_size, - "Limitation of compiled CASM bytecode size (felts).", - ParamPrivacyInput::Public, - )]); + let mut dump = BTreeMap::from([ + ser_param( + "max_bytecode_size", + &self.max_bytecode_size, + "Limitation of compiled CASM bytecode size (felts).", + ParamPrivacyInput::Public, + ), + ser_param( + "audited_libfuncs_only", + &self.audited_libfuncs_only, + "If true, restrict to audited libfuncs. Otherwise allow all.", + ParamPrivacyInput::Public, + ), + ]); dump.extend(ser_optional_param( &self.max_memory_usage, DEFAULT_MAX_MEMORY_USAGE, From 4e2aa961e22aa647d3e371f82311eb6aad2f91e6 Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Sun, 19 Oct 2025 11:10:22 +0300 Subject: [PATCH 057/313] chore: fix conflicts Signed-off-by: Dori Medini --- Cargo.lock | 247 ------------------ Cargo.toml | 10 +- .../apollo_compile_to_casm_types/src/lib.rs | 6 - .../src/sequencer_consensus_context_test.rs | 35 +-- .../src/config.rs | 8 - .../resources/app_configs/batcher_config.json | 8 - .../deployment_inputs/potc_mock.json | 25 +- .../potc_mock/deployment_config_override.json | 6 - crates/apollo_gateway/src/errors.rs | 8 +- crates/apollo_node/src/components.rs | 18 +- .../src/builders/dashboard_builder.py | 14 - 11 files changed, 31 insertions(+), 354 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17b455daaea..dea81541569 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1265,14 +1265,8 @@ dependencies = [ "serde", "serde_json", "shared_execution_objects", -<<<<<<< HEAD "sizeof", "starknet-types-core", -||||||| 9f5c80194 - "starknet-types-core 0.2.1", -======= - "starknet-types-core", ->>>>>>> origin/main-v0.14.0 "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -1728,15 +1722,7 @@ dependencies = [ "papyrus_base_layer", "pretty_assertions", "rstest", -<<<<<<< HEAD - "starknet-types-core", -||||||| 9f5c80194 - "serde", - "starknet-types-core 0.2.1", -======= - "serde", "starknet-types-core", ->>>>>>> origin/main-v0.14.0 "starknet_api", "thiserror 1.0.69", "tokio", @@ -1809,15 +1795,7 @@ dependencies = [ "pretty_assertions", "rand 0.8.5", "rstest", -<<<<<<< HEAD "starknet-types-core", -||||||| 9f5c80194 - "serde", - "starknet-types-core 0.2.1", -======= - "serde", - "starknet-types-core", ->>>>>>> origin/main-v0.14.0 "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", @@ -2114,15 +2092,7 @@ dependencies = [ "papyrus_common", "rand 0.8.5", "rand_chacha 0.3.1", -<<<<<<< HEAD "starknet-types-core", -||||||| 9f5c80194 - "serde", - "starknet-types-core 0.2.1", -======= - "serde", - "starknet-types-core", ->>>>>>> origin/main-v0.14.0 "starknet_api", "static_assertions", "thiserror 1.0.69", @@ -2442,15 +2412,7 @@ dependencies = [ "libp2p", "papyrus_common", "rand_chacha 0.3.1", -<<<<<<< HEAD "starknet-types-core", -||||||| 9f5c80194 - "serde", - "starknet-types-core 0.2.1", -======= - "serde", - "starknet-types-core", ->>>>>>> origin/main-v0.14.0 "starknet_api", "tokio", "tracing", @@ -3521,28 +3483,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -||||||| 9f5c80194 -name = "blake2s" -version = "0.15.0-rc.4" -dependencies = [ - "blake2", - "digest 0.10.7", - "starknet-types-core 0.2.1", -] - -[[package]] -======= -name = "blake2s" -version = "0.15.0-rc.4" -dependencies = [ - "blake2", - "digest 0.10.7", - "starknet-types-core", -] - -[[package]] ->>>>>>> origin/main-v0.14.0 name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4081,16 +4021,8 @@ dependencies = [ "rand 0.9.2", "sha2", "smol_str", -<<<<<<< HEAD "starknet-types-core", "thiserror 2.0.16", -||||||| 9f5c80194 - "starknet-types-core 0.2.1", - "thiserror 2.0.12", -======= - "starknet-types-core", - "thiserror 2.0.12", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -4143,16 +4075,8 @@ dependencies = [ "serde_json", "sha3", "smol_str", -<<<<<<< HEAD "starknet-types-core", "thiserror 2.0.16", -||||||| 9f5c80194 - "starknet-types-core 0.2.1", - "thiserror 2.0.12", -======= - "starknet-types-core", - "thiserror 2.0.12", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -4228,16 +4152,8 @@ dependencies = [ "itertools 0.14.0", "num-bigint 0.4.6", "num-traits", -<<<<<<< HEAD "starknet-types-core", "thiserror 2.0.16", -||||||| 9f5c80194 - "starknet-types-core 0.2.1", - "thiserror 2.0.12", -======= - "starknet-types-core", - "thiserror 2.0.12", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -4277,16 +4193,8 @@ dependencies = [ "serde", "serde_json", "smol_str", -<<<<<<< HEAD "starknet-types-core", "thiserror 2.0.16", -||||||| 9f5c80194 - "starknet-types-core 0.2.1", - "thiserror 2.0.12", -======= - "starknet-types-core", - "thiserror 2.0.12", ->>>>>>> origin/main-v0.14.0 "typetag", ] @@ -4309,16 +4217,8 @@ dependencies = [ "serde_json", "sha3", "smol_str", -<<<<<<< HEAD "starknet-types-core", "thiserror 2.0.16", -||||||| 9f5c80194 - "starknet-types-core 0.2.1", - "thiserror 2.0.12", -======= - "starknet-types-core", - "thiserror 2.0.12", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -4488,19 +4388,9 @@ dependencies = [ "serde_json", "sha2", "sha3", -<<<<<<< HEAD "starknet-crypto", "starknet-types-core", "thiserror 2.0.16", -||||||| 9f5c80194 - "starknet-crypto 0.8.1", - "starknet-types-core 0.2.1", - "thiserror 2.0.12", -======= - "starknet-crypto", - "starknet-types-core", - "thiserror 2.0.12", ->>>>>>> origin/main-v0.14.0 "zip", ] @@ -8102,37 +7992,11 @@ dependencies = [ [[package]] name = "lambdaworks-crypto" -<<<<<<< HEAD -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce8f59622ed408c318c9b5eca17f1a1154159e3738b5c4d5a22a0dd3700c906" -dependencies = [ - "lambdaworks-math", -||||||| 9f5c80194 -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc2a4da0d9e52ccfe6306801a112e81a8fc0c76aa3e4449fefeda7fef72bb34" -dependencies = [ - "lambdaworks-math 0.10.0", - "serde", - "sha2", - "sha3", -] - -[[package]] -name = "lambdaworks-crypto" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce8f59622ed408c318c9b5eca17f1a1154159e3738b5c4d5a22a0dd3700c906" -dependencies = [ - "lambdaworks-math 0.12.0", -======= version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58b1a1c1102a5a7fbbda117b79fb3a01e033459c738a3c1642269603484fd1c1" dependencies = [ "lambdaworks-math", ->>>>>>> origin/main-v0.14.0 "rand 0.8.5", "rand_chacha 0.3.1", "serde", @@ -8142,39 +8006,13 @@ dependencies = [ [[package]] name = "lambdaworks-math" -<<<<<<< HEAD -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "405d65a26831650ba348a503a2881ed7a0483ef3ec17f66e0fc8e2f9c97fc7ca" -||||||| 9f5c80194 -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1bd2632acbd9957afc5aeec07ad39f078ae38656654043bf16e046fa2730e23" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "lambdaworks-math" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "405d65a26831650ba348a503a2881ed7a0483ef3ec17f66e0fc8e2f9c97fc7ca" -======= version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "018a95aa873eb49896a858dee0d925c33f3978d073c64b08dd4f2c9b35a017c6" ->>>>>>> origin/main-v0.14.0 dependencies = [ -<<<<<<< HEAD "getrandom 0.2.16", -||||||| 9f5c80194 - "getrandom 0.2.15", -======= - "getrandom 0.2.15", "num-bigint 0.4.6", "num-traits", ->>>>>>> origin/main-v0.14.0 "rand 0.8.5", "serde", "serde_json", @@ -12323,7 +12161,6 @@ dependencies = [ name = "sizeof" version = "0.16.0-rc.0" dependencies = [ -<<<<<<< HEAD "size-of", "sizeof_internal", "sizeof_macro", @@ -12344,11 +12181,6 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.106", -||||||| 9f5c80194 - "starknet-types-core 0.2.1", -======= - "starknet-types-core", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -12533,44 +12365,11 @@ checksum = "b08520b7d80eda7bf1a223e8db4f9bb5779a12846f15ebf8f8d76667eca7f5ad" dependencies = [ "proc-macro2", "quote", -<<<<<<< HEAD "syn 2.0.106", ] [[package]] name = "starknet-crypto" -||||||| 9f5c80194 - "syn 2.0.100", -] - -[[package]] -name = "starknet-crypto" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039a3bad70806b494c9e6b21c5238a6c8a373d66a26071859deb0ccca6f93634" -dependencies = [ - "crypto-bigint", - "hex", - "hmac", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "rfc6979", - "sha2", - "starknet-curve 0.5.1", - "starknet-types-core 0.1.8", - "zeroize", -] - -[[package]] -name = "starknet-crypto" -======= - "syn 2.0.100", -] - -[[package]] -name = "starknet-crypto" ->>>>>>> origin/main-v0.14.0 version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1004a16c25dc6113c19d4f9d0c19ff97d85804829894bba22c0d0e9e7b249812" @@ -12594,41 +12393,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22c898ae81b6409532374cf237f1bd752d068b96c6ad500af9ebbd0d9bb712f6" dependencies = [ -<<<<<<< HEAD - "starknet-types-core", -] - -[[package]] -name = "starknet-types-core" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c043ab183b1cb1daab10d592719d27f283e7ef7e7ac8accd243b4e70b4e1c0d8" -||||||| 9f5c80194 - "starknet-types-core 0.2.1", -] - -[[package]] -name = "starknet-types-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4037bcb26ce7c508448d221e570d075196fd4f6912ae6380981098937af9522a" -dependencies = [ - "lambdaworks-crypto 0.10.0", - "lambdaworks-math 0.10.0", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "serde", - "size-of", - "zeroize", -] - -[[package]] -name = "starknet-types-core" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c043ab183b1cb1daab10d592719d27f283e7ef7e7ac8accd243b4e70b4e1c0d8" -======= "starknet-types-core", ] @@ -12637,7 +12401,6 @@ name = "starknet-types-core" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab92594a86ac627dd4c8d3350362cc8035e55c548c27c71dfa4c9fc6b3b6ab1a" ->>>>>>> origin/main-v0.14.0 dependencies = [ "blake2", "digest 0.10.7", @@ -12680,19 +12443,9 @@ dependencies = [ "serde", "serde_json", "sha3", -<<<<<<< HEAD "sizeof", "starknet-crypto", "starknet-types-core", -||||||| 9f5c80194 - "size-of", - "starknet-crypto 0.8.1", - "starknet-types-core 0.2.1", -======= - "size-of", - "starknet-crypto", - "starknet-types-core", ->>>>>>> origin/main-v0.14.0 "strum 0.25.0", "strum_macros 0.25.3", "thiserror 1.0.69", diff --git a/Cargo.toml b/Cargo.toml index f3a76f67534..4a6aa5ac7af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -344,16 +344,8 @@ sizeof_macro = { path = "crates/sizeof/sizeof_macro", version = "0.16.0-rc.0" } socket2 = "0.5.8" starknet-core = "0.16.0" starknet-crypto = "0.8.1" -<<<<<<< HEAD -starknet-types-core = "0.2.1" -starknet_api = { path = "crates/starknet_api", version = "0.16.0-rc.0" } -||||||| 9f5c80194 -starknet-types-core = "0.2.1" -starknet_api = { path = "crates/starknet_api", version = "0.15.0-rc.4" } -======= starknet-types-core = "=0.2.3" -starknet_api = { path = "crates/starknet_api", version = "0.15.0-rc.4" } ->>>>>>> origin/main-v0.14.0 +starknet_api = { path = "crates/starknet_api", version = "0.16.0-rc.0" } starknet_committer.path = "crates/starknet_committer" starknet_committer_and_os_cli.path = "crates/starknet_committer_and_os_cli" starknet_os.path = "crates/starknet_os" diff --git a/crates/apollo_compile_to_casm_types/src/lib.rs b/crates/apollo_compile_to_casm_types/src/lib.rs index e5b06b854d6..fd0cc50198c 100644 --- a/crates/apollo_compile_to_casm_types/src/lib.rs +++ b/crates/apollo_compile_to_casm_types/src/lib.rs @@ -85,13 +85,7 @@ impl SerializedClass { } pub fn size(&self) -> RawClassResult { -<<<<<<< HEAD Ok(size_of_serialized(&self.0)?) -||||||| 9f5c80194 - Ok(serde_json::to_string_pretty(&self.0)?.len()) -======= - Ok(serde_json::to_string(&self.0)?.len()) ->>>>>>> origin/main-v0.14.0 } fn new(value: serde_json::Value) -> Self { 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 54e8576191b..803fb28fca3 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs @@ -859,53 +859,44 @@ async fn override_prices_behavior( // In this case the L2 gas price must match the given override. assert_eq!( actual_l2_gas_price, override_l2_gas_price, - "Expected L2 gas price ({}) to match override_l2_gas_price ({})", - actual_l2_gas_price, override_l2_gas_price + "Expected L2 gas price ({actual_l2_gas_price}) to match override_l2_gas_price \ + ({override_l2_gas_price})", ); } else { // In this case the regular L2 gas calculation takes place, and gives a higher price. assert!( actual_l2_gas_price > min_gas_price, -<<<<<<< HEAD - "Expected L2 gas price > min ({min_gas_price}) due to high usage (EIP-1559), but got \ - {actual_l2_gas_price}" -||||||| 9f5c80194 - "Expected L2 gas price > min ({}) due to high usage (EIP-1559), but got {}", - min_gas_price, - actual_l2_gas_price -======= - "Expected L2 gas price ({}) > minimum l2 gas price ({}) due to high usage (EIP-1559)", - actual_l2_gas_price, - min_gas_price + "Expected L2 gas price ({actual_l2_gas_price}) > minimum l2 gas price \ + ({min_gas_price}) due to high usage (EIP-1559)", ); } if let Some(override_l1_gas_price) = override_l1_gas_price { assert_eq!( actual_l1_gas_price, override_l1_gas_price, - "Expected L1 gas price ({}) to match input l1 gas price ({})", - actual_l1_gas_price, override_l1_gas_price + "Expected L1 gas price ({actual_l1_gas_price}) to match input l1 gas price \ + ({override_l1_gas_price})", ); } else { assert_eq!( actual_l1_gas_price, expected_l1_prices.base_fee_per_gas.0, - "Expected L1 gas price ({}) to match input l1 gas price ({})", - actual_l1_gas_price, expected_l1_prices.base_fee_per_gas.0 + "Expected L1 gas price ({actual_l1_gas_price}) to match input l1 gas price ({})", + expected_l1_prices.base_fee_per_gas.0 ); } if let Some(override_l1_data_gas_price) = override_l1_data_gas_price { assert_eq!( actual_l1_data_gas_price, override_l1_data_gas_price, - "Expected L1 data gas price ({}) to match input l1 data gas price ({})", - actual_l1_data_gas_price, override_l1_data_gas_price + "Expected L1 data gas price ({actual_l1_data_gas_price}) to match input l1 data gas \ + price ({override_l1_data_gas_price})", ); } else { assert_eq!( actual_l1_data_gas_price, expected_l1_prices.blob_fee.0, - "Expected L1 data gas price ({}) to match input l1 data gas price ({})", - actual_l1_data_gas_price, expected_l1_prices.blob_fee.0 ->>>>>>> origin/main-v0.14.0 + "Expected L1 data gas price ({actual_l1_data_gas_price}) to match input l1 data gas \ + price ({})", + expected_l1_prices.blob_fee.0 ); } } diff --git a/crates/apollo_consensus_orchestrator_config/src/config.rs b/crates/apollo_consensus_orchestrator_config/src/config.rs index e3d153dedbe..097effd50d4 100644 --- a/crates/apollo_consensus_orchestrator_config/src/config.rs +++ b/crates/apollo_consensus_orchestrator_config/src/config.rs @@ -2,19 +2,11 @@ use std::collections::BTreeMap; use std::fmt::Debug; use std::time::Duration; -<<<<<<< HEAD:crates/apollo_consensus_orchestrator_config/src/config.rs use apollo_config::converters::{ deserialize_milliseconds_to_duration, deserialize_seconds_to_duration, }; use apollo_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; -||||||| 9f5c80194:crates/apollo_consensus_orchestrator/src/config.rs -use apollo_config::converters::deserialize_milliseconds_to_duration; -use apollo_config::dumping::{ser_param, SerializeConfig}; -======= -use apollo_config::converters::deserialize_milliseconds_to_duration; -use apollo_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; ->>>>>>> origin/main-v0.14.0:crates/apollo_consensus_orchestrator/src/config.rs use apollo_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; diff --git a/crates/apollo_deployments/resources/app_configs/batcher_config.json b/crates/apollo_deployments/resources/app_configs/batcher_config.json index 0527dfe9ff5..c8ec2c30813 100644 --- a/crates/apollo_deployments/resources/app_configs/batcher_config.json +++ b/crates/apollo_deployments/resources/app_configs/batcher_config.json @@ -50,14 +50,6 @@ "batcher_config.storage.mmap_file_config.growth_step": 2147483648, "batcher_config.storage.mmap_file_config.max_object_size": 1073741824, "batcher_config.storage.mmap_file_config.max_size": 1099511627776, -<<<<<<< HEAD - "batcher_config.storage.scope": "StateOnly" -} -||||||| 9f5c80194 - "batcher_config.storage.scope": "StateOnly" -} -======= "batcher_config.storage.scope": "StateOnly", "batcher_config.propose_l1_txs_every": 10 } ->>>>>>> origin/main-v0.14.0 diff --git a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json index 5953623c7fd..ca986dcc89f 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json +++ b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json @@ -1,5 +1,18 @@ { - "node_and_validator_ids": [[0, "0x64"], [1, "0x65"], [2, "0x66"]], + "node_and_validator_ids": [ + [ + 0, + "0x64" + ], + [ + 1, + "0x65" + ], + [ + 2, + "0x66" + ] + ], "num_validators": 3, "http_server_ingress_alternative_name": "potc-testnet-mock-sepolia.starknet.io", "ingress_domain": "starknet.io", @@ -13,15 +26,7 @@ "l1_startup_height_override": null, "state_sync_type": "Central", "p2p_communication_type": "Internal", -<<<<<<< HEAD:crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json - "deployment_environment": "Potc2", - "audited_libfuncs_only": true, - "requires_k8s_service_config_params": true -||||||| 9f5c80194:crates/apollo_deployments/resources/deployment_inputs/potc2_sepolia.json - "deployment_environment": "Potc2", - "requires_k8s_service_config_params": true -======= "deployment_environment": "PotcMock", + "audited_libfuncs_only": true, "requires_k8s_service_config_params": false ->>>>>>> origin/main-v0.14.0:crates/apollo_deployments/resources/deployment_inputs/potc_mock.json } diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json index 4b79dbccf6c..52b96a275f4 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json @@ -7,16 +7,10 @@ "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, -<<<<<<< HEAD:crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "sierra_compiler_config.audited_libfuncs_only": true, - "starknet_url": "https://feeder.potc-mock-sepolia-fgw.starknet.io/", -||||||| 9f5c80194:crates/apollo_deployments/resources/deployments/potc2/deployment_config_override.json - "starknet_url": "https://feeder.potc-mock-sepolia-fgw.starknet.io/", -======= "starknet_url": "https://feeder.potc-testnet-mock-sepolia.starknet.io/", ->>>>>>> origin/main-v0.14.0:crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, "state_sync_config.p2p_sync_client_config.#is_none": true, diff --git a/crates/apollo_gateway/src/errors.rs b/crates/apollo_gateway/src/errors.rs index 060b53bdc87..0f532e0a104 100644 --- a/crates/apollo_gateway/src/errors.rs +++ b/crates/apollo_gateway/src/errors.rs @@ -15,14 +15,8 @@ use reqwest::StatusCode; use serde_json::{Error as SerdeError, Value}; use starknet_api::block::GasPrice; use starknet_api::executable_transaction::ValidateCompiledClassHashError; -<<<<<<< HEAD -use starknet_api::transaction::fields::{AllResourceBounds, TransactionSignature}; -||||||| 9f5c80194 -use starknet_api::transaction::fields::AllResourceBounds; -======= use starknet_api::execution_resources::GasAmount; -use starknet_api::transaction::fields::AllResourceBounds; ->>>>>>> origin/main-v0.14.0 +use starknet_api::transaction::fields::{AllResourceBounds, TransactionSignature}; use starknet_api::StarknetApiError; use thiserror::Error; use tracing::{debug, error, warn}; diff --git a/crates/apollo_node/src/components.rs b/crates/apollo_node/src/components.rs index 6cb9074a0d3..c1810e269d1 100644 --- a/crates/apollo_node/src/components.rs +++ b/crates/apollo_node/src/components.rs @@ -384,27 +384,11 @@ pub async fn create_node_components( let l1_start_block = fetch_start_block(&base_layer, l1_scraper_config) .await .unwrap_or_else(|err| panic!("Error while initializing the L1 scraper: {err}")); -<<<<<<< HEAD + debug!("L1 start block: {l1_start_block:?}"); let monitored_base_layer = MonitoredEthereumBaseLayer::new(base_layer, l1_endpoint_monitor_client).await; -||||||| 9f5c80194 - - let monitored_base_layer = MonitoredEthereumBaseLayer::new( - base_layer, - l1_endpoint_monitor_client, - base_layer_config.node_url.clone(), - ); - -======= - debug!("L1 start block: {l1_start_block:?}"); - let monitored_base_layer = MonitoredEthereumBaseLayer::new( - base_layer, - l1_endpoint_monitor_client, - base_layer_config.node_url.clone(), - ); ->>>>>>> origin/main-v0.14.0 Some( L1Scraper::new( l1_scraper_config.clone(), diff --git a/deployments/monitoring/src/builders/dashboard_builder.py b/deployments/monitoring/src/builders/dashboard_builder.py index b1507965145..440e4703553 100755 --- a/deployments/monitoring/src/builders/dashboard_builder.py +++ b/deployments/monitoring/src/builders/dashboard_builder.py @@ -83,21 +83,7 @@ def create_grafana_panel(panel: dict, panel_id: int, y_position: int, x_position } ], }, -<<<<<<< HEAD - "options": {"showPercentChange": show_percent_change}, "links": ([{"url": link, "title": "GCP Logs", "targetBlank": True}]), -||||||| 9f5c80194 - "options": { - "showPercentChange": show_percent_change - }, - "links": ( - [{"url": link, "title": "GCP Logs", "targetBlank": True}] - ), -======= - "links": ( - [{"url": link, "title": "GCP Logs", "targetBlank": True}] - ), ->>>>>>> origin/main-v0.14.0 "transformations": [ # Renames labels of the form {label="value"} to just "value" { From 805110ae9a315ce977031224352dfb5b2cdd9064 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 11:38:35 +0300 Subject: [PATCH 058/313] papyrus_node: Papyrus cleanup - papyrus_reader (#9615) --- crates/apollo_batcher/src/block_builder.rs | 4 ++-- crates/apollo_state_reader/src/papyrus_state_test.rs | 4 ++-- crates/native_blockifier/src/py_block_executor.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index fe83320ec80..cdf337aead9 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -677,10 +677,10 @@ impl BlockBuilderFactory { ); let class_reader = Some(ClassReader { reader: self.class_manager_client.clone(), runtime }); - let papyrus_reader = + let apollo_reader = PapyrusReader::new_with_class_reader(self.storage_reader.clone(), height, class_reader); let state_reader = StateReaderAndContractManager { - state_reader: papyrus_reader, + state_reader: apollo_reader, contract_class_manager: self.contract_class_manager.clone(), }; diff --git a/crates/apollo_state_reader/src/papyrus_state_test.rs b/crates/apollo_state_reader/src/papyrus_state_test.rs index ce91f2c28de..4494a4d06a3 100644 --- a/crates/apollo_state_reader/src/papyrus_state_test.rs +++ b/crates/apollo_state_reader/src/papyrus_state_test.rs @@ -49,8 +49,8 @@ fn test_entry_point_with_papyrus_state() -> apollo_storage::StorageResult<()> { // BlockNumber is 1 due to the initialization step above. let block_number = BlockNumber(1); - let papyrus_reader = PapyrusReader::new(storage_reader, block_number); - let mut state = CachedState::from(papyrus_reader); + let apollo_reader = PapyrusReader::new(storage_reader, block_number); + let mut state = CachedState::from(apollo_reader); // Call entrypoint that want to write to storage, which updates the cached state's write cache. let key = felt!(1234_u16); diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index c805a564fd6..1b3f8f06b9c 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -404,10 +404,10 @@ impl PyBlockExecutor { ) -> StateReaderAndContractManager { // Full-node storage must be aligned to the Python storage before initializing a reader. self.storage.validate_aligned(next_block_number.0); - let papyrus_reader = PapyrusReader::new(self.storage.reader().clone(), next_block_number); + let apollo_reader = PapyrusReader::new(self.storage.reader().clone(), next_block_number); StateReaderAndContractManager { - state_reader: papyrus_reader, + state_reader: apollo_reader, contract_class_manager: self.contract_class_manager.clone(), } } From 21dfcd7bdd3d24b43b6635dfbbc59fd6b09071a7 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 12:05:42 +0300 Subject: [PATCH 059/313] papyrus_node: Papyrus cleanup - PapyrusReader (#9616) --- crates/apollo_batcher/src/block_builder.rs | 8 ++++---- crates/apollo_state_reader/src/papyrus_state.rs | 12 ++++++------ crates/apollo_state_reader/src/papyrus_state_test.rs | 4 ++-- crates/native_blockifier/src/py_block_executor.rs | 10 +++++----- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index cdf337aead9..0a3a41e9619 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -12,7 +12,7 @@ use apollo_class_manager_types::transaction_converter::{ }; use apollo_class_manager_types::SharedClassManagerClient; use apollo_infra_utils::tracing::LogCompatibleToStringExt; -use apollo_state_reader::papyrus_state::{ClassReader, PapyrusReader}; +use apollo_state_reader::papyrus_state::{ApolloReader, ClassReader}; use apollo_storage::StorageReader; use async_trait::async_trait; use blockifier::blockifier::concurrent_transaction_executor::ConcurrentTransactionExecutor; @@ -622,7 +622,7 @@ pub struct BlockMetadata { // Type definitions for the abort channel required to abort the block builder. pub type AbortSignalSender = tokio::sync::oneshot::Sender<()>; pub type BatcherWorkerPool = - Arc>>>; + Arc>>>; /// The BlockBuilderFactoryTrait is responsible for creating a new block builder. #[cfg_attr(test, automock)] @@ -658,7 +658,7 @@ impl BlockBuilderFactory { block_metadata: BlockMetadata, runtime: tokio::runtime::Handle, ) -> BlockBuilderResult< - ConcurrentTransactionExecutor>, + ConcurrentTransactionExecutor>, > { info!( "preprocess and create transaction executor for block {}", @@ -678,7 +678,7 @@ impl BlockBuilderFactory { let class_reader = Some(ClassReader { reader: self.class_manager_client.clone(), runtime }); let apollo_reader = - PapyrusReader::new_with_class_reader(self.storage_reader.clone(), height, class_reader); + ApolloReader::new_with_class_reader(self.storage_reader.clone(), height, class_reader); let state_reader = StateReaderAndContractManager { state_reader: apollo_reader, contract_class_manager: self.contract_class_manager.clone(), diff --git a/crates/apollo_state_reader/src/papyrus_state.rs b/crates/apollo_state_reader/src/papyrus_state.rs index 2145b73f8a8..f3eed8942dc 100644 --- a/crates/apollo_state_reader/src/papyrus_state.rs +++ b/crates/apollo_state_reader/src/papyrus_state.rs @@ -27,7 +27,7 @@ use starknet_types_core::felt::Felt; #[path = "papyrus_state_test.rs"] mod test; -type RawPapyrusReader<'env> = apollo_storage::StorageTxn<'env, RO>; +type RawApolloReader<'env> = apollo_storage::StorageTxn<'env, RO>; pub struct ClassReader { pub reader: SharedClassManagerClient, @@ -88,14 +88,14 @@ impl ClassReader { } } -pub struct PapyrusReader { +pub struct ApolloReader { storage_reader: StorageReader, latest_block: BlockNumber, // Reader is `None` for reader invoked through `native_blockifier`. class_reader: Option, } -impl PapyrusReader { +impl ApolloReader { pub fn new_with_class_reader( storage_reader: StorageReader, latest_block: BlockNumber, @@ -108,7 +108,7 @@ impl PapyrusReader { Self { storage_reader, latest_block, class_reader: None } } - fn reader(&self) -> StateResult> { + fn reader(&self) -> StateResult> { self.storage_reader .begin_ro_txn() .map_err(|error| StateError::StateReadError(error.to_string())) @@ -195,7 +195,7 @@ impl PapyrusReader { } // Currently unused - will soon replace the same `impl` for `PapyrusStateReader`. -impl StateReader for PapyrusReader { +impl StateReader for ApolloReader { fn get_storage_at( &self, contract_address: ContractAddress, @@ -261,7 +261,7 @@ impl StateReader for PapyrusReader { } } -impl FetchCompiledClasses for PapyrusReader { +impl FetchCompiledClasses for ApolloReader { fn get_compiled_classes(&self, class_hash: ClassHash) -> StateResult { self.get_compiled_class_from_db(class_hash) } diff --git a/crates/apollo_state_reader/src/papyrus_state_test.rs b/crates/apollo_state_reader/src/papyrus_state_test.rs index 4494a4d06a3..ad926f1ee17 100644 --- a/crates/apollo_state_reader/src/papyrus_state_test.rs +++ b/crates/apollo_state_reader/src/papyrus_state_test.rs @@ -19,7 +19,7 @@ use starknet_api::contract_class::ContractClass; use starknet_api::state::{StateDiff, StorageKey}; use starknet_api::{calldata, felt}; -use crate::papyrus_state::PapyrusReader; +use crate::papyrus_state::ApolloReader; #[test] fn test_entry_point_with_papyrus_state() -> apollo_storage::StorageResult<()> { @@ -49,7 +49,7 @@ fn test_entry_point_with_papyrus_state() -> apollo_storage::StorageResult<()> { // BlockNumber is 1 due to the initialization step above. let block_number = BlockNumber(1); - let apollo_reader = PapyrusReader::new(storage_reader, block_number); + let apollo_reader = ApolloReader::new(storage_reader, block_number); let mut state = CachedState::from(apollo_reader); // Call entrypoint that want to write to storage, which updates the cached state's write cache. diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 1b3f8f06b9c..aec6db91551 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -2,7 +2,7 @@ use std::str::FromStr; -use apollo_state_reader::papyrus_state::PapyrusReader; +use apollo_state_reader::papyrus_state::ApolloReader; use blockifier::blockifier::config::{ContractClassManagerConfig, TransactionExecutorConfig}; use blockifier::blockifier::transaction_executor::{ BlockExecutionSummary, @@ -79,7 +79,7 @@ pub struct PyBlockExecutor { pub tx_executor_config: TransactionExecutorConfig, pub chain_info: ChainInfo, pub versioned_constants: VersionedConstants, - pub tx_executor: Option>>, + pub tx_executor: Option>>, /// `Send` trait is required for `pyclass` compatibility as Python objects must be threadsafe. pub storage: Box, pub contract_class_manager: ContractClassManager, @@ -394,17 +394,17 @@ impl PyBlockExecutor { impl PyBlockExecutor { pub fn tx_executor( &mut self, - ) -> &mut TransactionExecutor> { + ) -> &mut TransactionExecutor> { self.tx_executor.as_mut().expect("Transaction executor should be initialized") } fn get_aligned_reader( &self, next_block_number: BlockNumber, - ) -> StateReaderAndContractManager { + ) -> StateReaderAndContractManager { // Full-node storage must be aligned to the Python storage before initializing a reader. self.storage.validate_aligned(next_block_number.0); - let apollo_reader = PapyrusReader::new(self.storage.reader().clone(), next_block_number); + let apollo_reader = ApolloReader::new(self.storage.reader().clone(), next_block_number); StateReaderAndContractManager { state_reader: apollo_reader, From 61b0b36c547160633c5b640664d7b1dcd0209915 Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Sun, 19 Oct 2025 12:13:02 +0300 Subject: [PATCH 060/313] chore: fix retry mechanism for services Signed-off-by: Dori Medini --- Cargo.lock | 1 + crates/apollo_deployments/Cargo.toml | 1 + crates/apollo_deployments/src/deployments.rs | 9 -- .../src/deployments/consolidated.rs | 7 + .../src/deployments/distributed.rs | 18 +++ .../src/deployments/hybrid.rs | 153 ++---------------- crates/apollo_deployments/src/service.rs | 4 + .../apollo_infra/src/component_client/mod.rs | 2 +- .../remote_component_client.rs | 2 +- .../src/component_execution_config.rs | 8 + 10 files changed, 54 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dea81541569..410e041eb67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,6 +1329,7 @@ dependencies = [ "alloy", "apollo_config", "apollo_http_server_config", + "apollo_infra", "apollo_infra_utils", "apollo_monitoring_endpoint_config", "apollo_network", diff --git a/crates/apollo_deployments/Cargo.toml b/crates/apollo_deployments/Cargo.toml index df09365e149..37a2764b7d8 100644 --- a/crates/apollo_deployments/Cargo.toml +++ b/crates/apollo_deployments/Cargo.toml @@ -12,6 +12,7 @@ workspace = true alloy.workspace = true apollo_config.workspace = true apollo_http_server_config.workspace = true +apollo_infra.workspace = true apollo_infra_utils.workspace = true apollo_monitoring_endpoint_config.workspace = true apollo_network.workspace = true diff --git a/crates/apollo_deployments/src/deployments.rs b/crates/apollo_deployments/src/deployments.rs index aa7573aecbe..110c34ad9bc 100644 --- a/crates/apollo_deployments/src/deployments.rs +++ b/crates/apollo_deployments/src/deployments.rs @@ -1,12 +1,3 @@ pub mod consolidated; pub mod distributed; pub mod hybrid; -<<<<<<< HEAD -||||||| 9f5c80194 - -pub(crate) const IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES: usize = 0; -======= - -pub(crate) const IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES: usize = 0; -pub(crate) const RETRIES_FOR_L1_SERVICES: usize = 2; ->>>>>>> origin/main-v0.14.0 diff --git a/crates/apollo_deployments/src/deployments/consolidated.rs b/crates/apollo_deployments/src/deployments/consolidated.rs index 7277717e8b3..a755fbd7218 100644 --- a/crates/apollo_deployments/src/deployments/consolidated.rs +++ b/crates/apollo_deployments/src/deployments/consolidated.rs @@ -1,5 +1,6 @@ use std::collections::BTreeSet; +use apollo_infra::component_client::remote_component_client::DEFAULT_RETRIES; use apollo_node_config::component_config::ComponentConfig; use apollo_node_config::component_execution_config::{ ActiveComponentExecutionConfig, @@ -69,6 +70,12 @@ impl ServiceNameInner for ConsolidatedNodeServiceName { } } + fn get_retries(&self) -> usize { + match self { + Self::Node => DEFAULT_RETRIES, + } + } + fn get_toleration(&self, environment: &Environment) -> Option { match environment { Environment::CloudK8s(_) => Some(Toleration::ApolloCoreService), diff --git a/crates/apollo_deployments/src/deployments/distributed.rs b/crates/apollo_deployments/src/deployments/distributed.rs index 4f25e7f104a..dfa56acd682 100644 --- a/crates/apollo_deployments/src/deployments/distributed.rs +++ b/crates/apollo_deployments/src/deployments/distributed.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, BTreeSet}; +use apollo_infra::component_client::DEFAULT_RETRIES; use apollo_node_config::component_config::ComponentConfig; use apollo_node_config::component_execution_config::{ ActiveComponentExecutionConfig, @@ -38,6 +39,8 @@ const BATCHER_STORAGE: usize = 500; const CLASS_MANAGER_STORAGE: usize = 500; const STATE_SYNC_STORAGE: usize = 500; +pub const RETRIES_FOR_L1_SERVICES: usize = 2; + // TODO(Tsabary): define consts and functions whenever relevant. #[derive(Clone, Copy, Debug, Display, PartialEq, Eq, Hash, Serialize, AsRefStr, EnumIter)] @@ -198,6 +201,21 @@ impl ServiceNameInner for DistributedNodeServiceName { } } + fn get_retries(&self) -> usize { + match self { + Self::Batcher + | Self::ClassManager + | Self::ConsensusManager + | Self::HttpServer + | Self::Mempool + | Self::StateSync + | Self::SignatureManager + | Self::Gateway + | Self::SierraCompiler => DEFAULT_RETRIES, + Self::L1 => RETRIES_FOR_L1_SERVICES, + } + } + fn get_toleration(&self, environment: &Environment) -> Option { match environment { Environment::CloudK8s(_) => match self { diff --git a/crates/apollo_deployments/src/deployments/hybrid.rs b/crates/apollo_deployments/src/deployments/hybrid.rs index f380d8b0286..d015e80855b 100644 --- a/crates/apollo_deployments/src/deployments/hybrid.rs +++ b/crates/apollo_deployments/src/deployments/hybrid.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, BTreeSet}; +use apollo_infra::component_client::DEFAULT_RETRIES; use apollo_infra_utils::path::resolve_project_relative_path; use apollo_infra_utils::template::Template; use apollo_node_config::component_config::ComponentConfig; @@ -33,12 +34,7 @@ use crate::deployment_definitions::{ CONSENSUS_P2P_PORT, MEMPOOL_P2P_PORT, }; -<<<<<<< HEAD -||||||| 9f5c80194 -use crate::deployments::IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES; -======= -use crate::deployments::{IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES, RETRIES_FOR_L1_SERVICES}; ->>>>>>> origin/main-v0.14.0 +use crate::deployments::distributed::RETRIES_FOR_L1_SERVICES; use crate::k8s::{ get_environment_ingress_internal, get_ingress, @@ -194,6 +190,17 @@ impl ServiceNameInner for HybridNodeServiceName { } } + fn get_retries(&self) -> usize { + match self { + Self::Core + | Self::HttpServer + | Self::Mempool + | Self::Gateway + | Self::SierraCompiler => DEFAULT_RETRIES, + Self::L1 => RETRIES_FOR_L1_SERVICES, + } + } + fn get_toleration(&self, environment: &Environment) -> Option { match environment { Environment::CloudK8s(cloud_env) => match self { @@ -702,140 +709,6 @@ impl ServiceNameInner for HybridNodeServiceName { } } -<<<<<<< HEAD -||||||| 9f5c80194 -impl HybridNodeServiceName { - /// Returns a component execution config for a component that runs locally, and accepts inbound - /// connections from remote components. - fn component_config_for_local_service(&self, port: u16) -> ReactiveComponentExecutionConfig { - ReactiveComponentExecutionConfig::local_with_remote_enabled( - self.k8s_service_name(), - IpAddr::from(Ipv4Addr::UNSPECIFIED), - port, - ) - } - - /// Returns a component execution config for a component that is accessed remotely. - fn component_config_for_remote_service(&self, port: u16) -> ReactiveComponentExecutionConfig { - let mut base = ReactiveComponentExecutionConfig::remote( - self.k8s_service_name(), - IpAddr::from(Ipv4Addr::UNSPECIFIED), - port, - ); - match self { - HybridNodeServiceName::Gateway | HybridNodeServiceName::SierraCompiler => { - let remote_client_config_ref = base - .remote_client_config - .as_mut() - .expect("Remote client config should be available"); - remote_client_config_ref.idle_connections = IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES - } - HybridNodeServiceName::Core - | HybridNodeServiceName::HttpServer - | HybridNodeServiceName::L1 - | HybridNodeServiceName::Mempool => {} - }; - base - } - - fn component_config_pair(&self, port: u16) -> HybridNodeServiceConfigPair { - HybridNodeServiceConfigPair { - local: self.component_config_for_local_service(port), - remote: self.component_config_for_remote_service(port), - } - } -} - -/// Component config bundling for services of a hybrid node: a config to run a component -/// locally while being accessible to other services, and a suitable config enabling such services -/// the access. -struct HybridNodeServiceConfigPair { - local: ReactiveComponentExecutionConfig, - remote: ReactiveComponentExecutionConfig, -} - -impl HybridNodeServiceConfigPair { - fn local(&self) -> ReactiveComponentExecutionConfig { - self.local.clone() - } - - fn remote(&self) -> ReactiveComponentExecutionConfig { - self.remote.clone() - } -} - -======= -impl HybridNodeServiceName { - /// Returns a component execution config for a component that runs locally, and accepts inbound - /// connections from remote components. - fn component_config_for_local_service(&self, port: u16) -> ReactiveComponentExecutionConfig { - ReactiveComponentExecutionConfig::local_with_remote_enabled( - self.k8s_service_name(), - IpAddr::from(Ipv4Addr::UNSPECIFIED), - port, - ) - } - - /// Returns a component execution config for a component that is accessed remotely. - fn component_config_for_remote_service(&self, port: u16) -> ReactiveComponentExecutionConfig { - let mut base = ReactiveComponentExecutionConfig::remote( - self.k8s_service_name(), - IpAddr::from(Ipv4Addr::UNSPECIFIED), - port, - ); - match self { - // Force new connections when connecting to autoscaled services. This is to ensure - // better load balancing. - HybridNodeServiceName::Gateway | HybridNodeServiceName::SierraCompiler => { - let remote_client_config_ref = base - .remote_client_config - .as_mut() - .expect("Remote client config should be available"); - remote_client_config_ref.idle_connections = IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES - } - // Fast failures when connecting to the l1 services. - HybridNodeServiceName::L1 => { - let remote_client_config_ref = base - .remote_client_config - .as_mut() - .expect("Remote client config should be available"); - remote_client_config_ref.retries = RETRIES_FOR_L1_SERVICES - } - HybridNodeServiceName::Core - | HybridNodeServiceName::HttpServer - | HybridNodeServiceName::Mempool => {} - }; - - base - } - - fn component_config_pair(&self, port: u16) -> HybridNodeServiceConfigPair { - HybridNodeServiceConfigPair { - local: self.component_config_for_local_service(port), - remote: self.component_config_for_remote_service(port), - } - } -} - -/// Component config bundling for services of a hybrid node: a config to run a component -/// locally while being accessible to other services, and a suitable config enabling such services -/// the access. -struct HybridNodeServiceConfigPair { - local: ReactiveComponentExecutionConfig, - remote: ReactiveComponentExecutionConfig, -} - -impl HybridNodeServiceConfigPair { - fn local(&self) -> ReactiveComponentExecutionConfig { - self.local.clone() - } - - fn remote(&self) -> ReactiveComponentExecutionConfig { - self.remote.clone() - } -} - ->>>>>>> origin/main-v0.14.0 #[allow(clippy::too_many_arguments)] fn get_core_component_config( batcher_local_config: ReactiveComponentExecutionConfig, diff --git a/crates/apollo_deployments/src/service.rs b/crates/apollo_deployments/src/service.rs index 1271132cb59..ef789611524 100644 --- a/crates/apollo_deployments/src/service.rs +++ b/crates/apollo_deployments/src/service.rs @@ -271,6 +271,8 @@ pub(crate) trait ServiceNameInner: Display { fn get_scale_policy(&self) -> ScalePolicy; + fn get_retries(&self) -> usize; + fn get_toleration(&self, environment: &Environment) -> Option; fn get_ingress( @@ -429,12 +431,14 @@ pub(crate) trait GetComponentConfigs: ServiceNameInner { /// Returns a component execution config for a component that is accessed remotely. fn component_config_for_remote_service(&self, port: u16) -> ReactiveComponentExecutionConfig { let idle_connections = self.get_scale_policy().idle_connections(); + let retries = self.get_retries(); ReactiveComponentExecutionConfig::remote( self.k8s_service_name(), IpAddr::from(Ipv4Addr::UNSPECIFIED), port, ) .with_idle_connections(idle_connections) + .with_retries(retries) } fn component_config_pair(&self, port: u16) -> ComponentConfigPair { diff --git a/crates/apollo_infra/src/component_client/mod.rs b/crates/apollo_infra/src/component_client/mod.rs index 558a849fbb7..6dd5395c726 100644 --- a/crates/apollo_infra/src/component_client/mod.rs +++ b/crates/apollo_infra/src/component_client/mod.rs @@ -1,6 +1,6 @@ mod definitions; mod local_component_client; -mod remote_component_client; +pub mod remote_component_client; pub use definitions::*; pub use local_component_client::*; diff --git a/crates/apollo_infra/src/component_client/remote_component_client.rs b/crates/apollo_infra/src/component_client/remote_component_client.rs index 49e294e113f..c498b204990 100644 --- a/crates/apollo_infra/src/component_client/remote_component_client.rs +++ b/crates/apollo_infra/src/component_client/remote_component_client.rs @@ -22,7 +22,7 @@ use crate::metrics::RemoteClientMetrics; use crate::requests::LabeledRequest; use crate::serde_utils::SerdeWrapper; -const DEFAULT_RETRIES: usize = 150; +pub const DEFAULT_RETRIES: usize = 150; const DEFAULT_IDLE_CONNECTIONS: usize = 10; const DEFAULT_IDLE_TIMEOUT_MS: u64 = 30000; const DEFAULT_MAX_RETRY_INTERVAL_MS: u64 = 1000; diff --git a/crates/apollo_node_config/src/component_execution_config.rs b/crates/apollo_node_config/src/component_execution_config.rs index 730a91e8ee1..09b00344090 100644 --- a/crates/apollo_node_config/src/component_execution_config.rs +++ b/crates/apollo_node_config/src/component_execution_config.rs @@ -189,6 +189,14 @@ impl ReactiveComponentExecutionConfig { self } + pub fn with_retries(mut self, retries: usize) -> Self { + self.remote_client_config + .as_mut() + .expect("Remote client config should be available") + .retries = retries; + self + } + #[cfg(any(feature = "testing", test))] pub fn set_url_to_localhost(&mut self) { self.url = Ipv4Addr::LOCALHOST.to_string(); From a01e137fff77dc870e2210a1f160be0a9f61635b Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Sun, 19 Oct 2025 12:32:44 +0300 Subject: [PATCH 061/313] apollo_batcher_config: add propose_l1_txs_every Signed-off-by: Dori Medini --- crates/apollo_batcher_config/src/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/apollo_batcher_config/src/config.rs b/crates/apollo_batcher_config/src/config.rs index 81e30d57906..5a76f1df3f6 100644 --- a/crates/apollo_batcher_config/src/config.rs +++ b/crates/apollo_batcher_config/src/config.rs @@ -133,6 +133,7 @@ pub struct BatcherConfig { pub contract_class_manager_config: ContractClassManagerConfig, pub max_l1_handler_txs_per_block_proposal: usize, pub pre_confirmed_cende_config: PreconfirmedCendeConfig, + pub propose_l1_txs_every: u64, } impl SerializeConfig for BatcherConfig { @@ -200,6 +201,7 @@ impl Default for BatcherConfig { contract_class_manager_config: ContractClassManagerConfig::default(), max_l1_handler_txs_per_block_proposal: 3, pre_confirmed_cende_config: PreconfirmedCendeConfig::default(), + propose_l1_txs_every: 1, // Default is to propose L1 transactions every proposal. } } } From 7eb111d200c6c3aeac79b2541ebba5221a4a3700 Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Sun, 19 Oct 2025 12:40:59 +0300 Subject: [PATCH 062/313] apollo_consensus_orchestrator: fix import Signed-off-by: Dori Medini --- crates/apollo_consensus_orchestrator/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/apollo_consensus_orchestrator/src/utils.rs b/crates/apollo_consensus_orchestrator/src/utils.rs index b4bfa0de075..8b55caec31c 100644 --- a/crates/apollo_consensus_orchestrator/src/utils.rs +++ b/crates/apollo_consensus_orchestrator/src/utils.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use apollo_consensus_orchestrator_config::config::ContextConfig; use apollo_l1_gas_price_types::{L1GasPriceProviderClient, PriceInfo, DEFAULT_ETH_TO_FRI_RATE}; use apollo_protobuf::consensus::{ConsensusBlockInfo, ProposalPart}; use apollo_state_sync_types::communication::{ @@ -28,7 +29,6 @@ use starknet_api::StarknetApiError; use tracing::{info, warn}; use crate::build_proposal::BuildProposalError; -use crate::config::ContextConfig; use crate::metrics::CONSENSUS_L1_GAS_PRICE_PROVIDER_ERROR; use crate::validate_proposal::ValidateProposalError; From 86320a40552f55ae9d9a85162599e5f90e163d95 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Sun, 19 Oct 2025 14:19:41 +0300 Subject: [PATCH 063/313] apollo_compile_to_casm_types: add test for size method (#9560) --- Cargo.lock | 1 + .../apollo_compile_to_casm_types/Cargo.toml | 2 + .../apollo_compile_to_casm_types/src/test.rs | 42 ++++++++++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fe7baf77b35..34cce6b0427 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1029,6 +1029,7 @@ dependencies = [ "apollo_metrics", "apollo_proc_macros", "async-trait", + "blockifier_test_utils", "expect-test", "mockall", "serde", diff --git a/crates/apollo_compile_to_casm_types/Cargo.toml b/crates/apollo_compile_to_casm_types/Cargo.toml index 8dd8a82b543..a50e5dd696c 100644 --- a/crates/apollo_compile_to_casm_types/Cargo.toml +++ b/crates/apollo_compile_to_casm_types/Cargo.toml @@ -25,5 +25,7 @@ strum_macros.workspace = true thiserror.workspace = true [dev-dependencies] +blockifier_test_utils.workspace = true expect-test.workspace = true mockall.workspace = true +starknet_api = { workspace = true, features = ["testing"] } diff --git a/crates/apollo_compile_to_casm_types/src/test.rs b/crates/apollo_compile_to_casm_types/src/test.rs index 35e505d5973..d2b0db59bd8 100644 --- a/crates/apollo_compile_to_casm_types/src/test.rs +++ b/crates/apollo_compile_to_casm_types/src/test.rs @@ -1,6 +1,9 @@ +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; use expect_test::expect; +use starknet_api::contract_class::{ContractClass, SierraVersion}; -use crate::size_of_serialized; +use crate::{size_of_serialized, RawClass, RawExecutableClass}; #[test] fn test_size_of_serialized() { @@ -16,3 +19,40 @@ fn test_size_of_serialized() { assert_eq!(size, serialized_size); expect!["31"].assert_eq(&size.to_string()); } + +#[test] +fn compact_serialization() { + const EXPECTED: &str = "{\"V1\":[{\"bytecode\":[\"0x1\",\"0x1\",\"0x1\"],\"compiler_version\":\ + \"\",\"entry_points_by_type\":{\"CONSTRUCTOR\":[],\"EXTERNAL\":[],\"\ + L1_HANDLER\":[]},\"hints\":[],\"prime\":\"0x0\"},\"1.7.0\"]}"; + let raw_executable_class = + RawExecutableClass::try_from(ContractClass::test_casm_contract_class()).unwrap(); + let serialized = serde_json::to_string(&raw_executable_class.0).unwrap(); + + assert_eq!(serialized, EXPECTED); + assert_eq!(raw_executable_class.size().unwrap(), EXPECTED.len()); +} + +#[test] +fn consistent_serialization_size() { + let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); + + let sierra_class = test_contract.get_sierra(); + let sierra_class_length = serde_json::to_vec(&sierra_class).unwrap().len(); + + let raw_sierra_class: RawClass = sierra_class.try_into().unwrap(); + let raw_sierra_class_size = raw_sierra_class.size().unwrap(); + + assert_eq!(raw_sierra_class_size, sierra_class_length); + + let casm_class = ContractClass::V1(( + serde_json::from_str(&test_contract.get_raw_class()).unwrap(), + SierraVersion::LATEST, + )); + let casm_class_length = serde_json::to_vec(&casm_class).unwrap().len(); + + let raw_casm_class = RawExecutableClass::try_from(casm_class).unwrap(); + let raw_casm_class_size = raw_casm_class.size().unwrap(); + + assert_eq!(raw_casm_class_size, casm_class_length); +} From 73882d001fb5052ec7e39a2d0d5bad748e1954d8 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 14:26:29 +0300 Subject: [PATCH 064/313] apollo_infra: flatten json events in trace (#9630) --- crates/apollo_infra/src/trace_util.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/apollo_infra/src/trace_util.rs b/crates/apollo_infra/src/trace_util.rs index 3d0ff8907e6..cfd699657d3 100644 --- a/crates/apollo_infra/src/trace_util.rs +++ b/crates/apollo_infra/src/trace_util.rs @@ -26,7 +26,8 @@ pub async fn configure_tracing() { .with_target(false) // No module name. // Instead, file name and line number. .with_file(true) - .with_line_number(true); + .with_line_number(true) + .flatten_event(true); let level_filter_layer = EnvFilter::builder() .with_default_directive(DEFAULT_LEVEL.into()) From 4e91669d772187af850e3bf41061cc00d7d7f459 Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 14:37:42 +0300 Subject: [PATCH 065/313] starknet_committer_and_os_cli: bump c-kzg to 2.1.5 (#9628) --- Cargo.lock | 445 +- Cargo.toml | 4 +- .../apollo_l1_endpoint_monitor/src/monitor.rs | 2 +- .../src/py_block_executor_test.rs | 4 +- .../papyrus_base_layer/src/base_layer_test.rs | 2 +- crates/papyrus_base_layer/src/eth_events.rs | 3 +- .../src/ethereum_base_layer_contract.rs | 10 +- .../hint_implementation/kzg/trusted_setup.txt | 4096 +++++++++++++++++ .../hints/hint_implementation/kzg/utils.rs | 6 +- 9 files changed, 4412 insertions(+), 160 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e56924d9348..3c87fb44942 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,9 +93,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b4ae82946772d69f868b9ef81fc66acb1b149ef9b4601849bec4bcf5da6552e" +checksum = "b17c19591d57add4f0c47922877a48aae1f47074e3433436545f8948353b3bbb" dependencies = [ "alloy-consensus", "alloy-contract", @@ -113,13 +113,14 @@ dependencies = [ "alloy-signer-local", "alloy-transport", "alloy-transport-http", + "alloy-trie", ] [[package]] name = "alloy-chains" -version = "0.1.69" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e2652684758b0d9b389d248b209ed9fd9989ef489a550265fe4bb8454fe7eb" +checksum = "bf01dd83a1ca5e4807d0ca0223c9615e211ce5db0a9fd1443c2778cacf89b546" dependencies = [ "alloy-primitives", "num_enum", @@ -128,15 +129,16 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fbf458101ed6c389e9bb70a34ebc56039868ad10472540614816cdedc8f5265" +checksum = "6a0dd3ed764953a6b20458b2b7abbfdc93d20d14b38babe1a70fe631a443a9f1" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", "alloy-trie", + "alloy-tx-macros", "auto_impl", "c-kzg", "derive_more 2.0.1", @@ -144,16 +146,18 @@ dependencies = [ "k256", "once_cell", "rand 0.8.5", + "secp256k1", "serde", + "serde_json", "serde_with", "thiserror 2.0.12", ] [[package]] name = "alloy-consensus-any" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc982af629e511292310fe85b433427fd38cb3105147632b574abc997db44c91" +checksum = "9556182afa73cddffa91e64a5aa9508d5e8c912b3a15f26998d2388a824d2c7b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -165,9 +169,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0a0c1ddee20ecc14308aae21c2438c994df7b39010c26d70f86e1d8fdb8db0" +checksum = "b19d7092c96defc3d132ee0d8969ca1b79ef512b5eda5c66e3065266b253adf2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -181,14 +185,15 @@ dependencies = [ "alloy-transport", "futures", "futures-util", + "serde_json", "thiserror 2.0.12", ] [[package]] name = "alloy-core" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d8bcce99ad10fe02640cfaec1c6bc809b837c783c1d52906aa5af66e2a196f6" +checksum = "5ca96214615ec8cf3fa2a54b32f486eb49100ca7fe7eb0b8c1137cd316e7250a" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -199,15 +204,14 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb8e762aefd39a397ff485bc86df673465c4ad3ec8819cc60833a8a3ba5cdc87" +checksum = "3fdff496dd4e98a81f4861e66f7eaf5f2488971848bb42d9c892f871730245c8" dependencies = [ "alloy-json-abi", "alloy-primitives", "alloy-sol-type-parser", "alloy-sol-types", - "const-hex", "itoa", "serde", "serde_json", @@ -216,9 +220,9 @@ dependencies = [ [[package]] name = "alloy-eip2124" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675264c957689f0fd75f5993a73123c2cc3b5c235a38f5b9037fe6c826bfb2c0" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -229,9 +233,9 @@ dependencies = [ [[package]] name = "alloy-eip2930" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -240,9 +244,9 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b15b13d38b366d01e818fe8e710d4d702ef7499eacd44926a06171dd9585d0c" +checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -252,9 +256,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e86967eb559920e4b9102e4cb825fe30f2e9467988353ce4809f0d3f2c90cd4" +checksum = "305fa99b538ca7006b0c03cfed24ec6d82beda67aac857ef4714be24231d15e6" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -266,29 +270,31 @@ dependencies = [ "c-kzg", "derive_more 2.0.1", "either", - "once_cell", "serde", + "serde_with", "sha2", + "thiserror 2.0.12", ] [[package]] name = "alloy-genesis" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40de6f5b53ecf5fd7756072942f41335426d9a3704cd961f77d854739933bcf" +checksum = "a272533715aefc900f89d51db00c96e6fd4f517ea081a12fea482a352c8c815c" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-serde", "alloy-trie", "serde", + "serde_with", ] [[package]] name = "alloy-hardforks" -version = "0.1.4" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473ee2ab7f5262b36e8fbc1b5327d5c9d488ab247e31ac739b929dbe2444ae79" +checksum = "3165210652f71dfc094b051602bafd691f506c54050a174b1cba18fb5ef706a3" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -299,9 +305,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6beff64ad0aa6ad1019a3db26fef565aefeb011736150ab73ed3366c3cfd1b" +checksum = "5513d5e6bd1cba6bdcf5373470f559f320c05c8c59493b6e98912fbe6733943f" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -311,12 +317,13 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27434beae2514d4a2aa90f53832cbdf6f23e4b5e2656d95eaf15f9276e2418b6" +checksum = "d91676d242c0ced99c0dd6d0096d7337babe9457cc43407d26aa6367fcf90553" dependencies = [ "alloy-primitives", "alloy-sol-types", + "http 1.2.0", "serde", "serde_json", "thiserror 2.0.12", @@ -325,9 +332,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a33a38c7486b1945f8d093ff027add2f3a8f83c7300dbad6165cc49150085e" +checksum = "77f82150116b30ba92f588b87f08fa97a46a1bd5ffc0d0597efdf0843d36bfda" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -351,9 +358,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db973a7a23cbe96f2958e5687c51ce2d304b5c6d0dc5ccb3de8667ad8476f50b" +checksum = "223612259a080160ce839a4e5df0125ca403a1d5e7206cc911cea54af5d769aa" dependencies = [ "alloy-consensus", "alloy-eips", @@ -364,9 +371,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "846c2248472c3a7efa8d9d6c51af5b545a88335af0ed7a851d01debfc3b03395" +checksum = "3652a65bacfba0a169755090d4ecd7d3c63fa534b21d09b8e604dc2609760da6" dependencies = [ "alloy-genesis", "alloy-hardforks", @@ -385,24 +392,24 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c77490fe91a0ce933a1f219029521f20fc28c2c0ca95d53fa4da9c00b8d9d4e" +checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", "derive_more 2.0.1", - "foldhash", - "hashbrown 0.15.2", + "foldhash 0.2.0", + "hashbrown 0.16.0", "indexmap 2.9.0", "itoa", "k256", "keccak-asm", "paste", "proptest", - "rand 0.8.5", + "rand 0.9.2", "ruint", "rustc-hash 2.1.0", "serde", @@ -412,9 +419,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b03bde77ad73feae14aa593bcabb932c8098c0f0750ead973331cfc0003a4e1" +checksum = "f7283b81b6f136100b152e699171bc7ed8184a58802accbc91a7df4ebb944445" dependencies = [ "alloy-chains", "alloy-consensus", @@ -427,6 +434,7 @@ dependencies = [ "alloy-rpc-client", "alloy-rpc-types-anvil", "alloy-rpc-types-eth", + "alloy-signer", "alloy-sol-types", "alloy-transport", "alloy-transport-http", @@ -434,6 +442,7 @@ dependencies = [ "async-trait", "auto_impl", "dashmap", + "either", "futures", "futures-utils-wasm", "lru 0.13.0", @@ -473,15 +482,14 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445a3298c14fae7afb5b9f2f735dead989f3dd83020c2ab8e48ed95d7b6d1acb" +checksum = "1154b12d470bef59951c62676e106f4ce5de73b987d86b9faa935acebb138ded" dependencies = [ "alloy-json-rpc", "alloy-primitives", "alloy-transport", "alloy-transport-http", - "async-stream", "futures", "pin-project", "reqwest 0.12.12", @@ -491,16 +499,15 @@ dependencies = [ "tokio-stream", "tower 0.5.2", "tracing", - "tracing-futures", "url", "wasmtimer", ] [[package]] name = "alloy-rpc-types" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157deaec6ba2ad7854f16146e4cd60280e76593eed79fdcb06e0fa8b6c60f77" +checksum = "47ab76bf97648a1c6ad8fb00f0d594618942b5a9e008afbfb5c8a8fca800d574" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -510,9 +517,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a80ee83ef97e7ffd667a81ebdb6154558dfd5e8f20d8249a10a12a1671a04b3" +checksum = "456cfc2c1677260edbd7ce3eddb7de419cb46de0e9826c43401f42b0286a779a" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -522,9 +529,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604dea1f00fd646debe8033abe8e767c732868bf8a5ae9df6321909ccbc99c56" +checksum = "23cc57ee0c1ac9fb14854195fc249494da7416591dc4a4d981ddfd5dd93b9bce" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -533,9 +540,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e13d71eac04513a71af4b3df580f52f2b4dcbff9d971cc9a52519acf55514cb" +checksum = "6d7d47bca1a2a1541e4404aa38b7e262bb4dffd9ac23b4f178729a4ddc5a5caa" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -548,14 +555,15 @@ dependencies = [ "itertools 0.14.0", "serde", "serde_json", + "serde_with", "thiserror 2.0.12", ] [[package]] name = "alloy-serde" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1cd73fc054de6353c7f22ff9b846b0f0f145cd0112da07d4119e41e9959207" +checksum = "6a8468f1a7f9ee3bae73c24eead0239abea720dbf7779384b9c7e20d51bfb6b0" dependencies = [ "alloy-primitives", "serde", @@ -564,9 +572,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96fbde54bee943cd94ebacc8a62c50b38c7dfd2552dcd79ff61aea778b1bfcc" +checksum = "33387c90b0a5021f45a5a77c2ce6c49b8f6980e66a318181468fb24cea771670" dependencies = [ "alloy-primitives", "async-trait", @@ -579,9 +587,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6e72002cc1801d8b41e9892165e3a6551b7bd382bd9d0414b21e90c0c62551" +checksum = "b55d9e795c85e36dcea08786d2e7ae9b73cb554b6bea6ac4c212def24e1b4d03" dependencies = [ "alloy-consensus", "alloy-network", @@ -595,9 +603,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2" +checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -609,9 +617,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ad5da86c127751bc607c174d6c9fe9b85ef0889a9ca0c641735d77d4f98f26" +checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -628,9 +636,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3d30f0d3f9ba3b7686f3ff1de9ee312647aac705604417a2f40c604f409a9e" +checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ "alloy-json-abi", "const-hex", @@ -646,9 +654,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" +checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", "winnow 0.7.4", @@ -656,24 +664,25 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43d5e60466a440230c07761aa67671d4719d46f43be8ea6e7ed334d8db4a9ab" +checksum = "70319350969a3af119da6fb3e9bddb1bce66c9ea933600cb297c8b1850ad2a3c" dependencies = [ "alloy-json-abi", "alloy-primitives", "alloy-sol-macro", - "const-hex", "serde", ] [[package]] name = "alloy-transport" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec325c2af8562ef355c02aeb527c755a07e9d8cf6a1e65dda8d0bf23e29b2c" +checksum = "702002659778d89a94cd4ff2044f6b505460df6c162e2f47d1857573845b0ace" dependencies = [ "alloy-json-rpc", + "alloy-primitives", + "auto_impl", "base64 0.22.1", "derive_more 2.0.1", "futures", @@ -691,9 +700,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.12.6" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a082c9473c6642cce8b02405a979496126a03b096997888e86229afad05db06c" +checksum = "0d6bdc0830e5e8f08a4c70a4c791d400a86679c694a3b4b986caf26fad680438" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -706,20 +715,33 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.7.8" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6917c79e837aa7b77b7a6dae9f89cbe15313ac161c4d3cfaf8909ef21f3d22d8" +checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" dependencies = [ "alloy-primitives", "alloy-rlp", "arrayvec", - "derive_more 1.0.0", + "derive_more 2.0.1", "nybbles", "serde", "smallvec", "tracing", ] +[[package]] +name = "alloy-tx-macros" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bf39928a5e70c9755d6811a2928131b53ba785ad37c8bf85c90175b5d43b818" +dependencies = [ + "alloy-primitives", + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -2749,7 +2771,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix", + "rustix 0.38.43", "slab", "tracing", "windows-sys 0.59.0", @@ -3053,7 +3075,7 @@ version = "0.66.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cexpr", "clang-sys", "lazy_static", @@ -3073,7 +3095,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.12.1", @@ -3096,7 +3118,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.13.0", @@ -3114,7 +3136,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.13.0", @@ -3158,6 +3180,22 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.2.1" @@ -3166,9 +3204,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bitvec" @@ -3322,9 +3360,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.13" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" dependencies = [ "cc", "glob", @@ -3417,9 +3455,9 @@ dependencies = [ [[package]] name = "c-kzg" -version = "1.0.3" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" dependencies = [ "blst", "cc", @@ -4805,6 +4843,16 @@ dependencies = [ "darling_macro 0.20.10", ] +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + [[package]] name = "darling_core" version = "0.14.4" @@ -4833,6 +4881,21 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "serde", + "strsim 0.11.1", + "syn 2.0.100", +] + [[package]] name = "darling_macro" version = "0.14.4" @@ -4855,6 +4918,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.100", +] + [[package]] name = "dashmap" version = "6.1.0" @@ -5887,6 +5961,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -6493,7 +6573,17 @@ checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.4", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "foldhash 0.2.0", "serde", ] @@ -6558,6 +6648,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hex_fmt" version = "0.3.0" @@ -6800,6 +6899,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.1", "tower-service", + "webpki-roots 0.26.7", ] [[package]] @@ -7279,7 +7379,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cfg-if", "libc", ] @@ -7785,7 +7885,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f0bee397dc9a7003e7bd34fffc1dc2d4c4fdc96530a0c439a5f98c9402bc7bf" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "byteorder", "derive_more 0.99.18", "indexmap 1.9.3", @@ -8222,7 +8322,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "libc", "redox_syscall 0.5.8", ] @@ -8248,6 +8348,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" version = "0.7.4" @@ -8914,7 +9020,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", @@ -9170,13 +9276,14 @@ dependencies = [ [[package]] name = "nybbles" -version = "0.3.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" +checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" dependencies = [ "alloy-rlp", - "const-hex", + "cfg-if", "proptest", + "ruint", "serde", "smallvec", ] @@ -9252,7 +9359,7 @@ version = "0.10.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cfg-if", "foreign-types", "libc", @@ -9809,7 +9916,7 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix", + "rustix 0.38.43", "tracing", "windows-sys 0.59.0", ] @@ -10013,11 +10120,11 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "hex", "lazy_static", "procfs-core", - "rustix", + "rustix 0.38.43", ] [[package]] @@ -10026,7 +10133,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "hex", ] @@ -10067,18 +10174,18 @@ dependencies = [ [[package]] name = "proptest" -version = "1.5.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" dependencies = [ - "bit-set 0.5.3", - "bit-vec 0.6.3", - "bitflags 2.6.0", + "bit-set 0.8.0", + "bit-vec 0.8.0", + "bitflags 2.9.4", "lazy_static", "num-traits", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_xorshift 0.3.0", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_xorshift 0.4.0", "regex-syntax 0.8.5", "rusty-fork", "tempfile", @@ -10387,6 +10494,7 @@ checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", + "serde", ] [[package]] @@ -10450,6 +10558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.1", + "serde", ] [[package]] @@ -10526,11 +10635,11 @@ dependencies = [ [[package]] name = "rand_xorshift" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.9.3", ] [[package]] @@ -10548,7 +10657,7 @@ version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", ] [[package]] @@ -10614,7 +10723,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", ] [[package]] @@ -10767,7 +10876,10 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls 0.23.20", "rustls-pemfile 2.2.0", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", @@ -10775,6 +10887,7 @@ dependencies = [ "system-configuration 0.6.1", "tokio", "tokio-native-tls", + "tokio-rustls 0.26.1", "tokio-util", "tower 0.5.2", "tower-service", @@ -10783,6 +10896,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots 0.26.7", "windows-registry", ] @@ -11008,13 +11122,14 @@ dependencies = [ [[package]] name = "ruint" -version = "1.12.4" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" +checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", + "ark-ff 0.5.0", "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", @@ -11025,9 +11140,10 @@ dependencies = [ "primitive-types", "proptest", "rand 0.8.5", + "rand 0.9.2", "rlp", "ruint-macro", - "serde", + "serde_core", "valuable", "zeroize", ] @@ -11134,10 +11250,23 @@ version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.11.0", "windows-sys 0.59.0", ] @@ -11414,13 +11543,34 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -11433,7 +11583,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "core-foundation 0.10.0", "core-foundation-sys", "libc", @@ -11491,18 +11641,28 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -11967,7 +12127,7 @@ dependencies = [ "base64 0.21.7", "crypto-bigint", "flate2", - "foldhash", + "foldhash 0.1.4", "hex", "indexmap 2.9.0", "num-traits", @@ -12373,9 +12533,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.25" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4560533fbd6914b94a8fb5cc803ed6801c3455668db3b810702c57612bac9412" +checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" dependencies = [ "paste", "proc-macro2", @@ -12426,7 +12586,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -12494,15 +12654,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.2.15", + "getrandom 0.3.1", "once_cell", - "rustix", + "rustix 1.1.2", "windows-sys 0.59.0", ] @@ -13034,8 +13193,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "futures", - "futures-task", "pin-project", "tracing", ] @@ -13671,7 +13828,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.43", ] [[package]] @@ -14092,7 +14249,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", ] [[package]] @@ -14178,8 +14335,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" dependencies = [ "libc", - "linux-raw-sys", - "rustix", + "linux-raw-sys 0.4.15", + "rustix 0.38.43", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a14b1bd817f..75c8a28fa81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,7 +92,7 @@ license = "Apache-2.0" license-file = "LICENSE" [workspace.dependencies] -alloy = "0.12" +alloy = "1.0.38" anyhow = "1.0.44" apollo_batcher.path = "crates/apollo_batcher" apollo_batcher_types.path = "crates/apollo_batcher_types" @@ -175,7 +175,7 @@ blockifier_reexecution.path = "crates/blockifier_reexecution" blockifier_test_utils = { path = "crates/blockifier_test_utils", version = "0.15.0-rc.4" } byteorder = "1.4.3" bytes = "1" -c-kzg = "1.0.3" +c-kzg = "2.1.5" cached = "0.44.0" cairo-felt = "0.9.1" cairo-lang-casm = "2.12.3" diff --git a/crates/apollo_l1_endpoint_monitor/src/monitor.rs b/crates/apollo_l1_endpoint_monitor/src/monitor.rs index 770433f3c81..3391a07e33b 100644 --- a/crates/apollo_l1_endpoint_monitor/src/monitor.rs +++ b/crates/apollo_l1_endpoint_monitor/src/monitor.rs @@ -90,7 +90,7 @@ impl L1EndpointMonitor { // high-level readability (through a dedicated const) and to improve testability. async fn is_operational(&self, l1_endpoint_index: usize) -> bool { let l1_endpoint_url = self.get_node_url(l1_endpoint_index); - let l1_client = ProviderBuilder::new().on_http(l1_endpoint_url.clone()); + let l1_client = ProviderBuilder::new().connect_http(l1_endpoint_url.clone()); let l1_endpoint_url = to_safe_string(l1_endpoint_url); // Note: response type annotation is coupled with the rpc method used. diff --git a/crates/native_blockifier/src/py_block_executor_test.rs b/crates/native_blockifier/src/py_block_executor_test.rs index 3708046ffa4..0cad01f943d 100644 --- a/crates/native_blockifier/src/py_block_executor_test.rs +++ b/crates/native_blockifier/src/py_block_executor_test.rs @@ -41,7 +41,7 @@ fn global_contract_cache_update() { ); let class_hash = class_hash!("0x1"); - let temp_storage_path = tempfile::tempdir().unwrap().into_path(); + let temp_storage_path = tempfile::tempdir().unwrap().keep(); let mut block_executor = PyBlockExecutor::create_for_testing( PyConcurrencyConfig::default(), PyContractClassManagerConfig::default(), @@ -124,7 +124,7 @@ fn global_contract_cache_update_large_contract() { let dep_casm: DeprecatedContractClass = serde_json::from_value(raw_contract_class) .expect("DeprecatedContractClass is not supported for this contract."); - let temp_storage_path = tempfile::tempdir().unwrap().into_path(); + let temp_storage_path = tempfile::tempdir().unwrap().keep(); let mut block_executor = PyBlockExecutor::native_create_for_testing( Default::default(), PyContractClassManagerConfig::default(), diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index 2a73e1a878e..71444eca537 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -35,7 +35,7 @@ fn base_layer_with_mocked_provider() -> (EthereumBaseLayerContract, Asserter) { // See alloy docs, functions as a queue of mocked responses, success or failure. let asserter = Asserter::new(); - let provider = ProviderBuilder::new().on_mocked_client(asserter.clone()).root().clone(); + let provider = ProviderBuilder::new().connect_mocked_client(asserter.clone()).root().clone(); let contract = Starknet::new(Default::default(), provider); let base_layer = EthereumBaseLayerContract { contract, config: Default::default() }; diff --git a/crates/papyrus_base_layer/src/eth_events.rs b/crates/papyrus_base_layer/src/eth_events.rs index 51d1c291bd0..2f9177a620e 100644 --- a/crates/papyrus_base_layer/src/eth_events.rs +++ b/crates/papyrus_base_layer/src/eth_events.rs @@ -19,11 +19,10 @@ use crate::{EventData, L1Event}; // Note: don't move as method for L1Event, we don't want to expose alloy's inner type Log to our // base layer's API. pub fn parse_event(log: Log, block_timestamp: BlockTimestamp) -> EthereumBaseLayerResult { - let validate = true; let l1_tx_hash = log.transaction_hash; let log = log.inner; - let event = Starknet::StarknetEvents::decode_log(&log, validate)?.data; + let event = Starknet::StarknetEvents::decode_log(&log)?.data; match event { Starknet::StarknetEvents::LogMessageToL2(event) => { let fee = Fee(event.fee.try_into().map_err(EthereumBaseLayerError::FeeOutOfRange)?); diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index d8e487bad39..61ea67a79cd 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -5,6 +5,7 @@ use std::time::Duration; use alloy::dyn_abi::SolType; use alloy::eips::eip7840; +use alloy::network::Ethereum; use alloy::primitives::Address as EthereumContractAddress; use alloy::providers::{Provider, ProviderBuilder, RootProvider}; use alloy::rpc::json_rpc::RpcError; @@ -47,7 +48,7 @@ sol!( /// An interface that plays the role of the starknet L1 contract. It is able to create messages to /// L2 from this contract, which appear on the corresponding base layer. -pub type StarknetL1Contract = Starknet::StarknetInstance<(), RootProvider>; +pub type StarknetL1Contract = Starknet::StarknetInstance; #[cfg(any(feature = "testing", test))] pub struct L1ToL2MessageArgs { @@ -126,10 +127,9 @@ impl BaseLayerContract for EthereumBaseLayerContract { call_state_block_hash.call_raw().into_future() )?; - let validate = true; - let block_number = sol_data::Uint::<64>::abi_decode(&state_block_number, validate) + let block_number = sol_data::Uint::<64>::abi_decode(&state_block_number) .inspect_err(|err| error!("{err}: {state_block_number}"))?; - let block_hash = sol_data::FixedBytes::<32>::abi_decode(&state_block_hash, validate) + let block_hash = sol_data::FixedBytes::<32>::abi_decode(&state_block_hash) .inspect_err(|err| error!("{err}: {state_block_hash}"))?; Ok(BlockHashAndNumber { number: BlockNumber(block_number), @@ -366,7 +366,7 @@ fn build_contract_instance( starknet_contract_address: EthereumContractAddress, node_url: Url, ) -> StarknetL1Contract { - let l1_client = ProviderBuilder::default().on_http(node_url); + let l1_client = ProviderBuilder::default().connect_http(node_url); // This type is generated from `sol!` macro, and the `new` method assumes it is already // deployed at L1, and wraps it with a type. Starknet::new(starknet_contract_address, l1_client) diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/trusted_setup.txt b/crates/starknet_os/src/hints/hint_implementation/kzg/trusted_setup.txt index d2519656fb2..47d17784051 100644 --- a/crates/starknet_os/src/hints/hint_implementation/kzg/trusted_setup.txt +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/trusted_setup.txt @@ -4161,3 +4161,4099 @@ b990ae72768779ba0b2e66df4dd29b3dbd00f901c23b2b4a53419226ef9232acedeb498b0d0687c4 8d27e7fbff77d5b9b9bbc864d5231fecf817238a6433db668d5a62a2c1ee1e5694fdd90c3293c06cc0cb15f7cbeab44d0d42be632cb9ff41fc3f6628b4b62897797d7b56126d65b694dcf3e298e3561ac8813fbd7296593ced33850426df42db a92039a08b5502d5b211a7744099c9f93fa8c90cedcb1d05e92f01886219dd464eb5fb0337496ad96ed09c987da4e5f019035c5b01cc09b2a18b8a8dd419bc5895388a07e26958f6bd26751929c25f89b8eb4a299d822e2d26fec9ef350e0d3c 92dcc5a1c8c3e1b28b1524e3dd6dbecd63017c9201da9dbe077f1b82adc08c50169f56fc7b5a3b28ec6b89254de3e2fd12838a761053437883c3e01ba616670cea843754548ef84bcc397de2369adcca2ab54cd73c55dc68d87aec3fc2fe4f10 +97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb +ad3eb50121139aa34db1d545093ac9374ab7bca2c0f3bf28e27c8dcd8fc7cb42d25926fc0c97b336e9f0fb35e5a04c81 +8029c8ce0d2dce761a7f29c2df2290850c85bdfaec2955626d7acc8864aeb01fe16c9e156863dc63b6c22553910e27c1 +b1386c995d3101d10639e49b9e5d39b9a280dcf0f135c2e6c6928bb3ab8309a9da7178f33925768c324f11c3762cfdd5 +9596d929610e6d2ed3502b1bb0f1ea010f6b6605c95d4859f5e53e09fa68dc71dfd5874905447b5ec6cd156a76d6b6e8 +851e3c3d4b5b7cdbba25d72abf9812cf3d7c5a9dbdec42b6635e2add706cbeea18f985afe5247459f6c908620322f434 +b10f4cf8ec6e02491bbe6d9084d88c16306fdaf399fef3cd1453f58a4f7633f80dc60b100f9236c3103eaf727468374f +ade11ec630127e04d17e70db0237d55f2ff2a2094881a483797e8cddb98b622245e1f608e5dcd1172b9870e733b4a32f +af58c8a2f58f904ce20db81005331bf2d251e227e7d1bef575d691bdca842e6233eb2e26c2e116a61a78594772b38d25 +b3c1313c31ec82da5a7a09e9cf6656ca598c243345fe8d4828e520ade91787ffb8b9867db789b34ad67cef47b26ff86d +a8ed8a235355948e0b04be080b7b3e145293accefb4704d1da9050796b2f6870516c1ebf77ae6a65359edcfd016c0f36 +80e792d5ba24b8058f6d7291a2ec5cb68aab1e16e96d793128e86815631baf42c56b6205c19e25ce9727bd1fd6f9defb +816288c5d726b094e3fdf95cb8882f442c4d9d1101b92c7938a7dfd49bc50636d73ea1b05f75eb731c908c8fd8dee717 +ae009128d128ba2e1519bfa7a0c01ed494a7d461c3aba60f8a301701fed61fe4e31d6c79ce189542ae51df91e73ce1b3 +96a866d60a9007d05825c332476a83e869e15b11d7257172a67690ea9bd3efea44bf9c8d42191454eb04fcf110b16396 +8b250a2a06419adb9b611e89f7f8f2990aa301949b533ad3bf17c4a61ab5f5be0b1d5e2b571864d13f1bb75805c7795d +8450f49facf2e620fa45ee90e1801178842d927a2a25fc6ed7ba99a4eec7ae40eebfee41028eaa84f107f4a777694976 +91049080cf659c0985a22d1366e59191bb89663f922e8168b9b7d85c8a73d74a6d9dceefd855d3d858b493670c750581 +a1e167aeb2008087f3195926f1985c0a459d6ec57237255b1473a96de4e2c1cf766127c862c7dc853a6909e67cb06cf7 +b667c0d4e26e20698b07567358625d5f003839c92de8088e12dbd74a6f6a3156b4ea8d252c9ad62af5f6c4fec1cf6cc7 +8e4b5e304c0b1b161ae3e4b68b5e3ac66c42acd7c1ee2458044f6527c508a93995e50894d72d57c1350f91afe72775ff +8c642640aa7915421cdc21fd639f88a42052b1cfa358ff7702e60793a92b7b5926dae15a0c8f8f59cd3013f01c159ba3 +a356f35e713cfc283056bf539de54a21731e61efb4c47319f20de4a4b723d76a33b65f4a67d298b9ec5c2a1579418657 +93ce204146ce95f484dc79c27919a16c9e3fc14a9111c6c63d44491158d5838117d20851cc3227a5e8ba6ccf79e77f39 +b585664cbb9a84b52f89114e1cf0cf1171bea78a136dc1404ac88a11210b2debc3b7a55e702da93ff629095c134a295e +b6dfd444ec7fdceb14c6328f26ca12c3f9fc4327d8d8c68948e92e7e61262b82d833a65a9e3af6353ffa832b6da25705 +b4d4b8eb9ecfffe3f0d48fb4149c7b31aec1da7041ec03bd0750c52a2a7cbc3a7cfbf09d5bfdc56e3860826a62d0bb91 +a4e248e3d61db52da9683fef188579c470d65e2df9064726847b1599fc774049ffdc6ef2ae578d5ed7874f1298ecdf69 +a68a0fffc2e37d3183feb01b42234c0f4e510f9dc29d09c571e6da00fecad9da224cd0f31550070148667e226c4ca413 +86adda2ffecb77236c18005051f31f9657a0d50fef2a1175dfda32e74d5d53df825c10f289eb0ad39df0c64fc9bc7729 +998266d5c9c3764ed97d66fa9ed176af043999652bae19f0657c8328629d30af453230e3681c5a38e2f01e389ed8d825 +a05261554d3c620af0c914cf27ab98f5d3593c33ab313c198e0c40d6c72022eb5943778cd4f73e9fe8383392a7004976 +ad243fb3631bf90fedb9d679fd71fc0cf06bda028591ded2bd4c634ea7b3c2bd22eca2ab318fcdaa6c2cda1e63e1c57b +89b9859a04f903c95e97fb2951f01cc6418a2505eee0b5bc7266b4d33e01b69b9fe7dc56fa9ebb5856095be0925a422d +a68d118343a5bbfbbab95ff9bfe53aeb7fdbaf16db983e6f4456366df2aa01fbdb6ee9901cb102fc7d2bd099be2f1f3e +b49301f25d5a9dd2ec60ddb0b4b477291958487efea9e54dc0e4ef388f03b8bbadd13259d191f7a0b7513876767d8282 +8b93df7fb4513f67749905fd43db78f7026589b704ebb9ea3255d0ad6415437799f40f02e07efccda1e6fd5e8cd0a721 +ad88769ace96455da37c3c9019a9f523c694643be3f6b37b1e9dcc5053d1fe8e463abebdb1b3ef2f2fb801528a01c47c +80f0eb5dcbfaaf421bf59a8b9bd5245c4823c94510093e23e0b0534647fb5525a25ea3aeea0a927a1ee20c057f2c9234 +b10ad82ea6a5aeabe345d00eb17910d6942b6862f7f3773c7d321194e67c9cced0b3310425662606634dcd7f8b976c04 +82f6fd91f87822f6cc977808eeac77889f4a32fb0d618e784b2331263d0ffa820b3f70b069d32e0319c9e033ab75d3b4 +9436d3dc6b5e25b1f695f8c6c1c553dab312ccace4dac3afddc141d3506467cd50cb04a49ea96ea7f5a8a7b0fc65ef37 +8e0a9491651d52be8ebf4315fbbb410272f9a74b965d33b79ff1b9e1be3be59e43d9566773560e43280549c348e48f01 +8809137e5d3a22400d6e645a9bd84e21c492371736c7e62c51cef50fee3aa7f2405724367a83fd051ff702d971167f67 +b536a24f31a346de7f9863fc351fa602158404d2f94747eebe43abf1f21bf8f95a64146c02a4bec27b503f546789a388 +b5cdf5a04fc12a0e0ef7545830061dff7fd8abea46e48fbe6235109e6c36ee6bffcb9529e2f3d0d701cf58bbfb6a4197 +ab15377525753467d042b7931f66f862cbbb77464212c9aa72d4e5c04375ef55f619b3a446091c1ba1a3b5d9f05e538f +905a75b943ad017ff78ea6ddd1d28a45c7273ee1c2e5e3353685813793ead3370c09cabd903fcab9d8b1c6961372d486 +8147df4324faddc02fb0896367a7647b719b6499a361aecfdd3a34296fa6768ad31c34f9e873fd1e683386c44651883e +ac91d08570dd91f89d2e01dca67cdc83b640e20f073ea9f0734759c92182bb66c5d645f15ebd91ed705b66486ed2088d +ac6295ef2513bbea7ef4cdcf37d280300c34e63c4b9704663d55891a61bf5c91b04cc1d202a3a0a7c4520c30edc277c7 +b604be776a012095c0d4ebc77797dd8dec62a54c0559fb2185d7bac6b50d4e5fd471ac2d7f4523206d5d8178eabd9a87 +80ead68def272ce3f57951145e71ed6dc26da98e5825ef439af577c0c5de766d4e39207f205d5d21db903d89f37bbb02 +9950b4a830388c897158c7fe3921e2fe24beedc7c84e2024e8b92b9775f8f99593b54a86b8870ec5087734295ba06032 +b89ba714adabf94e658a7d14ac8fc197376a416841c2a80e1a6dde4f438d5f747d1fb90b39e8ea435c59d6ecda13dea1 +b0c78e7cc60bd05be46d48fbb0421a678c7f14b8d93730deb66fbe1647613b2c62b5075126d917047820c57fc3509cb9 +a860c4acc5444e9ae987e8c93cb9a5f17d954d63c060cc616f724e26bc73d2c54cd36e0492d1fde173847278e55942ba +8fb8269c9d5c15428e8d45da1251e4c4a4b600d47da0caea29fef246854d8fb6acae86a8e6440d0c429d8dd9c2dfee0c +96c5d8eb6fd5c525b348ee4335d200139e437e4be83690af0f35b7f336a7cda8c6d2958647988b84da9f2dd7bbb7710b +a7f62141c4346cc14e9823dc38ac7d587b0427022afc1498d12ee2c43f6ac3a82167057e670dd524b74137f8c3ceb56d +956aac50d06b46a3e94397f163f593f5010d366aa2d816c2205c7d0f47f90cf0f36c169e964f9bcf698d49182d47d91f +b812899bcdc0e70d79ca729cb01104bf60e1357b9085a10f64f3ba9865d57e9abd0a505a502d4de07afb46f4d266be2f +abce02c7e1372e25d40944dc9ece2904a8f59c8854c5f2875fe63ace8ce37d97881f4f9ab4f7bad070ec8e0daee58d3f +8fb13c515b2d6abb4e14ed753fad5cc36c3631dfe21a23d0f603aad719423dd5423157eefcbd9a9c6074e155b79eb38d +a9ef67304dc297ab5af778cf8afa849eeac27db4b6978963e97b95ef7a8d3264d0d07775f728c298a2b6daed2ecf5053 +a9b975520adb066e2ff2a4cde53284c23bc84261a22dc43b1634d99eff8e7892e46bb6e6da7319c9e72788aa9ea7a1ea +a6eaea4ab4206294474d9b956d9d3188d558a5633de2bd05df0d3bac03dbcbe4ed85406349c1d2e660b77c6da1f5bf8c +af4a19f77290dddee762e1e0d4bc9945aacea3f75756ae46cd3e58a8f74d1b5db73e4834687946b0f39191e32f2fed0c +aafa6523f58f1a4cabc924c86d842816d606afeea21fa4b2b8b9573425810fdcc41c98888318e868f9c05e2be12178a3 +8ef38fba0a3fa4ebe985239c8b759c22aaef0c57e6f39050a651c869487803b0d1e389c3d958fb5a7f37740f050ac69e +b07dfc9f85913c608ca7596a2e361f05e4853fad00e796fd492d247de6414892ce160f627669b1ba933b6ad726415d4e +94da679ad1d78b2bff5283c938f17b2a7d6e9cbcdf59d340e6dfb652951c7a9e852ac0590f99cfee9631b9410f6f00ea +98a907c9c021a5b034d3720197c160a82c4b7146cb73d48efeed99b9d0c6b831812cf80ac7e19e85a676a8cd3ead72de +adb746595466a12929019d0048cea33236b05c1229d2eba73b259a18a786f2bc3f05fc0598d8ce253cecb80bdf679aaf +a2fbac016996d68f9027a157b0a3f6a336144a798d6113adfcda3a5d05b62c31f108f112aa915906aef22b7f83b9228b +81841dea1904406d1b6fa49b4b3f7f6cb40b7646cf44d36c9fa07e3dee29f8e47324b40d8356ddf653109673c3374e9b +a3edbb8aac5e60c775775cbdb19067341b2e2530de48738e84c2c07151241ee31f0d8333bf20c2bc9dcb7b2e638a6b5e +b8aa6890e22964828787ce86460d3a32f12a655bb5c28de500f2fcf6b61e3334640ec6ba96029a4912af0d18df4b4139 +8ca43169f04243ad0fdb0152de17c60d9e31ee0ab520970fccd98590e05508821a183b4b367967e60d53c2c826ec5dbd +b179fffd9df8c00486c5a8b9327d599f5a11745ef564f06e126849b06fe2f99273c81f65bc941efb0debaadfecbfec1c +acf068f1c2b1926279cc82750ce21b0d6b0bfd0406f0d8bbfa959bd83935932957c7f6b8de318315bf0b75f6ee41a0f2 +b97831da260919c856e9f71a41687f5979bc16f8a53b1037285b4a2f9ce93af5cfe70bf0ad484744827fb55c847b58eb +aff50b0bd907383b0c241727af364fe084d021221bfb1b09fb6c1a7752eeba45d662493d590f1f182764b90b25f17906 +aeeef044c14e3ad41e1235c9e816e1eb49087fd3abe877b89b3bade74459186126e160bb569bcd77779e701b19b5f71a +8483deb2b7001ca7c438fcdca8ca6aba96c9cbc4becfd9b16a6062705eae270011bcaedcae69bb54630d8c78129e57c7 +aeee8d24be4ac0d9784c029e239fb5e64316ce29b88f47394cfaaa8bb966a72061bff72f99d02dc51c9705854686e77f +90ae09525a16bb2422169e15d6831c87968a14ebc0d1d27e11a759839c73c655b9d33ee5b12f275d6f440688146fbd2f +a3a41fc7fefef101422465e506bea7f3ff23c26fe35f5732b86f5f2471fb93b37ebc339f84c6be1e8d22abc812c2e212 +86f4b5293e8aea4af1f1fb05dcf99714cb3aff1cfc849b1bb73524061c921c9da9ad92579a852e1889da29d952f02fe5 +8932ef39d4050a1e9dc0fd8afeaf159472d71c5c27f458c69d2730836606ea56e19c8c4febf2535f930d3260e9bc7637 +86307b9f3696bb21c20e4558e30310389e7367803c353d437e9b696039a0ff054d9a4953b75237ab1d1dd6f71118c189 +96e57730e683ef5b550c91de18b19ac73879f3e26234297db68d28747ed0953beb0f3913cfb720c602720bf9330685d8 +b04a19ee70123782e47b238abde55baf60ac0c66292a998af0d14afc8bbeb1134e557b94cd17a020084631c09a0d3c02 +829abc8718be8139569fcb2c398962f38f4201114d30e2b2fb23566f8a27a5c380f5605cec543415202a12ed859e33f6 +a0744fa488c8fa92a722c5fc4ef5a47dfe824eccd87d26c8bab9c174cbb151d44b1b29082c48652f03d3177e5ec86001 +81d4035ae9fd28bdcd78b135cb54955d3b685a527319df6ee7e904b8e6d796f5f5a5f5035ee1de750c4cb6050e452b9e +b205e8c2ec24d7104fa0106c09ad34b5a912c1adef553fb718838dd627355993c2ec01055c11d00b2c75b68e9516d44b +b12d09da7968fa7394e449624fc7174d1d76c069ccb03e140d4d87a2d3f6d1f7b9cfc930f0c80becc673406ebe63f08e +b23752c158695da85048fdf38b395681cc0e8998630af8a9ed41efbda08c9964c2dc8ae6e53377264be4467d702c0de4 +b0d84582fd73628d96b8c1ec96197697c41a963542451a2ade0890af0d33c7161d0f18e1a1ce2c168ca2dc1e9119d55e +8b877e618b469aa187632e410b125d2999d5738fd66d482000706b51fd904a0c7e7daa8c9b729fa33817bbc4154cba2a +b1cfc8a7551b601723b937d497d01dec3ee7614c2bf13d430b1058d5ebc1406045009ff02c2ac15bf8cf16f860193d1e +b6d9da84f97b21e13175bbb0b5cc8e79e88b470c87a3e115726c1bd98e0288526c58f3faaa8aa170ace0cd6a60852525 +ad2e773c2d527671ca5fab7085dde4da31cd35f45d4315dd95d8893ff5fb900494dca08eccfc1a2fc7bf7c7fd2fcab97 +8d5a79b34aeb761d4a0c73f09f02e9548e6d382c33ee6887a759ab05762b490b8a549ef2933c7e3a46415c154c0221c0 +b6f2cbe81bd0a7298403be392f8456bed30aed7ef30216959357698f789affd2942ae5fbaf3f48ecebeb7c273b20cb57 +b5b6c45d99cea7ce6a1dc134aff4a8f630f299b42bd59592a7592345f8cd35bcbee944e61b0723de732fcad6e4425b63 +8077d64dfcb2418974e956ea6dbf8a4c05b25d2a025333ad7e2a379f1976dc036771403383a51bfa3476c9c619ef8bef +ad2e0a9d479c77a5fb73b3613a177fdaad50dcb50fed50e756ba18164c153af30b07fb2565e80ff7469f1b0338b7b5de +81017d1d80a6b6df4e99d0d7f85a8180b5523e8fa2ea2672fddff604933f8a113cab27fce098dcb454d7d1f7ed266e04 +852355479d68e76c7febf6dfe2ef8e80d575c0d3bd52c983803592021cfa898c571c0b884412c21e66f0dbfe03167b53 +98e1bf8ad48421467c93b9f72b47dded7c41b4fcd36ea55ca43ab24b0d0b876f5a731f422579b7167c7138fad2121266 +803369314abd5422019ed4b0ef652b4dbe97ef5a87b0ea373eec9628b64a12120b2c3d4eb53db405131ff786d14c7ac6 +adf2613fc34f73e1160975c140e925ed84d254e03cc3bc7fc1d19957b499c9ba9d9e4c1639981b594a7095c0a52c6757 +a2f6a68efdff6e4173c00692abcfdfcdaf6f8b62369afad3dafaae4f2f38c4860780b4624d185e20e4f4498b75b5fe94 +8b1658aa0e119fb8401d486ed08d60240d26a8623ef9788e3b45ad09ae31259395b021bd16be395139cbb7149714e764 +a7dd8bf21121285e00672ee8bb84e0cb39b2496fb53a26e35dfbca7f2b04e9a9ff9db15f53fe63fcbeafeb2deeaf2ca4 +b6d8d709e44bc18f3b41d69608edce60c02bcba48d3b7e2fd420842657f0665a7343246dea149a25e8f3416284abae66 +aaf744ca5e9bcb63e3e2939b7a1e96e4a93c88c76bec0cf4294dd7db95cdd3f6a7d92196e352d08680e2328bc4592899 +84434b015a7c398d35f1ec71fce455d62ba4ed4f62da042ec31bb2b4db47073314354cd50bc322297a1cfe35138bf490 +8d70b3a3cd9d5dfefdacfa418c0b775a112a47ce538d33a560a519660009c3f141fd6221c18539129e9c0acdaceeeb80 +b8c6903412a800ec78a4c15f31c24385a267b0c0ece32fd31bbbb557fd70c3b2d60d8fc0f90fbd70f43baa1928ea30ba +8e391dd445ea06cabb433f057853f8159511b2f9bef41aed9ccd14e0a6fcd912bbaebd38fd5fb736cfde0fa34b7a4874 +a40cd988f70613df32babbd1bbc2f1b29ff1ab0147b01161555a81d56c9621657999bcdb1df38485f687afc51d5d0f23 +b6a008b4426b3d7b28ae04eee4698fc8ef6a35d89008ef5394da39ce582ce1a45dcfae9a33b90f6fa4237f3667803873 +8987280debfb175c3b44a2f152ea82548e4f680966f1fcbee9bf7d714e31bf8080c33f52705ef3aeee70544b22516aba +a78a51a2c11eea7680a5a0ae417a2981f8c69c396e06da621eadd7510a3664ade49d065617bec67b3de779548a4f4509 +a4d9163f0a1bc048385e94d5e0bcafeee1b18f28eb23505623b9e8ef16f3df76408254dfbe790e45f2884198060d388d +83dcae2568a0c518793c0f6e38b42f9ceb50673d100b556a17ec8bd9faeec84afe50b8d72422c6b2356959667bb8e2de +874731941be4474b4576226e5906b5dee89fc9b56a9870dcc7289c1a7d494d345ba6aba31f7546a16f9963283c05f744 +82c1cfab1f501189ac20147fc4631075dbf1abf9125b7d42fcb4f31cf73f3d6461b1bd08fdf6e45cc54bc08a7d5d51d1 +b978228286f5d4a10ce027b6bea3021affcaa805340ca4b5192c69e8c56db59f48e4a14a284ec015f53baf97389f62b2 +af125f4fdccd1c1b64fdffecb5ec7cf8c7392bbe476e1b89a5b5329c5ba4a526e58c11e72ab9de8a38d60af648d75adc +8411a41ec14295acab0d36389013535a80dfff6e024bffeb32fb3070762f61256419e8c51b2ad6de9dbe4f1e8e286912 +8ea67a91112a41f9c65515cd496f4b0cdefa1400fc06568eef000c9eae6dc250fb7622eb3f2deca10b37287cd96fa463 +8da99b6c55c31dee6a49aabb54da249d348a31d4416201a10c45a3b04b11e99d4ae9813632f0ee36c523b5cca62f6f49 +8b44656341e039e2bd83a19c3bb9a88f6209482e274f8cd4f8557b728e5948dd80b5745f621b96f4562928689314e8c2 +a02d424a615ba0dce8ed91f477e79852215a3a39d025059826fa278e7eebef19824b2a2844f5b3865a0f471b609a23f5 +a1f115cebc3fff3bcf233da27cef19eae791660f155d088003460f75567a550bef0722885010ddc384acdeac635939dc +b61a55ce9d143c17876776e064b58a10baf0ba13553c785c1e47f57b5f94c0cda8bc89d43d73386e57816c15b61a8ec8 +b4073f47041e20a8e548c7fb00e07ba3b9056c34eb4ab63bb0e7b48f8e338e8b56a17611a1b5f4c03b352450b86f1d69 +a7b1a07b213205b682fc5b6acb7e76fdf97b280c26621d8f3b76b7c1deb3511957da33a4e358c8e8f3d98b2a8855d67e +b797e67c2670fbd9844e8a68c585f404b035dc14bd4ec75c3f95f932c777f9db5d5f5df7629164af488fc1213035cc5f +99618200797b945f595794d6468e5c618649554ad9ba896330f1cc844090eb956ae9fc23132912f9047085c5f0c3bf7b +81194aa1319abf534cb3927af9adfb178a99d0e3e8c99ab1105f1d3b4fed40ec2971caf1d6647acb0c8d681eca53097b +80673f18e4978dbc226a6cd4b128a1259d9a7f833879c6e2fbe24d69fef2c3c23a51a4f3e8d88fa4533434bbb0723661 +8125bf6c7dbb2fb63aaa3f53283559f172c788223674adbeb6d5bd17cfe888e6b87a79aec774917f20ce911c1f85f8e7 +884bcdb1878b14fc38adc9fb8b4dd0b3afde404fbeb664f26ddfebc81736018551f23e75ce4cfe4865f610bcd454fbd7 +aec65c8d4be8316e98aa54888af01bc6703a0c5d04b69756ff39a0a947b66817ec59d76afe9f61a25749b5e890f03e02 +aa457aaa1b014a4c5a8992847a187a23321bb43452c98745987d038e3b04046102ae859b7a8e980eea978a39d76a88ef +a9832ee63b08e19123f719bfe2fe742125f32463efa966c7709a98ebfc65277670e9ea1fa2d2d78b96bdc7523b0c4c3e +a87b6b1b7858f96d55064274f29fbde56067064962cf3c3e2ba3110b22ea633bc037a74d23543ce3307a46208855d74f +897cbe4ab68a753020fec732dfcc052c7ed9905342b5a6fe0aa25c631f9ad9b659e0ee75d46f0df6507b6720675ee28c +97c3b5f0d54c1fc45e79445c3ff30458959e406a069f5bbf7979d684195b4fa0406b87c1c008f4075bc9e602ed863152 +921e65d582ea9322ddfad1c855331c3cac81f53c700b96db5305a643c084eb6793094e07944bfd41dc02c3b3cf671530 +8f23ef1aca02a260a3b65d25b110f28d3bafca44727448c8f2d03c5e77eda620c1721b06681bd816ee6027664d76352a +946a89b132ec0795aea9ff9dde7b77e7feafffe6e4a2f093042a7e6c71cd6ab87ce0ca914a1b5fabad4e1f96a795f163 +a01e2de9db33df6511172123ad6f7c64074237471df646b32dd9aff8c15278e2723108e4facaedca97e9f49503f8c792 +99dcdcde45b2ea3f15279936feede5f7d3b63ca4972f335b0559c2fa6f9faabd8127aa892a36deb114357ca906553ed8 +a3f8af37bfcf66b04d1896a4bd5d343f4733d4c3305369ac7e75a08f20f2004c10c642d2c7577f4e5c4d1f2cd851ac3b +b7294d15a3d674a56099f97a1adc9e82c15e90832eaf1722df110fc2abc8634c51515e5ad8522015498a3753b1fa8c49 +b4f27f5062ba7a04ea0048b3025b5e3d5b5d319a9e80310c808a5fb4e8e77b38c10a0f3172cb805cadbcc8bc66d36ec7 +aefe5decee0ae2dc372cc6cf4217daf97c4c908d145f100f0daf1ccdfdf641c78432c2e473e7e4b77dcdf2d4c2bb05f0 +acc84af7648a535ffd218c0cc95c8f7b092418c548815f1bafc286b1fe14f6ccb51b2044db3bff864d0bb70e88604084 +84d8e3dac0df6a22beb03742e1d4af684f139f07e2ea0f7fb27fc2d7d4f1e89b5e89f71af32ff115ed5e6092133535f0 +8ada001e1a03a823c4c056f636e77adc0f9dc08689d28de0d99e0feecab5db13abf37b41ec268dbdb42c75419a046c68 +87dac6c798d1744dff81d8bc3e0e04f3c9bf260e811685ddb9a9a8d6eda73927439b344f9a818d2103fad633de5a4a17 +ad9929a7d8a7d5d5954e48281a87e5c84f67e19110d73296b9989a09c76767a57a8115629239ffb4d99dfdf9c52ef6d9 +81ac7cbeef8ec35a5c3b61cc887080c29e6cd3e08af37e45830d17400dbacfb374dd07bf370b979828c3875b2027d5c6 +97f92c9182953b7e10f7a1bbb6b5b5c40b8275eb5a6eec1e29874c4712814749aa8c409651380216e1ff01d7b8511041 +a09794d0bbe7db013045d3fd857c1544fe6231d21afa3495fa300371f6301a3a0f4b8ea175b281503dd06078ff371ae4 +839bb58d320aa08116dd387a57a2b9bd9efc89c4cdfd82d0e47a00cabe644631d09be5436bd485df3b61b75ddf81a3ef +b1cdaa344f783757e8b9c1f84421da3c5be4c69f019a8fd4c1aa5bf1a63e8970c99e35c22cf3b48a0e6738bc6ba7ce8d +92af68e3216c78998208fb24b5ba0e645d0d3f5e28222b805668d7e9cdd6c033d3b22fd6df4c2d745d7f910d133cd226 +87640a4ea4e605e2204e5232b29a6c1c31152d83547eef14122cb76a0da52b8653801af48455a3ed713b9dcfee7b1ef1 +8147e5bf0c8f4731155ca0517ef3fae5a32b4d5d2d98ed0007b23893d8dbb7f8a1199c50c1750c2fa7c9cebe594b1bb0 +a76b4473c63c3ab6103c729afd2482822e4150f3155af39983b0ff0766c71cb622455ce6304e23853661eaa322219d18 +b3e2f05ca551bc3adec0067e4034aaffd72e0b64ac18ae25452c996927976c6727966e26d213b032521889be2170800d +a8414cd14cb3be658e9e0004ce511ef7063439b1cbc3166a11de030613fde4b59caad4e91d426927863c55382afbf476 +b2f0f8ab99f4d0ea785ac84fdbc00b20217b1df59b30b51d9d209d489d53b69dd5d82cdacc16fd1dd15c3a4001595f50 +8b2025d5fd658c9bbed619f3e3f6ac8efe7aeff8aa9401bd66a7ceb0062c44b353608ca073f95be99204f0a913bb77eb +94a46bc5a87291b42024b2137e623c70115b9c6b196604106bfbfa20f3f56ac7779763f56b580190d3cb2f1c648cada1 +aca9355545118d0769cacf69c4b23d6d68d229cd8f68f1bc0c847c05569c5af6bbbd8c4dceb637b4a6b3b5c83841bf5e +b0731992cab87c7116406b283a84707a34838bfa3284b0f6082dfabeaf41c5ac2b0ddc1b420547a1b0955aee92de2dc0 +b671f77588c0f69f6830a5b28e7d07ed161b81fa9791bb3a24aae6638e3aa5e186df74978a82549c370c18ebee04d4f0 +b5621ed841780f3e6681d880a76cf519cdd20d35197b112eeaa686764d57b5dfa78ffe1a294b6bc76b6e3949cd2a2369 +afeba2524659d00caecf089645611553187a6ed7102050f6dd20f5a19bed08ac7065912d88371ee06242897d58d652a4 +b78bfb83d44ced14a20135804aba3f00128c3ce1f302e95567ce4097b0d973414153fb305b9f156882a5a0554bf25973 +98510aede95d26b1adf214053eae051ffaf24894e2fa37961a91d0ff5392dd09388196648d95b73e90bd88f2587cc4bf +b35c682d49c295946b9f120fbc47b95abd9ee86d294abb003a92139fb825b509209562575015856a270eb3eea86397a7 +b9641bf685571dd9c478dd2033a1f1b11cd3a662b26502c78595863b8e536a189674a9a85f7a253453ebfd1b99fbd841 +b2ad37036a59b1c9b8457972665720a6868422ed8157b6810a9c0783006103be34ab732d7aeb8629653edd18fd0f1717 +af0920cff05179a3896ea6ea322c39adf91ada5bc40fe3f6fb1b1b4e121e907c904bbaa8ca00468b3749f3da144d71f3 +8e269672818ef1e2f9e0c8aa65c84442fcd9151d74bb8e870cee8c0e3fe24526e1a5388b430cef47b67f79b4e4056bcc +aa29a16fe00ea3d143b1032b1dd26b8ce638f37f95c085c7e777e8e2784bd724bd5c38b1583c61a6ec7c451dd78fd3fb +87452b7435911cc5f513b0c81b15aa04972ecbe3d7bbd0a5d676c96a8a311301c0e07fac925c53a350b46fbd3d4d0fc1 +869a81c351096f47748e41566ae7b77a454b1cdfaa41d34a5742f80df38fbf5cbb08924b6fdff58e3b18f05c62bbbbb1 +8b7bc1b0486300981147a40a449ada9a41afc06d735cce8bf0fab3ee94ba2e2ea57b1397e3cd31bc295352beb8334ef7 +93e93fc41adb2df279d95654921b4c2edf0d293dab58d0afefb221f777349ef88d0985b3447e3b935954a81f1580a92c +970fa7cdca8324faf3e62348bb50d78f580b4f43f2e1c11bd8382d48d0074a3c55c6407203a0c9cb1c5f2163ba421ef4 +924983929e608d27e4a36d4ed919297869e3c64de51aca794d32d6e90aea546bf898d98ceca28a0b2187734821b78504 +8d395332529c703d943d68415d443332b5c1342ca9d9a59bfa8bd4ab63e93358c4b0dde6ce1f2e8ea9dc8f52ad7ebd95 +80200dda853e588256599e7f905add5d5ee7c74272780317694fbae39318ae9be05d5bcd7b20cf460069743f3d4ef240 +a287d51d6359c9ef7c7ac1b20e479ce7d0146dba5606397bd04b7a622cec642508d5b45d51b31de71f9763595b6ac88e +a320396c075175d6599225cf2e1de8c7cab549f6316c07feb0f6eaa21f06b2dd29ab14fbdf2af4543b4890ec0fd08a4d +b1e9fe230418d20368691058adcbbe30011bab3000422f0371015ff8bd09c60fb5fa85d18550d35b1c900977ca48f58b +9718fc26a51783b971744933f20490e9b5cd9162f86b84788c4c5217f5409e37b5a39d628b18e5b35a757acf67596321 +a0cf81fdb161f4f1b419c5e4caa36d4bdca2325f0cd25b119a30178016f171bd6fb88403e4e3aec026c4089f180d540e +8ab1e36bd04625ee794ef04c4dcb8e004d61aceb2b62438377f49ad95dcf025ba25eb799280004941e555bf7172af6fe +9257b9e3d14d37fc7efae49b0c68d36eaac546035f4a2654d566b3ce1b2c4564cbb03dc8ec66efceb768559a8a507a18 +945d1123b839637ab5154a1972c3c83a0ff34a3b1a3465de6ef0416b1950f649869a3ef88d7f1036648ee385265ce2df +81449639d708860fc0229c94f754f7262e8a3c7f67960ff12dfd15df95f57a9ffcee2013e81978b7703dd42bd5d0816f +a865481deaae5a690fd53892791e5fa729db283b75a525a11cdfee1ce17e8e7f0b449d25f20b3c1b43da128dbdf98a8b +98766812a65fcd25b853546e3bba618a3edc9fd61510e4f8ab60c038a7fa50d197abeec8776109df0f2119be9445ad00 +b1b8dd5379d903dc41d74e999b1ab693607a0d2905692f4fb96adf08f738e5d31f9d00df28ccb8b5856145ca552c3e3c +99d20be7b511bec78a8ed03c207aa4aa9097ba39d85e18f1b8d52f65431ab7e9a773c7b9ac3e8d8b25458bc91bd00703 +b1b7c3563fe8cb33c7d3e0b89d00bdd13e86452ff507c2e69db7b3af06f247f139155396e9b0278753310dc63940a10b +b3dc9c08451b1de7c9969b1e47574bffff50490f4a16c51e12390195d9e9c72f794790caf7b0a835d64e01fec995d3ac +aaaa4761a00022ede0809d7063d3532b7bfae90ff16f45e17a340ad4ebaa2fbac40728ccc5fbe36a67ab0e707566c5dc +8319a1903314eab01f5442d2aee6ae9c3f6edfda0d9a88b416d0f874d7d1d05d08bb482102f8ca70a4fa34836d0840c1 +932949a6e9edfec344932a74d4f81eec3667ece1e8b8ca840ce07ffd4b5d6d8f01657c764d64ac1b9190f876b136490e +904db1568128487e312fe629dd8bb920cecafd3bb9cad8b63e269ae0129f2f5c80cd82f0d81e7feca9835c3945a72d28 +a17280693d30dcd43c85de8f6b02d5f30cb9097274ad680cede1ef105c903615b4c40f3c6aaca478642de324972514e0 +8d5f76e093aee71d0cdeb017fdfcb13bd068039746de90690ce150a0bfdbe7ddc4d539df0f82c2d2890a40b191900594 +96fa1f2196a3883cdd73c66d28403cbbb58f6a939a3697ee0d308d8a076393cbb4be86255af986869230ee410c01bcfa +a8b74438dc5cabd70a91bf25601af915c4418d074327a9b01e0190c27d3922c89bb9b41e0b366e82e313edda8f21983d +ac9fdc1a9b2e3ff379eb2370979372e13c4177bf4574f1490fadf05a7073e6d61e703e2d8eed9ce984aba317d411e219 +a45a6c9b958169f2f8df70143e6ac3e2f6f969a4eed6fd9f1c620711bc2454739bb69f0094079464790c5429c0d8aedd +8901cbdd1009864386577842c1e3d37835fddf834064d9613b4559ea9aef3084204e1f863c4306f874141f4374f449ff +b6c582161691e3635536686825be9c4d7399d668a7675738417e0363e064dfd28acdbd8dbc9e34c1dab8a1990f1f0eba +89e89ddaf3cacc78428f3168549c161283ca8337345750667c98212717b21e7d994eae4e45bbddacc832a18df1d79276 +84be275627eed8e1a73c7af8a20cee1ef5cc568cfeea7ec323d7f91b44e9653e9aeed47c1896a8240b99dde545f0e1fa +a779a54ab4f40228f6e2539595fb8d509b70aab7c19e1928c1be69ec1dc19285c3898cf15e5f8b8bc725e13af177fe17 +92e2a49d2b9b36349d442283b17d46f8f9bf5932c34223015ce62d2f285e7363b2c12232be4a838b5b6cf08e694c094c +8b4e28c6f3f36caa2cfb82ba88066c830f8017bd35608b077143dff236f3181230166f5a5c02fa0e5272297331726aed +85fd77d46162ffac4b8adb25baff0eb0512a53a3d01638b3a376ea34702279ce21c8e7d8884308c03e00c9bcc1a9fd29 +aad5e46916ff1be29009b595d1d8fa160cc7aa01c7fbf3a68f445c87615790dcab1fcdbdceda533d182b6541f09f2f73 +948df7654726250dae393325addd3c0a20431c81f00470962190335ea4b6d9f7463d6f308cda46b92084c1f24390b1da +8f577474dea132676504376c5542b730b6604fe3d965eaa194659fd11c52233bd0b11ab62e198c0f442327ff1c00e501 +ae2f1001546db3e0c19700adad997cd9f765fe7a51a502cbcd9a2a07a3a5db79c8f603e05cf96d80b688cb6c9b6cd3ae +953b68e5d9561088dd20406ea7fb6894cba33868a38ace38fc30b5813140cb15dd6dd2171befae5b4df2e4a9658889d8 +86c52901655ff11419b084a04da8fc3596eae59d81d3461601c0baff59ba59e3d1dd0b7ce719e741a3e97c013e898579 +b9a72dd5eff73f9912a28b55de073568efb3eb0241a10b77a2bfd4f30c2aa4fbfe0c89eb345c9f07fb725660873cb515 +8e7353f5f2932e4ffd95811caf46c9bd1a53643c27eb41a4ebd211f230955cd71a8b27e17cfe8aa708d8514c0de67a66 +a096b8e66312a92fb10839ebe60189a8d1bd34dff55f7dfae85e4d2f53a1a4a88211c19fc84494f066358ddce82be131 +931c5cd82719d76596832b007969b5f75d65cffabb41b9dac7910300db677c1309abe77eeb9837a68c760bb72013b73a +8ba10f5118d778085122065b55dd1918fddb650cce7854d15a8f0da747da44d7b12d44fc29ad7dc38f174be803db74c6 +8c971deec679372a328587d91fd24ab91043e936ca709c333453d7afd43ee256d08c71cb89f0ab0e89ae119831df6d86 +a2ac28a58034fbd8fd518f409221bad0efec52670880f202e09c0530e2aabc2171ed95e99891790596ffad163d86c110 +b3354e3dfa8068aba4f3741152b9204baa4e342c1cc77e6dd1419cbaf8da1d118be605846b8609e997d6a62a11f3423a +a12ab65a213c9d95c24865fddc2dffe0cf9fc527dd6bcdacc1bd7271e79929a4ab3427a231f4f49d0530474e6cbc88f9 +90afd65b7e6973f8aafbe74da0f42441840d3c93bd69bc1bec8fa56824e7ca97ad1b427c8a85da7d588469bd4ccc50c3 +a09175940c59489bac3d3da3a4091270d9118948cbbdd57f2bcc63fbf45b8010651c801d3e58dccf42733ce1d6b446a3 +a843bbf286e3cecc1fe370ff1bcf5f1001bc2e95b34246625ff50d48ee62343e82fba2d25b8a4bd5f7b5ffe90920efa2 +a3c4d1003219157fdbee2707ce07afa6c2a64ae8e450182c307ed7f070024071f30b12c4b0032960ff913c74e73a9976 +b24af3f68d66f825d06fc3ff94fcccebe28b1a0d4ba29c48d3a3c953b9bf7ae6707f193fef25e2dcbd2b74e483c774f0 +b0f657f7723184ef7d7e4381143f1ac8020d8c6c6f2dcbebb0eaf9870d61a81f2d452596503311e46d1b38f625d4756b +b90091004fc8f6205c51bec68547ac82dba0f5525631e7632cf6efe54eecd9020729fbee6105d1b8012402d3b79c54aa +8e3fa187713c60eb0a416d6900a894cdf81e6b6b69dae0bb64f6287f3c3f030cfa85c665f7aace1eab4937f380b8f728 +879bf0784ccf6725c9cd1ea8c49fde31c91c605de1ea664a33c2ce24c277ee45d20b66309f98d989acb2ff3b77e13101 +af3f3a3ddc4e11abd627d5aef8adffa91c25df5f0c68b4d2b5d51e7d9af3395ba4f6f7ae2325a6672847e1ecc6cad628 +973e667289e796d3a40f072e6fea575a9b371a9997cf8961677f8dd934619ddc47c1a3efe91bae9ef95acb11a8fe6d09 +afa81c5606de82f46b93f4bb6db3fc0670f4e0d1091388b138a66b3827322d95a56168c951c30831d59eeadc227500bd +b83eff77db5b4c18574662942eb36f6261c59f655f8a9c3d3731412d0f257c8e80aacc995c4b2303058a1ba32522a434 +912e5ac9234b9445be8260393ff08e4859a7a385e800b74d1534eeb971f58f74cfb518dfdb89f8705d89fbf721439129 +ab27c8ece4a51d23e22c2e22efa43487c941139b37ea1182e96efb54ca4809d8245eae0ebe8ba94f0ed4457896fe11b1 +a6630585d104a745bc79dba266d9292bbdad346449c8ee8140a5e6e8a6194411df9cdbf3d3ef83468a536d4f052e9335 +8b8c128244da48e7fec641a882d0005a2d05c7138d86a293e6a0a97c76bf632b44767d0ce44663c975e7f9f9679e25e3 +87dbcaca67351a4e7d2297d7cdba4796d12f58857e7ee4abd0645563577ff33544a44cd84e50b3a3b420d6998de9b57c +b859ba43df259d7f8e7fac70bfd7aae546d57a5dc90e107b174a95bf7fd3cf00f740c4434848e69b2a7e6061f66c1ef1 +99d6e20978fefc40c6d310187eb2ad3a39296f189ee122ed64d74f81033c3069d44f7a9d3988a1df635b609603a17272 +99a5ddf3420cc0c92b21f71a805245608d4995ead447d8f73a670d26d33e26920d5f07bfe1f6230bd5f15978055b4253 +b936ac0944d3c5e4b494f48f158000abb37b80b5c763f77fe856398c664b0f1ddbcc0a9a2a672db9278f08b4bafbe2ec +b4af85fbf4040e35a686dd016adec037c99b47cc2e4dfccaf7870ee9e8c97bff30f3035992def2a9d4af323c0b3af8ae +a5ee32b8bd5f8fa9000da4da0bf00565659a43285393d37080b555d0166bde64d87317b2eab2d48a0e7b287caa989be2 +894d4ad58ecb1c9ebc4f5a97407082e56cb7358d7a881ba7da72321c5027498454f2c7fa2bd5f67a4b11d38c7f14344a +965be9eeaa0d450dacc1b1cc2fbf0d5d4b0dd188f2c89aaa9260e7307a2a1eb22db6092fccb662269e9a1abfc547cabb +805893c424aec206260c1c2d2509d2cb9e67ee528bd5179a8417a667aa216a3f318ed118b50d28da18e36c01f0805e3f +972d7040d4963b35260ef0cc37cd01746f1a2a87cedc0dc7b0ee7e838c9e4573784ea743f563b5267eb3905d4fa961ba +8c7156991d4c2e561888feaecf501f721b4174e7d14109e9deeac5a9d748301c07e11fb2b04b09799f0d34ff42cb77d1 +894722ac35af3d507e81d737d21e16c5ba04686f8f004aa75934aae5e17acd3e065b96e229eb011c2f34096f4c62048b +81237937c247c88e8e31e2c72412189fe59c1daf65c5513489d86cf29ee922c0bb08e5f7890f09f4ada7e5262083d266 +8cf62cda2fe0d9a6b42aa2a1c483f4ad26378c7cc2c2d1510a76df7560b07dba8528b33aaacb15f7f20b9d4c7c9f61f6 +aaf0921fb3e1920eee5d0acb59dcc268b42f4b435d60d25d30357edd7dd758d035919691bd15311d85489dfa2e5ee696 +92cec07be2247ef42002ebcaf65ec855611b8e893a5675796f2225f55412201b0bf9f4761924d0c8377b9f131e09e39f +8e514a62ac1e91773d99588415426c97ad63e917c10d762fe06ace5277a5c3bf3730e4b9e5d116f8493b9ab8687b70e3 +83932df2d923a5052468a3ea87f7b55c6a80ede3594046ee4fe233046570921822bc16555b92ba6aeabaef9b1dc0805a +a2b5bfb249de3472113fd3f35bfabf3c21d5609da62a27ea6aab5f309c9068d94bc58ba03efb4ec11be06306d59e60e8 +8106cf3ebe6f0507be8c6e8d137987315fe3689ecb75bb27980f36ba5efac504baccea0e7603549b6d126beccc278804 +a73ee70b6fe8c082443972102c453fc0e386852476cf22224fc0bfe554735c12f96037fbf10922795f4502c4f052b5f4 +932b27e175440169958504f3ed6400e7d6dcd5e716c19dcd0f15c56c04503ed133d5a993e111c016f141e32d68b29886 +96f7ce4595318e0b4a6b368f788ff82226aac676aed4ace343867f751de414453a9aaaabef6e6224ce5aedc3d5cf77c4 +a950c1e3bc9a14484997013d44d876374b939af437ae7c821c131fb886063ee9fe7214a25a0c7084f0b07b99412eff75 +a9dba3886ed6855303106a1bdd26010f294218684e1c178afcfea3f37a2f04fd01724a31d82de3449046617e3507a115 +87a2f776b32a6b550cf3ceeaf78db02819be74968d228b1d14e0d74a1cdf994bb500b7abef6619455e98d728701fac5c +8cd887b07e335edc0b27e6a660cebb64d210741395be431d79d570139687b056557159407459799a8197b6079644f666 +b81a61fce00588909c13a90c1caa150f15788786af443ff60ce654b57147601f7e70b95659e01f470334a220b547611b +8aebc51141544c5f3d3b99422250424b9800031a8fdfbf22c430907a3a446fecaa2392105d66d64b1c8e847240da4a6a +90db7dc12baa02f3f86d3edadf9434e2b9318d4f6f0eca08276b765dbb38d8eb0d08be2fe70adf2bf16ceda5db08d3ca +aa1839894152d548cc6ad963de20fb6fcc843bc9af2a2bf967c63626b8ad19e900894d6106265f38f3afccca317c22f0 +848e27b741496988a582515c0c8847b2bfc6a001259396cdeea1e1b1d2828ca3a626693a1bf4adf3a3d7f8b1fa3d75fe +a0aa11754d4ee136ac3ca609b17bcae77758763b2016544ca7921dddedd8aafcc7ad5f2b337c8bf53084eb8e43ea41fb +b8713b7aa1c112178195fdcc9b7024f46e6bc04c4e76c41abe620aa265287809200d98eaed6c9703fa97e81d6964f0ec +8605b5b33309e9ea6823542b85383c496794b8481c577497aaf99ba90496e794dce405be615bf92c7b6361460e6b82e3 +826fa34faa7f83e063a7bf172addfc07badabada59cfc6604fdf481d29085251c0a67a1355b2cbd374e2975934b84cb6 +b45d131082dc16fa53af010d43eefb79200dc23d2f3ee26af95ac6a5cebc49c84a9ed293e534ed16ff3ef9a4a25456ec +91bd6ce3c5396a7a0de489e49f0cdf6dce1cd2d0be7a410326423c3185bd1125ce1e610768be7f15f4e44b62f8834fc3 +903ffbe3d33fbf106c01c727dc3a385201a67ded70d4df623934882f69a3a96c909b027a124f3d70cb072b0046a149e8 +b405359db9d9ef4821a181b440ef2918c240595141d861d19a85867a5afa74d2972d22c988775eab441e734700bae4a3 +8abb756d027233c83751910a832b0ef4d28d100077f1c5d656720c94906f91d85dd0ea94b1cc0ed95b692efee14c786e +a78ee77ab476a41a3454160ba7ca4085d8b1f7057c63e76db8b07cf20afdeddd2250cd00771a6329133bb4ad48ccc20a +a41810271d8c37197aa9b3dfcefe3498e42f5978d3f3d59defff4676d6402d8575b40683834f184f143b6cfbfc859b3a +90c24a0750242660bcc6d487358a3cc015730538a0a8beb00ad5ac2ef33cb8ca8a62121e50bec8f3d2f43900f8e3134a +8b96c39695d864ef5796941754978a1fd612b369f6b77fe5ae6587beac936ee28190af8f0a3822b63060af35e49a5c8b +acde2548883d0e63c0fc257bb9dadd919aba60a985b69ebcfa1bca78acca42fc1322ec30bcc8e7c188818f858d04ad33 +895c86ae9ff8d95f2707d4838a3bc8ddb05b2611f0476f014b9c150d0e8332bc73285037a747426f09ac8179ba4e19fc +821761fe406e18bd86fa9ca9db99d382cd3b5c70c456f471fa3706d57763d147706304c75d54f51ce8f3115aa26e59d9 +a803a80e3e8f47dc3c59ea23eafdec017458eac648b360cd42cbd075e0dde6f6f450b48c7646fb1e178c04f82ae51a12 +91f40e1b6f588bd592829ce937996452c40be0fd6c43793c607866701ac6a8c7227e0891d45c6e7b1599382b0a3fbdbb +9408246d996a634a58689337f2526dfb3ba9ffef1d3ff91c32aa8cbbed900861ef25d6477308b67d76491edfcc70d65e +a492325a427f3df1c9c690c5b553daa8ac41f62f5ae55f425539222bacf959e2f67afabbba1732e120d3e7a6dcdf7049 +8fd0c3e15477cae228613a171b6e9ec29ddc63ef74854d99b638adeffe39f89f34346a42851e8445e855a9f2bbef0f57 +b735ed01fafa051004dbaad5e8c9e2faca8f6049ef9b590f256ea4d75b04594af12764ad4e6031735eae36f83179db93 +a7d35f43fca06c86b3425dcb68a87186834ba9740664fd657915771beca4cdc0fa2fc9b4c2e9d9bdad8ec33543ddfa59 +a1156e71e2db1b17df5da28747c88e091bd687bfee59d89096437ab4dc9a543fe5c5272d5023d72adbaab397a6fc94d1 +ab06a58bd81b33a411bade8d8c5232d38fadc2e38507159edea6e2e104b8ebd65ca02b05335118f691d44197b847a4dd +848b67a10f1e6ff8f5c228f226ef2ffeb67fb8f50925fc94cbb588d61896d9dc79726959e649898fd3354fe3ff7b7ee3 +aa933397361f32b388edcf832f0db172a38e756b34d5f7a4a050fa7325058006c22cede26ee27917e8f1b0f301792bd7 +89e49e7f02cfaae4a4b9c4180c9f6559d76e3a45774955859d4147970b1470dac37bdc9aedca1c32a20b045049161590 +adc1825d5ab94fc719f25d8c9773f4d518134ed88eb13ac33cb910b2be3523ef9ef88d9e4aea2418b806e20108317bf6 +96c4b444c8a023da644f3a343ebeeed19a8392d2ce175992461451c318a54273b76c3574d8f2dceda2947ddd34d1a674 +8aa7e97e87c8c5b29bbd51a6d30396a6be1fb82b716ef83800f2c36d5b85467ade7e0f59d2db82c310fa92a9265f0b03 +9146c32d99f02c3a6f764dcd9b4807f1585f528ac69dc4f84e4380f6fda4f9d5057c375671d51e7aca2b2b4140e83da0 +a10760a533d9bc57536bcaf65f080302086aa50225437efd64e176841544711828c23a15c49c0dd1f357d3f10722ab72 +acb0811777e17f7ae7aaba5f6fce81b759c067a4908730916195a2505c7450d0e6e2194c2ef0f241090597d58e70de47 +b24f161e9bcdbad56665e2490b5e4c7768390d4668cd69a04ed74739062dbe832636dd33cda89e9b0afa8c77e93fc641 +96b4d01106b831868a88ef016500ef2fa42d0ce87a37ca8ca4194a92a22c113edfe04eb2ca037329f3c1acc635148f55 +aebbb95fb4f7adcc8e7a217aeb73f9e037cbb873d08c1cd9d68c6c6834511adf1af8b44567fee84327599bdcb734dedb +a9bd8b17300532fb94d028659bcafbe7bbdf32f8945baf5db4cfaa1bac09e57c94cad0ba046b4514044b8fe81ea8596d +a5557cbda599857c512533e7cadcf27bf8444daa0602aa7499cafc1cf1cf21f9d16429915db7485f0e9a1b5046cf01c5 +8810307c40bc661c478a9747ebf2a30e5a5ead942d1ac0418db36ba5db0709c476f7d19685cabe6959e33ec1f3bff914 +8829b741f41f2c32e10b252d9338deb486dba2f23996a44cf1dd888ad967a589d51329be34d764139f372a1043f6c2e5 +a6b4728d18857c5fa082fa67bfb3b1d801e76b251b1e211a19c87cea5fe7ce757f943c85071f7a03a718388cd5690e95 +86da7f397e2533cd487f962ae58e87bea2cd50af70ef2df9ea0f29f70b5843cde664d30ec207ab84fc817f3851277e02 +8085776ef4ac6d42ab85b9d9135ecc6380720efd274f966544eeedf4684028197de76ecab919fa5414302597e1962bca +b05a065c733033d223ba13d16baa7a97bd8c8b8b1f0e59a9bdd36ee17e9922d48eb39bd180c168b122088a77f0bf321a +a89343fe44a93023dcc7ef71bd3bcb6786f68e1885ad260edc56a52445d34757f476395ba7ad35437f89bc573c7618dc +a114a9cd6105b524f3969c69faa2e09afe21753a93361a296f9e0e3b4e3e63726ddf2e6bfd3ddc046043e50bd44e539e +8a5611fec539cf681c05636bb580f29acc06f628bb012649ffa41ea6c1521194a5643d5dd843f09b6eb2c3bdb4d41acd +ade247c4011ec73ec90b72f35afa59a999e64ba5a7e664a4b30874fea53ba6a14a76a41b58a5f891a20d019e5f091bdb +905b5d96df388160ade1ffe210d0c6d1979081bc3de3b8d93ac0d677cc2fc2dc1ef6dcd49d3947055514292a3fa2932e +a9520796ca9fccd11b7524d866507f731f0f88976f0de04286e68d7cf6dbd192d0d269f0cd60fd3d34011a9fe9e144c2 +989a1edf4d7dae811eb57a865c8e64297837ffeeaae6ee6ac3af0f1044f023f1ca552bf00f1642491f0f0f20e820632e +879c8e63713f4935ed6e020559e140ea3073ced79d3096c152c430141272117b4fd9a9fc3eef012e81262df02ea14bd7 +95074738ac1540c0312274333acd1ecad9c5509fee883c4d9295fa8d8200f6e637c363de395f9fa612f05c0dc58fae88 +a770e4fc595269eb806b113ab3187ea75c8f96b57bf9fcfaf535f3eedc1d4d7e6285a20990575de0ff09f62d06ed0692 +81283e5dfb6423439ff513eca1cc316941d196df8da2d1069d2d0b63f5289e630af2fd4119bc0144c002d33313372dab +abd1b108e743887b78f698f2aba9d5492f87a22868d1351d705d93a1084fd45be67170c68a6e18b07f400d9a01cda8c2 +8509c3f67b92908cea8144f4e2a71631a66a61ac3547601c788907e52e380e5fe8ae4110aed95d13c67d3bcdd5b55a61 +8fa5a790ec5cce6d4114128c295390120869aac5490a82feebd3c37a167120df2e7fdfaf2a4050a7dfebf48fb093212f +944753e1ea7d8bc727d46a7702077dc01dc0c6574e8263a16579b57ee155ca5901f71bb347a01a9a922b329d3ff75135 +b46bc1fd4590b7a6275e20036d247c5909fc549c78e95b64ae7ed96e3b05bb044840f19f7650ebfe7008ba09fa83c3c9 +b1e47e4d88e59a06c465348c6cc4181d40f45b91e5e883966d370c26622c328415c6144aa2f61ddb88ec752482c550ca +8bd4f8e293e3f1815c7e67167618fb3b0ea76424bc0985908957cfcede36109378e41b4d89555b8c2541b4c447e00461 +a70589a867b2bfb63d0106083d58475d506637148549ed35c83f14e5c8de996e1b1f3447ecc80cf5cd134ef4db9d2fb6 +8048b80ba6131d07370162724127b0f7cb17fa7f71855e55e5a75bd0a9e4fd71b0d0ea2d16ec98858e458528df8d06b5 +97326cb94bae7530f4ec3235770c5a7ba042759e789d91c31fedbd979e3c0e6a2c69e2af3c1979c6fe0094274dbd53ce +a18e9c1d3eabd62af4e31a4b8e08494f4167fd4598c95d0123f39c46c53f9e93f76615900246e81a286c782ac37c569f +80309c59d4522b15aba617cd3c6238663e8b1c7ad84456346082c8f281140fc0edf9caa19de411c7e7fb809ca4fa3f4d +8e450c0990e2f65923f252311623038899eeff7b5c2da85b3a224e0ef7132588b291b782d53c477ecb70f34501466178 +87843f96f41484e254e754c681a65681b9ae5c96c292140368743df9e60f7e2ada58ca2bb95fa39abe064b2ebf21eeba +858e8d5bf2a1cf26d8af5036b28b831d450a446026f58a1734b696c18f1f41482796b91cab0e5b443dd2f0b9cffa52b4 +99627dd6bad8c05c5904cd23aa667d664da846496dbbb8452705c4ec01e1480e9c7295504a5a8529e4a0c842306b038d +b64b33256c18b2c886a837a0c0730fdfe73befb0e2796207c4dc592c5a33cd51f8c2ef47c584dd5773abf9ce9c1b0082 +944f6da2a1546f0bfc4d98c3e73c79e935e33d208b6be26b0b5f8df6d0e3b74a5bda649853b99281bd3a3ec799a7dd04 +a266d165435784d4e884640155e35b2a911b3f89e1e715986de419b166a36a341ba724877d80583fa3da566f6a828971 +adff2698409d0756e78c534032ee926560c13d578cb178d5073172d049ebbce32a92692f7e2033ec781b9b0d894ddce0 +a91933f110756c699c28bf9e24fd405bf432002a28c4349e0ca995528e56a5a2d101b8d78afa90a178ff1a9bf2ba515c +8e77839c0eb4da2d01e4053912cd823eddffbdc6b9c42199fba707ca6ab49fc324288b57be959fbfb11d59085d49324a +aa124517c76692036c737e987f27c2660514e12a953e63ff4bcb269dd18fc44dae95e282de8444bed09639ef6577af88 +b285deae99688f1bd80f338772472fa2b35e68887c7eb52c4ef30fc733812444c5cd110050275ad999d5a9b57f782911 +8877b0fa85b44ef31f50bdb70b879fa6df5eb1940e2b304fd0c8f08abb65f3118fa3d97ff93919038c1e452fb1160334 +8a89f3b50dcbca655024542ca7d93df17deff5c7d01c7da2bdb69e76b3e0b4490d85c800fb3debb4b0b4d20c9527f7ad +b7e5dbe36e985354ac2f4ab7730fea01b850af00767a6c4d8ee72e884d0fe539bb81f2e34638fcf5d07b7c8d605f4c06 +a85a1d78f6d4f9d5d83ec0f2a426708342d4e4a5d15625554e8452f6a843d9aa4db0c7e68caebdaf767c5b3a6a6b2124 +a518078a9dac63c5bf511b21ed8e50d1ccede27ebfe9d240937be813f5ee56aef93dc3bf7c08606be1e6172f13f352ce +91144eedebda4d1ad801654ef4ecd46683489b177ba1de7259f7dd8242c8c1700e15938e06c5d29aa69f4660564209a0 +a16c4657bc29d1d3271f507847b5a4f6401cee4ad35583ad6b7a68e6c2b9b462d77b5dd359fd88ea91ce93bb99130173 +85b855778f4b506880a2833b8468871c700440a87112fa6a83fd3ddb7e294b3a232d045dc37dfc7100b36f910d93c2ae +8d86bb149d31bfbf1fabcae1b8183d19087fd601c3826a72a95d2f9cedb8bb0203d1136a754aa2dd61f84b7f515acfa9 +acfe7264eee24e14e9f95251cbcfdd7e7f7112955a1972058444df3c2d2a1070627baefada3574ebd39600f7f2ea7595 +906bd14ecca20ac4ae44bff77cc94eb5a4ecc61eba130de9838e066e8766ed3b58705f32c650e1e222b3100691b3806b +8f2cbc7b8593c4be941dd01b80dc406fe9dfdf813ef87df911763f644f6309d659ea9e3830ff9155e21b195fc3c01c57 +a68eb15ed78fae0060c6d20852db78f31bebb59d4ddc3c5bdd9a38dbe4efa99141b311473033ff8f8ea23af219bc8125 +a95cb76c9d23fc478c7e8a73161f2ff409c1e28a2624c7d5e026e3cee9e488f22225a0c5907264545a73e83260e3a4ec +b76f90e55fa37c9e2732fd6eba890dd9f1958c1a3e990bd0ce26055e22fe422d6f0bcc57a8a9890585717f0479180905 +b80cc95f365fabd9602ec370ca67aa4fb1219a46e44adf039d63c432e786835bb6b80756b38f80d0864ecb80e4acb453 +b753c86c82d98a5b04e89de8d005f513f5ea5ea5cf281a561d881ed9ad9d9a4be5febb6438e0dba3d377a7509d839df0 +a664733f3b902fac4d1a65ea0d479bb2b54a4f0e2140ed258570da2e5907746e2ac173ace9120d8de4a5e29657ae6e05 +9479722da1a53446e2559bb0e70c4e5bf3f86c0ce478eede6f686db23be97fcd496f00a9e174ceb89ab27f80621f9b80 +b707fd21b75a8d244d8d578f3302d1b32bb2d09f2bd5247dff638d8b8b678c87d4feab83fe275c5553720a059d403836 +93214c16831c6e1d6e5a1266f09f435bbed5030c3c4c96794b38d4a70871782002e558d960778e4465b1ff296ffedad8 +8648f84e18eb63dad624e5fa0e7a28af2ee6d47c28f191be0918c412bf24b5460c04bf2b7a127c472914a0741843f78b +b67f61e75d6b773a6b58b847d87084b94f3cdac3daa7bef75c2238903a84250355a986b158ff96ba276ca13a6035fdd6 +ae9b094b7b5359ee4239d0858d3755a51aba19fce8ad82b0936cca48017523319c3309409ea6e9883a41bece2077e4d8 +8d1d8e1fba8cebd7a0e1effea785a35e16b1a10842f43e2b161d75add11eccf8f942d2ae91c20eef6c1a0c813731ea9a +b82bd387458e3603782d5e2dec32ae03890a3fc156d7138d953f98eff4200de27c224f626e3648e80cd3dfc684c4790f +a6dd02a89ad1c84e25e91176c26355e21a01b126c1df4d22546159dab9d502dbc69bc0d793a017c1456516e4aa5fa53f +a9ab74a5c5459b8500beb0ad13e9cfe2656e966dc9b4f3f98bec7588023b4ddebf74e4fc722d30423f639f4ee1b2587f +b03e5f33ab7ecec12cbc547038d3fa4f7ea0437e571891c39660c38d148212d191be29e04eb2dc001b674219b7a15a9c +925df4fc6e898ca55090ad1a8f756cc5014167a042affda5b24896eeb6aac408545134920586a8e1a2b997de9758b78a +98c8580fb56ed329fad9665bdf5b1676934ddfb701a339cc52c2c051e006f8202e1b2b0f5de01127c2cacf3b84deb384 +afc3765d374c60fac209abd976fe2c6f03ce5cc5c392f664bb8fac01be6d5a6e6251ac5fb54cfcd73e3b2db6af587cbb +8e7e98fb5a0b5b50d1a64a411f216c6738baaca97e06d1eba1c561e5c52809b9dab1da9f378b5f7d56a01af077e4f8cf +b724bf90309651afb2c5babaa62dc6eac2b8a565701520fe0508cee937f4f7b6f483fc164b15d4be4e29414ce5d3c7d4 +9665160e7bf73c94f956ecb8ba8c46fe43ae55c354ce36da40ccc7594beae21d48d9c34d1af15228c42d062a84353a0c +8600ab3aa86b408ee6e477c55572573ed8cfb23689bbdadf9fccb00161b921ec66427d9988763a7009b823fa79f8a187 +b0d8d19fd1022e7bc628d456b9bd1a2584dce504eb0bf0802bdb1abd7a069abbeeccdb97ce688f3f84a229342dbc1c33 +8f447d5e5a65bb4b717d6939cbd06485b1d9870fe43d12f2da93ca3bb636133a96e49f46d2658b6c59f0436d4eede857 +b94e327d408d8553a54e263f6daa5f150f9067364ded7406dcb5c32db3c2dffd81d466ee65378db78d1c90bc20b08ab3 +b58c02781b74ef6f57f9d0714a96161d6bfa04aa758473fb4d67cc02094cd0c0f29d0527c37679a62b98771420cf638b +8cfa0a687ea51561713e928271c43324b938aa11bb90f7ffaa0e4a779b3e98899f2af59364ce67b73a46a88748c76efa +95d6d39c814c5362df69116558d81ce6f1c65fb400fc62de037f670d85f23f392c1451d43341c59bc342bc31842c8582 +af888b384c52d9e04e4db6c4e507c2037eb5857e9bcc33acf84fc3a02d93cbde8cce32141fce9f5fec715b5f24d56356 +a7822bbc3c236fd58bd978f0fc15fe0b60933a0c953db6436a233441219418090ae0c07c490a6548e319029771cdaba7 +8c53729f750922e5eb461774be8851a3f40fe42eed170881cc8024d590bf0a161d861f5c967144d15cdcdc3dc6b5cf88 +a052a25a4aeab0d5bb79bc92a6ae14b5ad07d1baca73f4f6684ccecfc7ea69bc21eadeb9510452fdba116c0502dd698f +923946b83d37f60555dbac99f141f5a232728c6eb819a37e568c8c6e4d9e97a4229fb75d1de7e9d81f3356f69e6d36f1 +8cab82cf7e415b64a63bd272fe514d8b1fa03ba29852ec8ef04e9c73d02a2b0d12092a8937756fdec02d27c8080fb125 +b1123314852495e8d2789260e7b3c6f3e38cb068a47bdf54ed05f963258d8bcabaa36ccbea095ba008e07a2678ec85a7 +a685b779514961e2652155af805996ceb15fb45c7af89c5896f161cac18e07b78c9776047c95b196362c9ad5430bcb22 +b734dd88f6cc6329c1cb0316c08ade03369a11dc33191086c6a177cf24540c7ceee8199b7afa86c344d78d513f828e81 +b0bf492fb136ecdb602c37636ed4deef44560ab752c0af5080a79c9f76a1f954eba60a0bf6ba8bd7b8cac21848c29741 +a5c74682323e85ac20f912ab9c1d6e1b9246c4c829dca40c8a7d58ec07ea0ad3524be30623f351269552f49b65a1245c +837403b9cf830fb33ecc11a7c8433e07745973c36acdeb3fc9ea8f7d8d690d462e1250b7410f79f2f4180fe8f3962a4f +b03d64b944d49c83608f2c5b9c14070c025f7568c4c33d4eeb1da31d07f0bc5897e498b35b50d557ee129f0c3c68e254 +827272aab8bf757e2483156e00fbebe1093a58070dd3af9855bbf946c7abfb9c8a850a6a8acda8c620902f391f968b8f +84c4eb863a865282d321302d06b362f8bd11c2bb0090f90ebffedd3eb3e7af704cff00d39a6d48cbea4262942e95200b +b044eb91653dc55dce75c8d636308a5a0dae1298de4382d318e934140a21ca90e8a210e06fdf93aadbbeab1c2ef3904a +a8c08955a4378522e09a351ecb21b54025a90f2936b974068e80862803e7da2b5380c4b83b4b4aad0409df8d6c8cc0cb +a763a5fb32bd6cb7d7c6199041f429782deacac22b6a8467077fab68824dd69343ebca63a11004c637b9cb3129dbf493 +8c44c8afa9a623f05c2e2aba12e381abdb6753bb494da81f238452f24c758c0a0d517982f3999d2537b7279d381625ed +8613f47fda577cd3bda7c99b80cf4b2dd40699edfd3df78acb5e456dd41fd0773bc8da6c5e8cbf726a519b9fb7646ccc +b21a30d49d7e1c52068482b837a4475568d0923d38e813cea429c1000b5f79b8905b08f6db237e2eccf7ef3e29848162 +b9bdf4915f3fbb8d84cdfd0deedf2c9dc5b14f52bf299ef5dca2f816988e66322df078da2c54b934b69728fd3bef40b5 +993b45f389f55eba8e5ba1042d9a87242c383a066cbf19bc871b090abe04de9ff6c1438cb091875d21b8c10fac51db58 +a85a95d14633d52d499727f3939979a498c154fd7ebb444b08f637b32c1caf5cca5e933a2f5d94f26851ae162707b77d +b9874c7c4be1c88a9646e0c2f467cd76bc21765b5ab85d551305f5ec0b4419e39d90703d4ac1bb01feb3b160517e97b7 +ad6771177fc78812904c90594712956357de1533a07fec3082ba707f19c5866596d624efc3e11773b3100547d8f6c202 +a79f31921134f7197f79c43a4b5d5b86736a8d3ad5af1bdf4ad8789c2bfe1c905199c5e9f21e9f446247224f82b334f8 +a7f1b6c45321222a350a86543162c6e4e3d2a7c2dce41aeb94c42c02418f0892dbd70c31700245d78c4d125163b2cd5e +92abafe3ec9dbe55c193fb69042500067eb8f776e9bf0f1cb5ab8eb12e3d34986d1204136856fb115c12784c3b8dea6e +89bc761238a4d989006ca5af5303c910c584fe7e6f22aa9f65f0718a1bc171e452c43695e9f5a591725e870770c0eceb +aa0e44c2b006a27d35e8087779411ba2f9f1966a0f5646ff6871bcf63a8b1a4a7638751b94c9b9798ccd491c940bc53f +8736fe82862b8106e7fdab7b5a964d87ec291a74b8eb1cb5a6c046a648c1b686064ef3d52297043b8940bfe870c712f8 +956a3def1942f05144d8e9c3a82fd2d3610064b53b9eefde3d5594a8f705bf8f6849eb2c22181796beffeba43cc74ee4 +af27416d00cf97d5a1f4a1b6b51c010884cceca294f1151c3b684a3f83c3c8a3c30771df1166d833cbddf6c873c400c3 +aac3b8dca2336fc4ffc63c362df461289e4bbd3418c621bde6c581d3ecedf66e2b3e523d4db39e3d8ba014577bf85efd +94c3a8167f62074e5b28c2bffe4b6ce645439a9a0c5da3ca1b3ee956590a465d6f84a8a4dbbe9070ffbd6bbc734e4d62 +95e23ba6986d25ed4451215da05bd72c5491528271726d79a94c8cb16aef1c85b190d6c5b8a3a1191c7cafbab1dccf0c +953e3dadb5ad68f7de31ac09692948655d174fe16d88b96930ef35b331da7f1dbc4c17863cd07b4ec3135b5205891a27 +915d018f18b5d63cb3301c2bb5c6e85e75a88ba80663c964d06575b6bacbbe59139d030b218ce0998271d5b28c00b26d +8c871ba3dd138a908b2f7effeea0e71df096b23e0dd47cab10b9762b250abfd1221da94a8ee884e05bdf02271fb85a04 +96bad5c6ebc3080ecbe337409ae398bbeada651221c42a43ea3b7c08c21841ddbcfde544c9b8d4772de6f2ce92c0b963 +b5dbcd0b1c44c62108841558ec0a48df4b327a741e208c38b1c052321eda6e6ad01af71d49dfcdd445ab6fa6f0c34e6d +97dba59219b69e8aef2659d1f10bbea98d74aefff1f6451de3f41be39acbac0122b8ff58b02e90554469e88911ec3547 +b7e5682ec306478be4858296f5d03364a61f3260636a4242f984d351a02e8723378496beb30c4ca22def9c9ca193ea70 +9656a7a3df4d11df3d8bc35930dff70a5e78a488ca57bba20bb06814fc390fc6c7cb3f39b22134992aad196cced577de +8b269695aa63eb56d0324ba984279dc4c88e565321f1d61d553622bd4f1910d5eff68393d3a830eb924472bd478c2aa3 +9177bcd04b28c87bc0440268b4c8995c6790cad6039594971b2c177f0e197055231e776927d3fa30d98fb897a2ba401f +ae0e943973482001c4f214b9da82e1c27e38aa254d0555e016095c537c835d3702bc2de5c67b234ab151e02b3b7a43a6 +82fc719a7d38bf4787fe1888019ad89fbf29beb951d2fece8686d2beb9119d0c8c6d13bc598748c72c70d73d488140ca +b716dc66f87eb16b95df8066877353962d91bf98cf7346a7f27056c2a4956fb65e55cb512af278783887ab269e91cd76 +81d58cd8bc6657362d724b966321cd29a1b5cdc4601a49fa06e07e1ad13b05e9f387ca4f053ed42396c508cd065c5219 +b32ad0280df6651c27bb6ddbdc61d5eb8246722140a2e29c02b8b52127de57a970e1ded5c2a67f9491ae9667349f4c46 +b68a2eb64cc43f423be8985b1a068e3814b0d6217837fb8fbfd9c786db9cca91885c86899c50a1242040b53bf304ced9 +85887515d4e371eabb81194cbc070e0c422179e01dbda050b359bd5870449c7950e6b3947b7a4a0eb68199341cc89fc3 +ac5fff3c27dfbab78eb8aad37ac31cc747a82401ebf3644a4f4f5aa98d37b8bf3b3f4bd8a3428b32a127c25c9e19d239 +86fceaa6fbf8913553a9e1e907fcb1f1986d5e401a7eafd353beefd1899d571454fea96ff5b2a21254d9fb693ec94951 +b6778bb296d3f0de2531b67d36fdbfa21475be0ca48b9dfcc38f396c41b557823735ed0b583e525a2bae1fe06e04058c +898088babeb5b9866537d6489f7514524c118704abd66b54210dc40a1c1ddb0a1edf7fe0b6e0db53b836f1828ecf939e +b27854364b97274765f0fb8d1f80d3660d469785d1b68da05e2bd1e4b8cbbe04304804d4c8aabb44cf030eba6c496510 +8c55bbf3603dc11cb78b6395ccbc01e08afcef13611f7c52956b7a65ccf9c70551bff3ae274367200be9fc2d5cb26506 +947726f73cd6281cd448d94f21d3b91b96de7ad3ff039f9153befbb5f172db9f53cacb4f88c80a3db26e6a0f7a846eb0 +a7b733a05e97528812d71cecb4f638a90d51acf6b8fcbc054787d6deb7e2595b7b8d1cbe1aa09d78375b5e684a2019bc +8d5ca6d161341461544c533314fe0a6655cde032c2d96f0e4ea7e41098b8b39fa075d38e2d8c74e2d0308f250d6cf353 +b960e9f081393e2260b41f988935285586a26657a3d00b0692ea85420373b9f279b2f1bb2da2caae72dd2e314045f1bd +852a49c7388c10821b387c6d51617add97ba72485f52be95d347bac44c638c92e9c6a44ba0d32afc4d59178a497d944a +8412162a65147e1334ad5af512982b2b48eef565682b3f3e0bbe93fbc5e1103db9375a0c486bdb1b2c57e4cb3a8e7851 +8f52c3eb5d4f1e1e82cfd2b291d4910195427603b796f6c311deb35ef14a01a57a9e6cad39619ad108f3e86f384f9e1c +88d221088f2bf0103c53e44d0d96cd7881ec2b0a965db9121a47481771a8b796edd5ac23c4f9c208a171dab301f7d3bb +b49c3235e8b3617ed08a1891b9e2bcb33dbdacceb94ca96330555b7e00904fe6a749ced9312b8634f88bcb4e76f91cb1 +a85834215e32f284d6dfb0cbfd97f6cffc7b9d354e8f8126d54598bb42d7f858a2b914cf84fa664069632db2ff89a332 +aa3d48eb483c6120c27d9b3e3d0178c1c942632ff54b69f5b3cfbc6ad4ff5b2b9ce6eb771fd1eea8edf4a74c97027265 +a446cfded353cdd9487783b45846402b973cdeddf87e2bf10cf4661610fff35743cc25e8d3b5771dcedfb46b018a5d18 +80998377b3b393ef3073f1a655ad9d1e34980750e9a5cfb95f53a221b053ddb4d6985747217e9c920735b0c851d7551f +a35ac469790fac6b8b07b486f36d0c02421a5f74ea2f0a20ffc5da8b622ac45dfccabfb737efa6e1689b4bd908234536 +8fb1f6d8e9c463b16ac1d0f36e04544320d5a482dd6ffaec90ea0f02b4611aaca984828bf67f84dcc3506b69af0a00a1 +b6e818d61aea62c5ed39c0a22ccbb327178feebdabda0c9927aa1549d2c5bb0637785c4aed2a6d9a7b4989fa8634c64a +b4e7208d16018bf67caafe996d436113eac619732e3f529a6efb7e6f094d8ebea55b7be0e122be075770f5957b6ea6f0 +b691d38b552befac61f6d367287c38d01fec73b7f2efdb6713ca30314a37fb7c177eb111fe6bee657f2681014e07630a +9817587e418e6e7e8e97ae27067f17b55d25dfb14e98f63f530620c855d9a348c9fa571c8508e2741f902f8b9fdc0c5c +b6a6e5ca779ba140bf1d84cd5394ede8262f7479637ec0087a4b152243a1774ba916d8115ce759a3bebd1b409de5f2fc +b53d1c84ad766ff794bf497db3228efd2cc8ed5fc1958d89c1126efdff361610ecb45ea8e329b39035ab00a66c1259c7 +adc31333c507c8e0f4aa2934fcdca57fd9c786722a50dbd5404e129541f7ac182cc7373bf14e1e4e06e6cf94b31b90eb +a82b7fde4642d982d95cec669efee140ad797a2442c7f6620580527d163accbf021b893446cbb8038ea82fe25b15d029 +91f7acf8a8903979afa281646fdecb54aa4d2ed905748e156e92f0910de268fa29d67107d40863935d677d1de8039be2 +86fea71c6d43a7d93216a92fc24dfce8521fd4534a9558b33762d002081247867a6eff54cad7116023277fb4049403ad +8ae5369a7f9f4c91f3be44b98089efd9c97c08f5bb4cd8b3150c115ecd86288fa0865a046a489c782973a111eb93966e +b6fb9e829aa2c81c2d9eac72bb2fd7f3a08e0cd763532c2ce3287444d33cf48b3621f205e9603ec58525934b61a795a9 +83e35ca808d84e41fc92115e9f6e283e928c3a614e6dfc48fe78c33b6411262e7bfa731eadb1e1937bc03cff60032e1d +832fca5196c95098ad47b7d24ba2f9d042e1c73ad2273edd1c2ce36386796ccc26e8567847697f3fcc2a0536a2a2087a +8fdb7038bc8f462ab2b76bf7053362f9c030019f1b6105cf42219a4e620ecc961e3eacb16a8e581a562a97f1418b0128 +8d3a5a404b51b1ad8ce3b23970e0d5cc57b573922341008e3a952a1dd24a135e19e55b79d86a70cfd82e1c0e9630f874 +ba00c025c1c21c57c03cdfc0bfd094b35422281ff0a64b68b240617aa58c6b18800af5f2047d3ff9068bbe987d6c7980 +b468f0dd51964b3806b0aa04f3fe28a035e8f5567fc7d27555be33d02701a838b8dbfe1348b6422c4eac46d2c75c40c7 +8a73a18c97da9958903c38584b08d0e7e26993a5d9b068a5e0e1ee0d8a873942745cf795f94f7a3d3ba88790a9fbb2f6 +953a0a40c2c8102723736854d13b228698c14a02d85c8d2e61db1a768019ac305faf0d5db62ac976430ce087a5b20f1e +8998219da6b34f657cb8a621c890a52cb98c2bc0f26f26e2af666eebeadadc5e8bdf4f830a91d04aca8ce186190152c8 +8941e08c3155ad432236ed05460420a05dd0aaab30477493ffb364b14c00ea5b9183d30d3442b6321d2d20c36e4f5c7e +93f293ff7fb56cf5b03aee6f3ad2ad78444398ed5b3be56d7bf5b56b5aa5a2b980d13895dd57a5726d1b067c20cc55e2 +84a16f313e3f75e31824f58d19ab24c6611fb4c75140a7cadc3c166f68819547c1d0ff7f7d13f5d8ae30dff1d80e2aa4 +b6e3e830b15039d3e28b08f5465bb089eade11ee3bd80afe39e010df7db1fcf0c56d698717677a41ddbc91eeaf6544d3 +95e928e6dfff51351281568ae72da7d1edeb6e9fe01f30af0499e7505ba35a22b5bb919d41bb809a432dce83f3977663 +aabeeb60ca46f9b0232ff82ea7766dcab8cc5aaf9d23539f30174f9486640bc9312868ca493b59b314519fc399973e47 +b393a11e957d0bbb3ecf617b075b5906a3450b348e62916c04791b366f0a7397cccd6648440ac544bc30526e1f95aad8 +abb5bfc3964a6d246da60bd809d0ea6daf4f8222efdc12ceb6730194e85f413ee7eb03bae300abf7ea900dbbc3d08971 +96c1bd1d1d216a4bfbcf000c123f296c0d31e1684e9e3884c14df23bf528c8d599f82bb98fcea491716b617216a8e0be +92d1e570a56f1741fd9f3d9f488cc336421c6256c14a08d340a63720be49b0029e3780e3e193a2e22bf66cc652fa22a3 +8769c08551e3a730e46f8e5d0db9cf38e565a001dfb50db3c30fa7fa0e98b19438edc23c6e03c8c144581b720d7b33a4 +b850bd67fdf5d77d9288680b2f6b3bc0f210580447fb6c404eb01139a43fccb7ed20051999ae2323ea5a58de9676bfb4 +80285da7a0aaf72c4528a137182d89a4db22a446e6c4a488cf3411937f4e83f7b00ec7549b0b4417682e283f91225dfe +80520368a80b97d80feb09dbc6908096c40ff7120f415702c1614d7112b0b57f6729581c71f4a3ce794ac959a46494ff +9817b4c27a490b1cd5a6337e7bc7e8005fa075dd980c6bf075ddfa46cd51cc307ad1d9f24e613b762a20fc6c877eab41 +ad66bda1a3034ec5e420b78107896ecf36126ce3ef9705163db259072dfa438c6107717a33572272062b9f60cb89557c +876114ef078c2915288e29c9abe6b0ad6a756b5ee2930ba1b8a17257f3f0557602d1225e8aa41ce8606af71ada2a971b +aa3d6cde4c3b9d3d5d0c77a33e67f182a3e1cf89b0921423b2024236171955b34afc52b1f25b1dad9da9b001371771d7 +984d3e3a72412d290e3459339757af7520d1739c7af0cbcf659c71999328db44f407d92e8a69fea11625612c49eac927 +ae890d0faf5bd3280dcad20a5f90e23a206661be8842375fea2ab22aadc500849ffbc52fe743b376d46bb926cedae6a6 +b1f231f3f4d710c3fe80099faeb56dac67c1baf53b8fe67a9920fe4f90e52cb9a4bf19211249a6456613b28efe337f18 +8caa54b418ba609d16520af3dff2e96d5f2eeb162c065a1763beb926547b2cfb3ae41d738db2c5681a9bc8bc9e6b9a1a +932157ff56c5ac29cf6cf44f450c882b3acfbb9f43d12d118da3d6256bde4e6eb3183aea304ab6967f37baa718ffec99 +9360bed8fc5b6aac36aa69473040689bfc30411d20ffb7275ef39b9ff5789f9055d149383ce9f0f7709a1f9d683adbfe +98b5b33209068335da72782179d0c7aeeabe94b5560a19d72088fe8323e56db7ce65debe37a97536b6b8a0ca3b840b61 +89a385c11be40064160b030a1bb28c3921fc8078522618a238c7ea0f86f34717ed9af9b4e2e20f5128e5f7fc66ad841e +b615703cbc64b4192990cc7e4903b74aed6a0076ce113b59ef7719197ffa46fb29eb78ca56b49873487432d0625c0faa +90f0d77abae9d3ad73a218e5ccec505ad108ea098451461567ae8ef9661606ca8e78df53b5d628b20b7037bd24622330 +92e0e7cc4dfadc5fa0ee6da0c8de0493030db6e54ba0317f52f232a6708b732068b6077bd13a17eb7eb40b88368085b5 +a24dad20094985bfccc6df1343506ed3bf9dcbdf4b2085a87627a5d71f7568db067304e465f8f380c5c88e8a27291a01 +8629a45a10619354c84bdc2f6c42f540eab5a46f53f2ae11970433d7a2aef007897590bf31dfba1c921614c6d6fe1687 +84ac64040d4206f82b08c771f375da4b7d752e41d2aa0da20ce845f6bc1b880a855d3ee966bca19b8ec327b4b43e7f0e +9608e6050c25996c052509f43f24a85cdf184135f46eaac520a9a6e78e0d44a6cee50ebc054048c708aefde8cd6651c2 +a32032b0e0d7cc35e480c328f315327f9385adb102a708c9ba637878deb74582ae26bb6d6e5f8c9e3a839b0e0154b82a +b7e3c78d63acc6564a49e9f00b0a820b56d4f37a2374af1f7f1d016268011df9e7af0670ed2b0eee961f15aa948328dd +8b88bfdd353acc91ad0d308a43e5fb40da22c228f2fe093c6d6904d70f69c6203f56636ed898b05df51d33f1095ef609 +b1d7a430c51fc857af55047683fc18c453b013527196c5e1bf776819a3dffca802217e9249ae03f084e2ea03ad67fcc2 +80558e28a819ddb5e72e97c54be0f57c173ccf78038d360d190b7f1350a19577b8e3f43fa2f7bf113a228cd3b965b2e4 +b4b2ec44e746c00dfc5661ba2514930934fc805cdc29adc531c02d28ce3cc754414b0485d4ee593232cd1175f357ad66 +b57cee5d32835f76572330f61ccd25a203f0e4a7e5053d32965db283aad92f287645533e8e615137208383ec51b1fd99 +930256086b419a8a6581c52590d0dbd9f8a3564c79424198fca3866b786df2f6098a18c50dc4abd20853a7184b1ce15d +8e75fd01181cffcd618a983492390f486e8c889972a46c1f34a4e1b38f384e8e4efc7e3c18533aa2057da9f9623e2238 +b375d927dd988429f9e2764e5943916131092c394fce13b311baa10f34b023dd3571da02553176091a0738cc23771b9a +b9e28e4c0d0477518034d000e32464852e6951c8db6f64ccdb1d2566f5094716213fbf2fc0e29ac88d0e79f725e3c926 +963981e99392afbd2b8318d5a6b2b0cc69c7f2f2f13f4b38dddbfedb2b0eaf0584aecfcbda20a4c60789c15d77970a58 +a7804e1977aa77c263c7c001afa6cf568032dea940e350d6a58ce4614f1a91c13ae1c78bfea740c229dce2444556976a +8787204177da3cde6d35cd3497fa8774d244f9faa9f4bd91b636a613a32ce2ea0326378cf9c4cf475e73ef751b355c4b +895aeef46a07152a04ec812f1aa1fd431389fa0ef6c6e96a5b833e70ea14073bc9984757a8ee456dbec9788e74e6f0ca +8d17f0e5826783440d1f0ec868003510a4d9952bfe4a638e44a36d94482ac18ba70ef7ff773bdf7a3b62d714dcf0fcba +810d5e36b31310b2e054a666d3b3f7ed16dfcb1765532d87ca2a3920316f0187303c27dd113db145d47e8961062a6c03 +b4e2fb48ae04cf8580bb6a28095076c9b95e5f13122b917328f334d4ac8a8648ce442919e28319a40148987350ab5303 +b85549a313544fa1eb3ceb78473b7d3d717fc85b808de7b79db7dbd0af838ebb020622a7503f1cbacab688dddb648f84 +80665adee057088eae827a5fe904ec3ad77d8843cdce0322d535e0659b4abc74a4d7ddd8a94c27f2def5c34ac2c038ee +ad72fc19c2ce99b5b717e35528fe7d3ac8add340b02ebeb4889d9a94c32f312a0b45ea84d21c54f84cc40ee4958b72e1 +99d530c843dff89a47a5ee8c87303ab18f8a82b0d5b808fca050354b35da5c5a5594d55921c6362d6cc917d75bdc18dc +99c7286c293e1be21c5b2a669dfdfcd5aa587105d2886fc5a8eaf8984da4e907f7d7b8c2362d64a4f1621b077a2a08a0 +b4a39e1a9ed5d80c9563c3ca3fadf76f5478c63a98f4346a61b930c9c733e002f3ff02bc16abfdb53d776184cc3f87ba +9378ea71b941979404c92d01fb70b33fa68d085bf15d60eb1c9fc2b5fcdee6379f5583389a3660a756a50019a2f19a69 +b68e17344a2bc45b8e2e19466b86dc139afefbf9bad2e2e28276a725099ebac7f5763f3cb52002261e3abe45ef51eb1a +819e64dc412b2d194d693b9b3157c1070a226af35c629837df145ea12ad52fa8eabd65b025a63c1fb0726207a58cdde8 +a5e8ff8748419466ff6df5d389125f3d46aedacf44eaf12cbfe2f68d218c7d5ab6de4a8279d13aecc25f3b1d98230894 +91560d54a9715cfda9cf7133ae51c432d0bf7fcbaeb468004994e6838bfc5ddcfa30e4e780667d0c4c0376780b083017 +ae8adb3309cc89d79a55ff74f129bb311fe4f5351a8b87600a87e0c3ba60825f71fccf67eadcf7e4b243c619417540fd +8d92cc1a6baa7bfa96fbce9940e7187b3d142f1888bdcb09bb5c8abf63355e9fb942ac4b4819d9be0e0e822d3e8e2e08 +a6e8b79fdd90c34735bb8fbef02165ccbe55ea726dc203b15e7a015bf311c9cac56efd84d221cc55eaa710ee749dbdfe +a409b151de37bddf39ce5f8aa3def60ee91d6f03ddd533fce9bf7bdbeac618cc982c4f1ffbf6e302b8353d8f28f8c479 +b9693975ef82171b3b9fc318ca296e4fe6110b26cbdfd653418f7754563fa7b6e22d64f8025ee4243483fa321572bfe4 +a039ebe0d9ee4a03ade08e2104ffd7169975b224061924cca2aae71464d250851e9f5f6f6cb288b5bf15df9e252712a6 +b27834db422395bd330e53736a001341ce02c9b148c277dabac67dc422741bfa983c28d47c27e8214cd861f2bad8c6f6 +a2bafaf4e2daf629fd27d7d5ac09fb5efc930ff2ae610f37519808683aa583fe1c6f37207daf73de1d8a164f79a0c981 +b856cee1cfcf5e50db9af4ab0aed3db2f43c936eaea369b5bba65582f61f383c285efbda97b1c068c5d230cbe94f7722 +a61ab205554c0550fa267e46a3d454cd1b0a631646b3df140623ff1bfffaa118e9abe6b62814968cc2a506e9c03ea9a0 +8c78edcd106377b9cbdfa2abd5278724aed0d9e4ae5869b5d2b568fdabb7804c953bae96294fcc70ef3cd52ba2cbe4ed +8570869a9bbf6cc84966545a36586a60be4d694839f367b73dfc40b5f623fc4e246b39b9a3090694aa2e17e652d07fd1 +a905b82c4da8d866a894da72315a95dc98faa3c7b3d809aef18f3b2be4801e736a1b79a406179e8cac8f74d27e71ac52 +a8eb8679ff1a64908515f6720ff69434cb33d63aeb22d565fde506618908b1d37585e3bd4d044fd0838b55787af06b42 +af4d86b2fbd1684a657dffe4210321a71e6ae560c144d44668d1f324dc9630e98348c3d444622a689327c1a59cc169dd +80359c6eab16954559ab0e6a1fee9a0526c45d3cae1a371159a2e3aa9b893afdc3a785c9559a5fd9cd8cd774234bf819 +8d4e5ff81eb5d17bbe8ae6416538ca51a9427ce142b311f5cbb14febbbbb9c1ffc6489fd625b9266264c366c12a9d997 +92e181c66489c5fa063ba2a1a354b6fd3439b8b4365a8c90e42e169bfaa1fb5766bf3e0fe804399d18bc8fbcafb5c3b1 +a9ddf229360a095393885083716cb69c819b2d7cfb100e459c2e6beb999ff04446d1e4a0534832ae3b178cbe29f4f1d3 +8e085ef7d919302a1cc797857b75cff194bdbc1c5216434fa808c3dea0cf666f39d9b00f6d12b409693d7a9bd50a912c +916dc4dc89e5e6acf69e4485a09fc66968f9b292eac61a146df1b750aa3da2425a0743d492179f90a543a0d4cd72c980 +b9cbf17e32c43d7863150d4811b974882da338cf0ed1313765b431b89457021dd1e421eeaa52840ef00551bb630962dc +a6fb875786daec1a91484481787093d8d691dd07e15c9c0c6ae0404bf9dc26083ed15d03c6d3fe03e29f28e20da21269 +a870fcb54b9a029e8086de9b08da8782c64ad2cc2e7fdf955b913d294038bb8136193256b85267e75a4ca205808a76b4 +99883f057e09b88bf0e316f9814c091837fd5c26eeb16fec108c9fed4b7a2bd1c783dac0e4242b5a906621ab606c1e50 +85d89069ca3190577dab39bbec43c16bf6dbca439ad3eebd8f5e9f507d84c3c43e77fd6323224582566a3aa2c8018951 +9363ba219e0003f6e8a9d8937b9e1449e4b2c5cd57194563b758bea39deab88778e8f8e4f7816970a617fb077e1e1d42 +820622f25553c035326145c1d2d537dc9cfd064c2f5bdf6d4ec97814de5fe9a0fbd443345fa2ea0a9d40d81d3936aa56 +87e31110aaf447e70c3316459250e4f7f8c24420c97828f9eb33b22107542c5535bdb48b0e58682dd842edea2886ff08 +95bf80cac6f42029d843d1246588acb40a74802f9e94b2bf69b1833936767e701ef7b0e099e22ab9f20f8c0c4a794b6c +a46ecf612b2763d099b27fb814bd8fdbaee51d6b9ac277ad6f28350b843ce91d701371adfaaf4509400dc11628089b58 +8604decf299fb17e073969708be5befeb1090ab688ad9f3f97a0847a40ea9a11bbcfc7a91e8dc27bc67a155123f3bd02 +8eb765c8dc509061825f3688cb2d78b6fef90cf44db33783d256f09be284bc7282205279725b78882688a514247c4976 +b5c30b2244fa109d66b3a5270b178960fdec47d31e63db0b374b80d2b626409eb76d2e8d1ebf47ef96c166743032fc5e +aab01e76290a7e936989530221646160bf8f64e61e79282e980c8c5dcaaa805ff096efd01d075a2c75917a3f4bf15041 +b9d79671debd0b83d0c7c7c3e64c0fb1274300564b262771f839b49218501e7f38ef80cae1f7e5a3c34acdc74c89dab6 +92c0eaceadf036b3b9dfd2712013aba3dd7c30b7760f501f52141618265baa31840fe77850a7014dc528f71f8cf39ce6 +b3cdd098059980455dd5b1c04182df1bd12fa844a866f02a9f8a86aab95b59945baa9af99f687410bffc5b07153cb23c +b361b73a62f71256b7f6ea8e0f6615e14fc5a06ee98b928ab3c9dd3eef9d9d30070e9855c82b7facb639cacb3401e01f +b9c85fc0f25a3271cf28b1ca900078eaaa66cbab0a3e677606e898ac32781a2dfce4d9cbd07404599e2c3c02fa161c9d +ac5b4fdac2a0b2e6430d9fc72bde4249d72183b197fc7347bb1546ae6f544426686bbe0caec3ee973b6836da5e831c44 +b675aebf24b92e398e166f171a6df442b3f5919b6bee192f31675a5e8eeb77d34c6590a6f0c0857417e0f78cfb085db8 +a9bef942044d8d62e6a40169f7dc7b49e40cd0d77f8678dd7c7bae6f46c46786f9b1e319a3fa408f22a54fd2a4d70804 +a20d19cd917d5102ae9ca0cf532127d2b953aa3303310e8a8c4b3da025dded993a47e3a28e6b02acfadb6d65dc2d41a3 +a47fdb04059b83b2afb86a47b2368bbd7247c337a36d3333b6e5ef2cc9476a92c4907e4c58a845c9ef9b497621e0b714 +94a9e9ffc14b411e11a4ffa59878d59460263589003dc7b6915247c549f67feede279bf3645fdd92379022fb21e3caeb +b92e1177dd9ecdaf1370c71b14954219cf0851f309bc216d5907a4e2e84e0df3457018224150c142cc6bf86644bb4b73 +8bc57fadd68a265b7df9b42227a9c0968db7b1bb50dc12f7d755505779f1ff2c408672b3091e903366acc9ce15d19fb6 +b6b5efbe1ac4e1bd2e8447c45000d09397b772ca5496acc447b881022608a41c4f60388814607a01890190105bee7be3 +95f7c85fd614df968f8ccf8d086579c9e1cec4644ecf06da26e3511cb39635a7326b3cec47bd51cf5646f1c660425e9c +b81765fb319bcdc74b4d608383ccb4af7dd84413b23af637be12e2827a75f7e4bcd14441cf979ed9038ae366fbb6f022 +a120ea76cda8c6c50c97035078f6648afe6537809bdba26e7c9e61de8f3070d2347160f9d34010effbf2ec7e94f5749f +92c1b8631953b40d3cc77eee2c72a064b999c09a9b92c11d8fa7b4072966273901c9dba25f9f79f384d9f11a56f3fc7a +a4b00dc0ab67b2300abc9c516e34daf444d6497b066a90cfe3381ed2812304ed37b14f3b948990443dc6c1cf1bed460c +a9e9f7e13c9f031bc7b9e6f1417c7abcc38894fe7d3f54869ee277afd2efa3e6fb50757dd36c8c94d591e0abdea322cc +84f3e98f831792b5ad14bcfe62a4c9f296476c6087c4c1ec7767fc642fbca141ff6a3deeb8b4d4106a9cda5a9937eea0 +8eb1a7931bbea9a714226fd74b0100ab88355287d9b0a349c095e9b5809b98f237ffd706bce7d67a770da355fb9cec7b +9738ef8739e1742c1f26b51a1621be0b89d37406a370c531e236f635c7064c661818817bb3858908986aa687b28b21be +a9cf3ce8501b003ccaf57552a4c4ec31081e44526d3aa3791d3dc4a7e438a357c0956f93c500356186d8fd4588ffac5e +a7af6a219cca59225839a9de5b19263cb23d75557d448bc7d677b62591a2e068c45e5f4457cceb3e9efa01d0601fc18a +972a24ece5eda7692cbb6fb727f92740451bc1281835e2a02931b2b05824a16b01dbe5edd03a0ed5b441ff25a5cc0188 +b21d1ec7597ce95a42f759c9a8d79c8275d7e29047a22e08150f0f65014702f10b7edce8c03f6e7ab578ce8c3b0ec665 +a13a1c7df341bd689e1f8116b7afc149c1ef39161e778aa7903e3df2569356ad31834fa58ceb191485585ce5ef6835c3 +a57bdb08119dc3bc089b5b2b5383455c4de0c2fcdac2dcfa21c7ac5071a61635ff83eceb7412f53fab42d1a01991de32 +b2968748fa4a6921ee752d97aa225d289f599a7db7a222450e69706533573ded450380c87f8cdd4a8b8c8db1b42b5c97 +8718ec04e0d5f38e3034ecd2f13dfde840add500f43a5e13457a1c73db0d18138f938690c8c315b5bcbeb51e8b9a2781 +82094789e26c4a04f2f30bdb97b9aecca9b756cbd28d22ab3c8bed8afc5b2963340ddfc5a5f505e679bf058cbc5dcbb8 +a35b8a566dd6ab67eddc2467906bffc76c345d508e52e9e4bb407b4f2b2c5f39b31d5a4bf5022f87bf7181dc6be2fe41 +a8c93b1e893d4777c0e3a1b4bef3be90c215781501407c4011457fc3240e13524b4d2bea64a6d0a3efe3f3b0dae9b8ab +877095ad18b1e5870818f7a606127ba1736a0b55b0dbcd281ec307c84b08afc0c9117e3a880fe48bfc225fbf37671a97 +84405ee0421ed2db1add3593df8426a9c1fcc8063e875f5311a917febc193748678dd63171d0c21665fb68b6d786c378 +a52cdc8209c3c310bed15a5db260c4f4d4857f19c10e4c4a4cfe9dfc324dfac851421bb801509cf8147f65068d21603c +8f8a028a70dda7285b664722387666274db92230b09b0672f1ead0d778cee79aae60688c3dfd3a8ed1efdeda5784c9d4 +a0be42fecc86f245a45a8ed132d6efc4a0c4e404e1880d14601f5dce3f1c087d8480bad850d18b61629cf0d7b98e0ae0 +83d157445fc45cb963b063f11085746e93ab40ece64648d3d05e33e686770c035022c14fdf3024b32b321abf498689ad +8a72bbf5a732e2d4f02e05f311027c509f228aef3561fc5edac3ef4f93313845d3a9f43c69f42e36f508efcc64a20be0 +b9ca29b0ec8e41c6a02f54d8c16aebf377982488cbe2ed1753090f2db4f804f6269af03e015d647a82ef06ffaa8cba6c +b4df3858d61bbb5ded1cf0be22a79df65ae956e961fbb56c883e1881c4c21fe642e3f5a0c108a882e553ac59595e3241 +86457d8890ac8858d7bab180ef66851247c2bf5e52bf69a4051d1d015252c389684fcc30bb4b664d42fbf670574ab3a3 +86d5576ea6dfa06d9ebce4cd885450f270c88a283e1e0d29cab27851c14ed2f00355e167b52e1539f1218ad11d8f13dd +883ad1364dc2a92388bfafaa9bc943c55b2f813525831e817a6208c666829a40455dde494eba054b2495a95f7ce69e8a +8942371e6925231c2c603b5f5a882d8404d39f0c7c4232557c2610b21c2c07f145466da798ea78b7932da2b774aa3128 +a799eb71496783cc7faf12c9d9804bf6180699a004b2f07fc5cc36840f63ce7eee7dde9275819a9aa3f8d92dc0d47557 +8eb3fb5c769548ee38c7882f51b959c5d5a42b5935269ccf987d6ddbb25a206e80c6000bcc328af149e0727c0b7c02c0 +8f3910d64e421a8f2d8db4c7b352ba5b3fc519d5663973fea5962efe4364fb74448770df944ef37ffe0382648fb56946 +b41413e0c26ff124cf334dab0dc8e538293d8d519d11cc2d10895a96b2064ac60c7da39f08589b38726cffa4c3f0bfef +b46ef2eb10abae0f35fa4c9c7ee2665e8044b8d9f91988a241da40fd5bbc63166925582151941b400006e28bbc5ba22a +b8baa8b4c420bb572a3b6b85479b67d994c49a7ebfe1274687d946a0d0b36dfed7630cfb897350fa166f5e2eff8f9809 +964b46d359c687e0dcfbdab0c2797fc2bd1042af79b7418795b43d32ffca4de89358cee97b9b30401392ff54c7834f9f +8410d0203d382ebf07f200fd02c89b80676957b31d561b76563e4412bebce42ca7cafe795039f46baf5e701171360a85 +b1a8d5d473c1a912ed88ea5cfa37c2aea5c459967546d8f2f5177e04e0813b8d875b525a79c29cb3009c20e7e7292626 +afaab9a1637429251d075e0ba883380043eaf668e001f16d36737028fded6faa6eeed6b5bb340f710961cee1f8801c41 +aef17650003b5185d28d1e2306b2f304279da50925f2704a6a3a68312f29fe5c2f2939f14e08b0ba9dee06ea950ad001 +97bcc442f370804aa4c48c2f8318d6f3452da8389af9335e187482d2e2b83b9382e5c297dce1a0f02935e227b74e09a3 +8a67a27b199f0bcd02d52a3e32f9b76a486b830ec481a49a4e11807e98408b7052b48581b5dd9f0b3e93052ec45dfb68 +b113bf15f430923c9805a5df2709082ab92dcdf686431bbad8c5888ca71cc749290fa4d4388a955c6d6ee3a3b9bc3c53 +8629ca24440740ce86c212afed406026f4ea077e7aa369c4151b6fa57bca7f33f9d026900e5e6e681ae669fd2bd6c186 +933a528371dcecc1ec6ded66b1c7b516bd691b3b8f127c13f948bfbcda3f2c774c7e4a8fbee72139c152064232103bdf +8568ddd01f81a4df34e5fa69c7f4bb8c3c04274147498156aec2e3bd98ea3e57c8a23503925de8fa3de4184563a2b79e +8160874ec030f30fda8f55bcf62613994ff7ed831e4901c7560eac647182b4a9b43bfaff74b916602b9d6ae3bfcaf929 +ae71c48d48cf9459800cdf9f8e96bc22e2d4e37259e5c92a2b24fbe2c6ca42675e312288603c81762f6ceb15400bc4c9 +b05f39bb83fda73e0559db1fd4a71423938a87ad9f060d616d4f4a6c64bf99472a2cbfb95f88b9257c9630fc21a0b81f +80c8479a640ed7a39e67f2db5ad8dfd28979f5443e8e6c23da8087fc24134d4b9e7c94320ffa4154163270f621188c27 +9969ba20ee29c64cb3285a3433a7e56a0fe4ddc6f3d93e147f49fe021bed4a9315266ebb2fb0eb3036bb02001ae015e6 +a198c89fef2ab88e498703b9021becc940a80e32eb897563d65db57cc714eaa0e79092b09dd3a84cfab199250186edcc +8df14a3db8fe558a54d6120bad87405ba9415a92b08c498812c20416c291b09fed33d1e2fcf698eb14471f451e396089 +81e245ef2649b8a5c8d4b27188dd7e985ef6639090bdc03462c081396cf7fc86ed7d01bfe7e649d2b399255e842bdc21 +8659f622c7ab7b40061bcf7a10144b51ad3ab5348567195924f2944e8c4ce137a37f1ba328e4716c10806f3fb7271689 +a575d610fc8fe09334ca619ecdadf02d468ca71dd158a5a913252ca55ea8d8f9ce4548937c239b9cb8ab752a4d5af24a +94744549cd9f29d99f4c8c663997bdfa90e975b31f1086214245de9c87b0c32209f515a0de64d72d5ef49c09b0a031fa +80a8677862b056df59e350c967a27436c671b65d58854e100115bac9824ba177e94c2a1bfcaa191a071b9cefdbee3989 +91be9a5504ec99922440f92a43fe97ddce2f21b9d94cd3a94c085a89b70c903696cec203bbab6d0a70693ba4e558fb01 +8c5a0087bcd370734d12d9b3ab7bc19e9a336d4b49fc42825b2bfedcd73bb85eb47bf8bb8552b9097cc0790e8134d08c +933aa9e6bd86df5d043e0577a48e17eea3352e23befdbb7d7dcac33b5703d5ace230443ac0a40e23bf95da4cc2313478 +984b7ee4bd081ee06c484db6114c2ce0ba356988efb90f4c46ff85ed2865fb37f56a730166c29ef0ae3345a39cdeae7a +ae830f908ea60276c6c949fb8813e2386cf8d1df26dcf8206aa8c849e4467243e074471380ed433465dc8925c138ea4c +874c1df98d45b510b4f22feff46a7e8ed22cfc3fad2ac4094b53b9e6477c8dfc604976ca3cee16c07906dece471aa6c6 +a603eb60d4c0fb90fa000d2913689126849c0261e6a8649218270e22a994902965a4e7f8c9462447259495fe17296093 +a7c73d759a8ad5e3a64c6d050740d444e8d6b6c9ade6fb31cb660fa93dc4a79091230baccb51c888da05c28cb26f6f3f +a4411b79b6a85c79ea173bd9c23d49d19e736475f3d7d53213c5349ebb94a266d510d12ba52b2ac7a62deaaaec7339b8 +943b84f8bbcee53b06266b5c4cd24d649d972593837fe82b0bf5d5e1bbc1a2bf148e1426c366d7c39ab566b10224cadc +8300012096a8b4cefecc080054bf3ceb0918162ba263c6848860423407796b5eb517170c0bad8e4905ac69a383055a21 +8244a1e3ad41908c6f037e2f8db052e81f281646141334829f36c707f307448b9ab79a7f382a1e8d86f877c90b59271c +8eca1b74687802ecc36a5d39e4516a9dee3de61a2047252d9ed737b49e0090c386e9d792ac004c96337681c7f29a16ad +b70fa47535f0524835039a20036c61e77f66146ad79d3d339214d8744742db41ceeb577c829d000011aeafbb12e09579 +84b3abbce48689f3adbb99889c7fd1f3e15ab455d477e34f5151c5c1c358ed77a5b6a581879f7e0f1f34106e0792e547 +ab45ecb58c0ef0dbce3d16afc6ac281e0d90ec48741ea96a141152647e98fcc87f3a3ff07ba81f3179118453ce123156 +90d231a145ba36a59087e259bbfc019fa369201fcfeaa4347d5fd0a22cd8a716e5a797f3cc357f2779edb08f3b666169 +a4f6074d23c6c97e00130bc05f25213ca4fa76c69ca1ace9dece904a2bdd9d987661f5d55023b50028c444af47ff7a08 +933af884939ad0241f3f1f8e8be65f91d77ac0fb234e1134d92713b7cfb927f1933f164aec39177daa13b39c1370fac8 +80d1db6933ce72091332ae47dc691acb2a9038f1239327b26d08ea9d40aa8f2e44410bbda64f2842a398cbe8f74f770f +a7a08605be2241ccc00151b00b3196d9c0717c4150909a2e9cd05538781231762b6cc6994bebbd4cddae7164d048e7b2 +96db0d839765a8fdbbac03430fa800519e11e06c9b402039e9ae8b6503840c7ecac44123df37e3d220ac03e77612f4e4 +96d70f8e9acd5a3151a8a9100ad94f16c289a31d61df681c23b17f21749c9062622d0a90f6d12c52397b609c6e997f76 +8cf8e22273f7459396ff674749ab7e24c94fe8ab36d45d8235e83be98d556f2b8668ba3a4ec1cb98fac3c0925335c295 +97b7e796a822262abc1a1f5a54cb72a1ea12c6c5824ac34cd1310be02d858a3c3aa56a80f340439b60d100e59c25097d +a48208328b08769737aa1a30482563a4a052aea736539eceab148fa6653a80cb6a80542e8b453f1f92a33d0480c20961 +b612184941413fd6c85ff6aa517b58303b9938958aa85a85911e53ed308778624d77eadb27ccf970573e25d3dfd83df7 +b3717068011648c7d03bbd1e2fc9521a86d2c3ae69113d732c2468880a3b932ebec93596957026477b02842ed71a331b +a0ad363e1352dcf035b03830fef4e27d5fd6481d29d5e8c9d51e851e3862d63cdcbaf8e330d61c1b90886921dac2c6fd +8db409fdacfa4bfdaf01cc87c8e97b53ca3a6e3a526d794eaad1c2023f3df4b888f1bf19fee9a990fe6d5c7c3063f30c +b34d6975310ab15938b75ef15020a165fc849949065d32d912554b51ffa1d3f428a6d1a396cb9329367670391de33842 +9117285e9e6762853fc074b8a92b3923864de2c88c13cea7bab574aaf8cdd324843455d2c3f83c00f91f27c7ecc5592a +b4b2e8f190ea0b60819894710c866bf8578dd1b231ae701d430797cc7ede6e216e8ca6a304f3af9484061563645bf2ab +8c493c6853ab135d96a464815dd06cad8b3e8b163849cdefc23d1f20211685753b3d3e147be43e61e92e35d35a0a0697 +9864d7880f778c42d33cf102c425e380d999d55a975a29c2774cad920dfddb80087a446c4f32ed9a6ab5f22ec6f82af0 +90f67fe26f11ca13e0c72b2c2798c0d0569ed6bc4ce5bbaf517c096e7296d5dd5685a25012f6c6d579af5b4f5d400b37 +a228872348966f26e28a962af32e8fa7388d04bc07cfc0224a12be10757ac7ab16a3387c0b8318fcb0c67384b0e8c1a4 +a9d9d64bba3c03b51acf70aeb746a2712ddafe3b3667ae3c25622df377c2b5504e7ab598263bec835ab972283c9a168b +932128971c9d333f32939a1b46c4f7cf7e9d8417bd08dc5bd4573ccbd6ec5b460ac8880fb7f142f7ef8a40eef76d0c6d +964115e7838f2f197d6f09c06fbb2301d6e27c0ecdf208350cf3b36c748436dac50f47f9f9ac651c09ab7ad7221c7e43 +a5941f619e5f55a9cf6e7f1499b1f1bcddcc7cf5e274efedaaad73a75bc71b1fc5c29cd903f6c69dc9a366a6933ca9d1 +a154bf5eaec096029e5fe7c8bf6c695ae51ace356bb1ad234747776c7e1b406dee2d58864c3f4af84ed69f310974125e +b504e6209d48b0338ab1e4bdab663bac343bb6e0433466b70e49dc4464c1ec05f4a98111fd4450393607510ae467c915 +813411918ea79bdde295393284dc378b9bdc6cfcb34678b9733ea8c041ac9a32c1e7906e814887469f2c1e39287e80f8 +8be0369f94e4d72c561e6edb891755368660208853988647c55a8eed60275f2dd6ee27db976de6ecf54ac5c66aaf0ae6 +a7e2701e55b1e7ea9294994c8ad1c080db06a6fc8710cd0c9f804195dce2a97661c566089c80652f27b39018f774f85e +956b537703133b6ddf620d873eac67af058805a8cc4beb70f9c16c6787bf3cc9765e430d57a84a4c3c9fbdd11a007257 +835ae5b3bb3ee5e52e048626e3ddaa49e28a65cb94b7ecdc2e272ff603b7058f1f90b4c75b4b9558f23851f1a5547a35 +85d67c371d1bf6dc72cca7887fa7c886ce988b5d77dc176d767be3205e80f6af2204d6530f7060b1f65d360a0eaeff30 +a84a6647a10fcef8353769ef5f55a701c53870054691a6e9d7e748cbe417b3b41dbb881bae67adc12cb6596c0d8be376 +87ffe271fc0964cb225551c7a61008d8bcb8b3d3942970dbcc2b9f4f9045a767971880368ea254e2038a3a0b94ecf236 +964bb721c51d43ee7dd67c1a2b7dd2cc672ce8fad78c22dcddb43e6aab48d9a4a7dc595d702aa54a6fb0ffabf01f2780 +a89b3f84bb7dcbe3741749776f5b78a269f6b1bebb8e95d3cc80b834fd2177c6be058d16cacfd0d5e1e35e85cde8b811 +b4314538e003a1587b5592ff07355ea03239f17e75c49d51f32babe8e048b90b046a73357bcb9ce382d3e8fbe2f8e68b +86daf4bf201ae5537b5d4f4d734ed2934b9cf74de30513e3280402078f1787871b6973aa60f75858bdf696f19935a0e2 +b1adf5d4f83f089dc4f5dae9dbd215322fa98c964e2eaa409bf8ca3fa5c627880a014ed209492c3894b3df1c117236c4 +b508d52382c5bac5749bc8c89f70c650bb2ed3ef9dc99619468c387c1b6c9ff530a906dfa393f78f34c4f2f31478508a +a8349a5865cb1f191bebb845dfbc25c747681d769dbffd40d8cedf9c9a62fa2cbc14b64bb6121120dab4e24bef8e6b37 +af0500d4af99c83db8890a25f0be1de267a382ec5e9835e2f3503e1bac9412acf9ff83a7b9385708ef8187a38a37bc77 +b76d57a1c1f85b8a8e1722a47057b4c572800957a6b48882d1fc21309c2e45f648a8db0fcff760d1dbc7732cf37c009b +b93c996cec0d3714667b5a5a5f7c05a7dc00bbc9f95ac8e310626b9e41ae4cc5707fac3e5bd86e1e1f2f6d9627b0da94 +93216fdb864217b4c761090a0921cf8d42649ab7c4da1e009ec5450432564cb5a06cb6e8678579202d3985bd9e941cef +8b8be41105186a339987ae3a5f075fbc91f34b9984d222dfed0f0f85d2f684b56a56ab5dc812a411570491743d6c8b18 +959b72782a6b2469e77fe4d492674cc51db148119b0671bd5d1765715f49fa8a87e907646671161586e84979ef16d631 +86b7fc72fb7e7904ea71d5e66ba0d5d898ace7850985c8cc4a1c4902c5bf94351d23ce62eed45e24321fb02adfa49fc8 +a2f244e7c9aa272cb0d067d81d25e5a3045b80b5a520b49fd5996ece267a7f1bea42e53147bbf153d9af215ea605fc9e +81aa2efa5520eebc894ce909ba5ce3250f2d96baa5f4f186a0637a1eea0080dd3a96c2f9fadf92262c1c5566ddb79bab +b607dd110cfe510d087bcff9a18480ba2912662256d0ab7b1d8120b22db4ad036b2266f46152754664c4e08d0fc583f6 +8f588d5f4837e41312744caac5eee9ddc3ad7085871041694f0b5813edf83dc13af7970f7c9b6d234a886e07fa676a04 +924921b903207783b31016cbec4e6c99e70f5244e775755c90d03a8b769738be3ba61577aca70f706a9c2b80040c9485 +ae0a42a222f1a71cd0d3c69ffb2f04c13e1940cce8efabe032629f650be3ceed6abb79651dbb81cb39a33286eb517639 +a07d7d76460f31f5f0e32e40a5ea908d9d2aebf111ac4fadee67ef6540b916733c35a777dcdc05f6417726ca1f2d57dd +88d7f8a31f8c99794291847d28745e5d0b5d3b9684ca4170b686ffbb5bb521a3ef6746c3c8db22e4250a0cdff7939d96 +849573071fd98c020dc9a8622a9eff221cb9f889bde259e7127a8886b73bef7ad430b87750915658918dcfb6b7b4d8d3 +b12d59f732fa47fad175d6263734da8db89230fd340a46ad1cdee51e577041a5c80bf24cd195593e637daf1a66ef5a98 +abbcfb8a4a6d5e269ee1ac5e277df84416c73ca55ec88317f73608201af25af0cb65b943c54684a5651df3a26e3daca2 +ab157f589bdbaf067a6a7ba7513df0492933855d39f3a081196cf2352e0ddc0162d476c433320366e3df601e0556278d +a86c0619b92e5ae4f7daa876a2abc5ba189156afc2fa05eef464dfa342ba37fc670d0dc308ad3822fcb461ab001bac30 +a3f292946476cfe8d5e544a5325439a00e0165a5f9bf3bb6a53f477baeac7697cc0377745536681aa116f326ce911390 +8aecbbfd442a6a0f01c1c09db5d9d50213eb6f1ff6fab674cde3da06a4edff3ed317e804f78300c22ef70c336123e05d +834ed4b58211fcd647d7bf7c0a3ba9085184c5c856b085e8a0fcd5215c661ef43d36f3f0f6329a9f1370501b4e73b6e4 +a114ea5ad2b402a0de6105e5730907f2f1e458d28ae35144cf49836e0ad21325fe3e755cfb67984ae0a32e65402aad1e +a005f12bed97d71cee288b59afe9affb4d256888727343944a99913980df2c963fe02f218e6ea992f88db693a4498066 +a010f286ab06b966e3b91ff8f1bdbe2fe9ab41a27bc392d5787aa02a46e5080e58c62c7d907818caae9f6a8b8123e381 +857bd6df2ddef04dbc7c4f923e0b1696d3016c8bfed07fdfa28a3a3bd62d89b0f9df49aae81cbb6883d5e7b4fadae280 +b3927030da445bc4756ac7230a5d87412a4f7510581fb422212ce2e8cf49689aca7ba71678743af06d4de4914c5aa4a0 +b86403182c98fcce558d995f86752af316b3b2d53ba32075f71c7da2596747b7284c34a1a87de604fcc71e7e117a8add +98dd19b5527733041689b2a4568edaf6aa0fe1a3dd800c290cda157b171e053648a5772c5d3d4c80e5a795bc49adf12e +88a3c227bb7c9bff383f9ad3f7762245939a718ab85ae6e5e13180b12bf724d42054d3852b421c1cd1b3670baddecb63 +b3cfd9ad66b52bbe57b5fff0fad723434d23761409b92c4893124a574acc1e6b1e14b4ec507661551cbbe05e16db362e +923e1bb482cf421dd77801f9780f49c3672b88508a389b94015fd907888dc647ee9ea8ec8d97131d235d066daf1f42b7 +8d5e16240f04f92aa948181d421006bdbc7b215648fb6554193224d00cf337ebbb958f7548cf01b4d828acffb9fbc452 +8b2b8f18ad0559746f6cda3acca294a1467fb1a3bc6b6371bc3a61a3bfe59418934fa8706f78b56005d85d9cb7f90454 +a9316e2a94d6e31426d2ae7312878ba6baaac40f43e2b8a2fa3ab5a774c6918551554b2dbb23dc82f70ba3e0f60b5b0d +9593116d92cf06b8cd6905a2ce569ee6e69a506c897911f43ae80fc66c4914da209fc9347962034eebbc6e3e0fe59517 +887d89d2b2d3c82b30e8f0acf15f0335532bd598b1861755498610cb2dd41ff5376b2a0bb757cb477add0ce8cfe7a9fc +b514cfe17875ecb790ad055271cc240ea4bda39b6cfa6a212908849c0875cb10c3a07826550b24c4b94ea68c6bb9e614 +a563d5187966d1257d2ed71d53c945308f709bcc98e3b13a2a07a1933dc17bcb34b30796bd68c156d91811fbd49da2cb +a7195ccc53b58e65d1088868aeeb9ee208103e8197ad4c317235bb2d0ad3dc56cb7d9a7186416e0b23c226078095d44c +a838e7a368e75b73b5c50fbfedde3481d82c977c3d5a95892ac1b1a3ea6234b3344ad9d9544b5a532ccdef166e861011 +9468ed6942e6b117d76d12d3a36138f5e5fb46e3b87cf6bb830c9b67d73e8176a1511780f55570f52d8cdb51dcf38e8c +8d2fc1899bc3483a77298de0e033085b195caf0e91c8be209fd4f27b60029cbe1f9a801fbd0458b4a686609762108560 +8f4e44f8ca752a56aa96f3602e9234ad905ad9582111daf96a8c4d6f203bf3948f7ce467c555360ad58376ee8effd2ba +8fb88640b656e8f1c7c966c729eb2ba5ccf780c49873f8b873c6971840db7d986bdf1332ba80f8a0bb4b4ee7401468fa +b72aa3235868186913fb5f1d324e748cd3ce1a17d3d6e6ea7639a5076430fe0b08841c95feb19bb94181fe59c483a9eb +b8b102690ebb94fc4148742e7e3fd00f807b745b02cbe92cd92992c9143b6db7bb23a70da64a8b2233e4a6e572fc2054 +8c9ae291f6cd744e2c6afe0719a7fc3e18d79307f781921fb848a0bf222e233879c1eca8236b4b1be217f9440859b6ce +a658ede47e14b3aad789e07f5374402f60e9cacb56b1b57a7c6044ca2418b82c98874e5c8c461898ebd69e38fecd5770 +89c0cb423580e333923eb66bda690f5aca6ec6cba2f92850e54afd882ba608465a7dbb5aa077cd0ca65d9d00909348ab +aed8e28d98d5508bd3818804cf20d296fe050b023db2ed32306f19a7a3f51c7aaafed9d0847a3d2cd5ba5b4dabbc5401 +96a0fcd6235f87568d24fb57269a94402c23d4aa5602572ad361f3f915a5f01be4e6945d576d51be0d37c24b8b0f3d72 +935d0c69edd5dfa8ed07c49661b3e725b50588f814eb38ea31bcc1d36b262fae40d038a90feff42329930f8310348a50 +900518288aa8ea824c7042f76710f2ea358c8bb7657f518a6e13de9123be891fa847c61569035df64605a459dad2ecc8 +947d743a570e84831b4fb5e786024bd752630429d0673bf12028eb4642beb452e133214aff1cfa578a8856c5ebcb1758 +a787266f34d48c13a01b44e02f34a0369c36f7ec0aae3ec92d27a5f4a15b3f7be9b30b8d9dd1217d4eeedff5fd71b2e5 +a24b797214707ccc9e7a7153e94521900c01a1acd7359d4c74b343bfa11ea2cdf96f149802f4669312cd58d5ab159c93 +97f5ee9c743b6845f15c7f0951221468b40e1edaef06328653a0882793f91e8146c26ac76dd613038c5fdcf5448e2948 +80abd843693aed1949b4ea93e0188e281334163a1de150c080e56ca1f655c53eb4e5d65a67bc3fc546ed4445a3c71d00 +908e499eb3d44836808dacff2f6815f883aeced9460913cf8f2fbbb8fe8f5428c6fc9875f60b9996445a032fd514c70f +ae1828ef674730066dc83da8d4dd5fa76fc6eb6fa2f9d91e3a6d03a9e61d7c3a74619f4483fe14cddf31941e5f65420a +a9f4dbe658cd213d77642e4d11385a8f432245b098fccd23587d7b168dbeebe1cca4f37ee8d1725adb0d60af85f8c12f +93e20ee8a314b7772b2439be9d15d0bf30cd612719b64aa2b4c3db48e6df46cea0a22db08ca65a36299a48d547e826a7 +a8746a3e24b08dffa57ae78e53825a9ddbbe12af6e675269d48bff4720babdc24f907fde5f1880a6b31c5d5a51fbb00e +b5e94dfab3c2f5d3aea74a098546aa6a465aa1e3f5989377d0759d1899babf543ad688bb84811d3e891c8713c45886c5 +a3929bada828bd0a72cda8417b0d057ecb2ddd8454086de235540a756e8032f2f47f52001eb1d7b1355339a128f0a53b +b684231711a1612866af1f0b7a9a185a3f8a9dac8bde75c101f3a1022947ceddc472beb95db9d9d42d9f6ccef315edbc +af7809309edbb8eb61ef9e4b62f02a474c04c7c1ffa89543d8c6bf2e4c3d3e5ecbd39ec2fc1a4943a3949b8a09d315a6 +b6f6e224247d9528ef0da4ad9700bee6e040bbf63e4d4c4b5989d0b29a0c17f7b003c60f74332fefa3c8ddbd83cd95c1 +adbcec190a6ac2ddd7c59c6933e5b4e8507ce5fd4e230effc0bd0892fc00e6ac1369a2115f3398dfc074987b3b005c77 +8a735b1bd7f2246d3fa1b729aecf2b1df8e8c3f86220a3a265c23444bdf540d9d6fe9b18ed8e6211fad2e1f25d23dd57 +96b1bf31f46766738c0c687af3893d098d4b798237524cb2c867ed3671775651d5852da6803d0ea7356a6546aa9b33f2 +8036e4c2b4576c9dcf98b810b5739051de4b5dde1e3e734a8e84ab52bc043e2e246a7f6046b07a9a95d8523ec5f7b851 +8a4f4c32ee2203618af3bb603bf10245be0f57f1cfec71037d327fa11c1283b833819cb83b6b522252c39de3ce599fa5 +ad06ed0742c9838e3abaaffdb0ac0a64bad85b058b5be150e4d97d0346ed64fd6e761018d51d4498599669e25a6e3148 +8d91cb427db262b6f912c693db3d0939b5df16bf7d2ab6a7e1bc47f5384371747db89c161b78ff9587259fdb3a49ad91 +ae0a3f84b5acb54729bcd7ef0fbfdcf9ed52da595636777897268d66db3de3f16a9cf237c9f8f6028412d37f73f2dfad +8f774109272dc387de0ca26f434e26bc5584754e71413e35fa4d517ee0f6e845b83d4f503f777fe31c9ec05796b3b4bc +a8670e0db2c537ad387cf8d75c6e42724fae0f16eca8b34018a59a6d539d3c0581e1066053a2ec8a5280ffabad2ca51f +ac4929ed4ecad8124f2a2a482ec72e0ef86d6a4c64ac330dab25d61d1a71e1ee1009d196586ce46293355146086cabba +845d222cb018207976cc2975a9aa3543e46c861486136d57952494eb18029a1ebb0d08b6d7c67c0f37ee82a5c754f26f +b99fa4a29090eac44299f0e4b5a1582eb89b26ed2d4988b36338b9f073851d024b4201cd39a2b176d324f12903c38bee +9138823bc45640b8f77a6464c171af2fe1700bdc2b7b88f4d66b1370b3eafe12f5fbb7b528a7e1d55d9a70ca2f9fc8e6 +8ac387dc4cf52bc48a240f2965ab2531ae3b518d4d1f99c0f520a3d6eb3d5123a35ef96bed8fa71ee2f46793fa5b33b3 +864adec6339d4c2ba2525621fceabd4c455902f6f690f31a26e55413e0722e5711c509dc47ce0bcc27bbdc7651768d2d +a0a52edb72268a15201a968dabc26a22909620bda824bd548fb8c26cc848f704166ed730d958f0173bd3b0a672f367bd +949e445b0459983abd399571a1a7150aab3dd79f4b52a1cd5d733e436c71c1d4b74287c6b0ce6cc90c6711ba4c541586 +858966355dac11369e3b6552f2b381665181693d5a32e596984da3314021710b25a37d8c548b08700eea13d86cb22f21 +974bcbb8d38c5e6518745cc03ad436e585b61f31d705e7e2e5085da9655d768ac4d800904f892c3dab65d6223e3f1fd6 +8092b6506b01308bf6187fde5ebd4fa7448c9a640961ba231be22ac5fa2c7635ef01e8b357722c7695d09b723101ea2a +a5b8ef360bf28533ee17d8cd131fff661d265f609db49599085c0c7d83b0af409a1b5c28e3a5e5d7f8459a368aa121e8 +b031b6d5e3ceab0f0c93314b3b675f55cf18cbc86f70444af266fe39cb22fd7dad75d8c84e07f1c1bfa2cb8283e1361a +93ad489e4f74658320c1cceed0137c023d3001a2c930ed87e6a21dbf02f2eb6ad1c1d8bcb3739c85dcfbecb040928707 +b15e4ec2cdab0d34aec8d6c50338812eb6ecd588cf123a3e9d22a7ca23b5a98662af18289f09e6cdd85a39a2863c945c +b304f71a9717cf40c22073f942618b44bf27cd5e2ed4a386ad45d75b0fcb5a8dafd35158211eaf639495c6f1a651cedb +b82d78d3eaaa7c5101b7a5aae02bd4f002cd5802d18c3abcda0dd53b036661c6d3c8b79e0abe591eab90b6fdc5fef5e3 +abbd1884243a35578b80914a5084449c237ee4e4660c279d1073a4d4217d1b55c6b7e9c087dfd08d94ac1416273d8d07 +92f4b61c62502745e3e198ec29bca2e18696c69dcb914d1f3a73f4998d012b90caf99df46e9bb59942e43cce377fe8fd +906e79df98185820c8208844e1ba6bd86cb96965814b01310bd62f22cbec9b5d379b2ef16772d6fc45a421b60cfd68fe +a0eae2784ef596e2eb270dd40c48d6c508e4394c7d6d08d4cc1b56fde42b604d10ba752b3a80f2c4a737e080ef51b44f +94c084985e276dc249b09029e49a4ef8a369cd1737b51c1772fbb458d61e3fe120d0f517976eba8ffa5711ba93e46976 +83619a0157eff3f480ab91d1d6225fead74c96a6fd685333f1e8e4d746f6273e226bad14232f1d1168a274e889f202f1 +a724fe6a83d05dbbf9bb3f626e96db2c10d6d5c650c0a909415fbda9b5711c8b26e377201fb9ce82e94fa2ab0bf99351 +a8a10c1b91a3a1fa2d7fd1f78a141191987270b13004600601d0f1f357042891010717319489f681aa8a1da79f7f00d5 +a398a2e95b944940b1f8a8e5d697c50e7aa03994a8a640dfad4ea65cfb199a4d97861a3ec62d1c7b2b8d6e26488ca909 +a2eedfe5452513b2a938fffd560798ef81379c5a5032d5b0da7b3bb812addbaad51f564c15d9acbbfc59bb7eddd0b798 +ab31c572f6f145a53e13b962f11320a1f4d411739c86c88989f8f21ab629639905b3eedb0628067942b0dc1814b678ca +ad032736dd0e25652d3566f6763b48b34ea1507922ed162890cd050b1125ec03b6d41d34fccba36ec90336f7cdf788ed +83028a558a5847293147c483b74173eca28578186137df220df747fccd7d769528d7277336ea03c5d9cdd0bc5ae3d666 +ab5d182cd1181de8e14d3ef615580217c165e470b7a094a276b78a3003089123db75c6e1650bf57d23e587c587cd7472 +a4793e089fbdb1597654f43b4f7e02d843d4ab99ee54099c3d9f0bd5c0c5657c90bb076379a055b00c01b12843415251 +98bdc52ee062035356fb2b5c3b41673198ddc60b2d1e546cb44e3bb36094ef3c9cf2e12bbc890feb7d9b15925439d1ea +a4f90cca6f48024a0341bd231797b03693b34e23d3e5b712eb24aba37a27827319b2c16188f97c0636a0c115381dc659 +8888e6c2e4a574d04ba5f4264e77abc24ccc195f1a7e3194169b8a2ceded493740c52db4f9833b3dbf4d67a3c5b252cb +83dc4e302b8b0a76dc0292366520b7d246d73c6aebe1bdd16a02f645c082197bcff24a4369deda60336172cefbcf09af +a4eb2741699febfeb793914da3054337cc05c6fa00d740e5f97cb749ae16802c6256c9d4f0f7297dcdbb8b9f22fc0afa +8b65557d5be273d1cb992a25cfce40d460c3f288d5cb0a54bdef25cbd17cdea5c32ec966e493addf5a74fd8e95b23e63 +97c6577e76c73837bcb398b947cb4d3323d511141e0ddd0b456f59fbb1e8f920a5c20d7827a24309145efddee786140f +abcc0849ffe2a6a72157de907907b0a52deece04cf8317bee6fe1d999444b96e461eac95b6afde3d4fe530344086a625 +9385c0115cb826a49df1917556efa47b5b5e4022b6a0d2082053d498ec9681da904ecf375368bb4e385833116ea61414 +8b868c1841f0cdc175c90a81e610b0652c181db06731f5c8e72f8fafa0191620742e61a00db8215a991d60567b6a81ca +a8df15406f31b8fcf81f8ff98c01f3df73bf9ec84544ddec396bdf7fafa6fe084b3237bf7ef08ad43b26517de8c3cd26 +a9943d21e35464ce54d4cc8b135731265a5d82f9ccf66133effa460ffdb443cdb694a25320506923eede88d972241bf2 +a1378ee107dd7a3abcf269fd828887c288363e9b9ca2711377f2e96d2ed5e7c5ec8d3f1da995a3dcbedf1752d9c088fc +8a230856f9227b834c75bdebc1a57c7298a8351874bf39805c3e0255d6fd0e846f7ad49709b65ec1fd1a309331a83935 +877bcf42549d42610e1780e721f5800972b51ba3b45c95c12b34cb35eeaf7eac8fa752edd7b342411820cf9093fea003 +84c7a0b63842e50905624f1d2662506b16d1f3ea201877dfc76c79181c338b498eceb7cad24c2142c08919120e62f915 +8e18b1bd04b1d65f6ed349b5d33a26fe349219043ead0e350b50ae7a65d6ff5f985dd9d318d3b807d29faa1a7de4fe42 +8ea7b5a7503e1f0b3c3cd01f8e50207044b0a9c50ed1697794048bbe8efd6659e65134d172fb22f95439e1644f662e23 +b1954a2818cad1dad6d343a7b23afa9aa8ad4463edc4eb51e26e087c2010927535020d045d97d44086d76acdb5818cbf +a5271ea85d0d21fa1ff59b027cf88847c0f999bbf578599083ff789a9b5228bc161e1c81deb97e74db1a82a0afd61c50 +aa2fa4c05af3387e2c799315781d1910f69977ec1cfea57a25f1a37c63c4daaa3f0ecd400884a1673e17dd5300853bcf +b1cd2a74ca0b8e6090da29787aef9b037b03b96607983a308b790133bd21297b21ca4e2edec890874096dbf54e9d04c3 +801931607ec66a81272feaa984f0b949ad12d75ecf324ba96627bd4dc5ddead8ebf088f78e836b6587c2b6c0b3366b6c +95d79504710bdf0ad9b9c3da79068c30665818c2f0cdbba02cc0a5e46e29d596032ac984441b429bd62e34535c8d55b0 +9857d41e25e67876510ff8dadf0162019590f902da1897da0ef6fc8556e3c98961edb1eb3a3a5c000f6c494413ded15e +8740c9ffe6bd179c19a400137c3bd3a593b85bd4c264e26b4dfb9e2e17ac73e5b52dfacc1dcb4033cfc0cd04785f4363 +977f98f29d948b4097a4abdf9345f4c1fb0aa94ba0c6bf6faa13b76f3a3efc8f688e1fe96099b71b3e1c05041118c8d1 +a364422b1239126e3e8d7b84953ce2181f9856319b0a29fcab81e17ac27d35798088859c1cfc9fc12b2dbbf54d4f70b3 +a0f6ba637f0db7a48e07439bb92ddb20d590ce9e2ed5bab08d73aa22d82c32a9a370fe934cbe9c08aeb84b11adcf2e0e +a2c548641bd5b677c7748327cca598a98a03a031945276be6d5c4357b6d04f8f40dd1c942ee6ec8499d56a1290ac134d +9863e9cc5fbcdbd105a41d9778d7c402686bfd2d81d9ed107b4fda15e728871c38647529693306855bee33a00d257a7e +a54173bf47b976290c88fd41f99300135de222f1f76293757a438450880e6f13dbde3d5fe7afc687bdfbcfc4fbc1fc47 +b8db413917c60907b73a997b5ab42939abd05552c56a13525e3253eb72b83f0d5cc52b695968a10005c2e2fe13290e61 +a1f8388ef21697c94ba90b1a1c157f0dc138e502379e6fc5dc47890d284563e5db7716266e1b91927e5adf3cde4c0a72 +9949013a59d890eb358eab12e623b2b5edb1acbee238dfad8b7253102abc6173922e188d5b89ec405aa377be8be5f16d +a00fdb7710db992041f6ddb3c00099e1ce311dea43c252c58f560c0d499983a89de67803a8e57baa01ee9d0ee6fa1e44 +a8b1bcbed1951c9cdb974b61078412881b830b48cd6b384db0c00fa68bcc3f4312f8e56c892ea99d3511857ef79d3db9 +8f3ee78404edc08af23b1a28c2012cee0bdf3599a6cb4ea689fc47df4a765ef519191819a72562b91a0fbcdb896a937e +8155bbb7fa8d386848b0a87caae4da3dec1f3dade95c750a64a8e3555166ccc8799f638bd80ed116c74e3a995541587a +abfe30adbc0a6f1fd95c630ed5dac891b85384fa9331e86b83217f29dff0bd7cad19d328485715a7e3df9a19069d4d2f +89d0783e496ee8dbb695764b87fb04cee14d4e96c4ba613a19736971c577d312079048142c12ce5b32b21e4d491d281b +856b8dbc9c5d8f56b6bb7d909f339ca6da9a8787bba91f09130a025ab6d29b64dbf728ba6ed26e160a23c1cdb9bc037b +8a30dd2ea24491141047a7dfe1a4af217661c693edf70b534d52ca547625c7397a0d721e568d5b8398595856e80e9730 +ae7e1412feb68c5721922ed9279fb05549b7ef6812a4fd33dbbbd7effab756ab74634f195d0c072143c9f1fd0e1ee483 +b7ce970e06fa9832b82eef572f2902c263fda29fdce9676f575860aae20863046243558ede2c92343616be5184944844 +85ed0531f0e5c1a5d0bfe819d1aa29d6d5ff7f64ad8a0555560f84b72dee78e66931a594c72e1c01b36a877d48e017ca +b8595be631dc5b7ea55b7eb8f2982c74544b1e5befc4984803b1c69727eac0079558182f109e755df3fd64bee00fcaa5 +99e15a66e5b32468ef8813e106271df4f8ba43a57629162832835b8b89402eb32169f3d2c8de1eb40201ce10e346a025 +844c6f5070a8c73fdfb3ed78d1eddca1be31192797ad53d47f98b10b74cc47a325d2bc07f6ee46f05e26cf46a6433efb +974059da7f13da3694ad33f95829eb1e95f3f3bfc35ef5ef0247547d3d8ee919926c3bd473ab8b877ff4faa07fcc8580 +b6f025aecc5698f6243cc531782b760f946efebe0c79b9a09fe99de1da9986d94fa0057003d0f3631c39783e6d84c7d5 +b0c5358bc9c6dfe181c5fdf853b16149536fbb70f82c3b00db8d854aefe4db26f87332c6117f017386af8b40288d08f9 +a3106be5e52b63119040b167ff9874e2670bd059b924b9817c78199317deb5905ae7bff24a8ff170de54a02c34ff40a4 +ad846eb8953a41c37bcd80ad543955942a47953cbc8fb4d766eac5307892d34e17e5549dc14467724205255bc14e9b39 +b16607e7f0f9d3636e659e907af4a086ad4731488f5703f0917c4ce71a696072a14a067db71a3d103530920e1ec50c16 +8ed820e27116e60c412c608582e9bb262eaaf197197c9b7df6d62b21a28b26d49ea6c8bb77dfde821869d9b58025f939 +97bc25201d98cde389dd5c0c223a6f844393b08f75d3b63326343073e467ac23aacef630ddc68545ea874299ba4a3b4f +b73c9695ad2eefd6cc989a251c433fab7d431f5e19f11d415a901762717d1004bb61e0cc4497af5a8abf2d567e59fef4 +adaabe331eea932533a7cc0cf642e2a5e9d60bbc92dd2924d9b429571cbf0d62d32c207b346607a40643c6909b8727e2 +a7b1bbfe2a5e9e8950c7cb4daab44a40c3ffab01dc012ed7fe445f4af47fa56d774a618fafe332ab99cac4dfb5cf4794 +b4a3c454dcd5af850212e8b9ba5fe5c0d958d6b1cabbf6c6cfe3ccbc4d4c943309c18b047256867daf359006a23f3667 +a5c0b32f6cef993834c1381ec57ad1b6f26ae7a8190dd26af0116e73dadc53bb0eeb1911419d609b79ce98b51fdc33bc +ac2f52de3ecf4c437c06c91f35f7ac7d171121d0b16d294a317897918679f3b9db1cef3dd0f43adb6b89fe3030728415 +94722ae6d328b1f8feaf6f0f78804e9b0219de85d6f14e8626c2845681841b2261d3e6a2c5b124086b7931bf89e26b46 +a841a0602385d17afabca3a1bb6039167d75e5ec870fea60cfcaec4863039b4d745f1a008b40ec07bca4e42cb73f0d21 +8c355f0a1886ffced584b4a002607e58ff3f130e9de827e36d38e57cb618c0cb0b2d2dea2966c461cb3a3887ede9aef1 +a6a9817b0fc2fd1786f5ba1a7b3d8595310987fb8d62f50a752c6bb0b2a95b67d03a4adfd13e10aa6190a280b7ee9a67 +a1d2e552581ecbafeaef08e389eaa0b600a139d446e7d0648ac5db8bbbf3c438d59497e3a2874fc692b4924b87ff2f83 +a1b271c55389f25639fe043e831e2c33a8ba045e07683d1468c6edd81fedb91684e4869becfb164330451cfe699c31a8 +8c263426e7f7e52f299d57d047a09b5eeb893644b86f4d149535a5046afd655a36d9e3fdb35f3201c2ccac2323a9582e +b41c242a7f7880c714241a97d56cce658ee6bcb795aec057a7b7c358d65f809eb901e0d51256826727dc0dc1d1887045 +93001b9445813c82f692f94c0dc1e55298f609936b743cf7aae5ebfa86204f38833d3a73f7b67314be67c06a1de5682d +82087536dc5e78422ad631af6c64c8d44f981c195ddea07d5af9bb0e014cdc949c6fa6e42fce823e0087fdb329d50a34 +8e071861ceba2737792741c031f57e0294c4892684506b7c4a0fc8b2f9a0a6b0a5635de3d1e8716c34df0194d789ae86 +b471c997e1e11774bd053f15609d58838a74073a6c089a7a32c37dd3f933badf98c7e5833263f3e77bc0d156a62dd750 +8d2d8686fb065b61714414bb6878fff3f9e1e303c8e02350fd79e2a7f0555ded05557628152c00166ce71c62c4d2feaa +ae4c75274d21c02380730e91de2056c0262ffcecf0cbdb519f0bdb0b5a10ae2d4996b3dc4b3e16dbaea7f0c63d497fef +97140d819e8ca6330e589c6debdee77041c5a9cedb9b8cbd9c541a49207eeb7f6e6b1c7e736ec8ba6b3ab10f7fcd443a +af6659f31f820291a160be452e64d1293aa68b5074b4c066dac169b8d01d0179139504df867dc56e2a6120354fc1f5be +a5e5d8088a368024617bfde6b731bf9eee35fc362bed3f5dfdd399e23a2495f97f17728fec99ca945b3282d1858aa338 +a59cfc79d15dbdde51ab8e5129c97d3baba5a0a09272e6d2f3862370fdbaf90994e522e8bd99d6b14b3bb2e9e5545c6f +a30499b068083b28d6c7ddcc22f6b39b5ec84c8ee31c5630822c50ea736bb9dca41c265cffc6239f1c9ef2fd21476286 +88ffe103eca84bbe7d1e39a1aa599a5c7c9d5533204d5c4e085402a51441bb8efb8971efe936efbbfa05e5cb0d4b8017 +b202356fbf95a4d699154639e8cb03d02112c3e0128aab54d604645d8510a9ba98936028349b661672c3a4b36b9cb45d +8b89bb6574bf3524473cff1ff743abcf1406bd11fb0a72070ccd7d8fce9493b0069fb0c6655252a5164aee9e446ea772 +93247b1038fa7e26667ee6446561d4882dc808d1015daafb705935ddc3598bb1433182c756465960480f7b2de391649e +b027f94d3358cbb8b6c8c227300293a0dee57bf2fee190a456ad82ecfb6c32f8090afa783e2ab16f8139805e1fb69534 +a18bb1849b2f06c1d2214371031d41c76ffa803ee3aa60920d29dbf3db5fbfac2b7383d5d0080ba29ce25c7baa7c306b +827bf9fd647e238d5ac961c661e5bbf694b4c80b3af8079f94a2484cb8fba2c8cf60e472ebcd0b0024d98ae80ad2ff5a +838e891218c626a7f39b8fd546b013587408e8e366ecc636b54f97fa76f0a758bc1effa1d0f9b6b3bc1a7fcc505970a0 +836523b5e8902d6e430c6a12cff01e417d2bd7b402e03904034e3b39755dee540d382778c1abe851d840d318ebedce7f +850a77dda9ac6c217e2ef00bf386a1adec18b7f462f52801c4f541215690502a77ef7519b690e22fdf54dc2109e0ca38 +a8265c6ae7b29fc2bda6a2f99ced0c1945dd514b1c6ca19da84b5269514f48a4f7b2ccbab65c9107cfd5b30b26e5462f +ab3d02ee1f1267e8d9d8f27cc388e218f3af728f1de811242b10e01de83471a1c8f623e282da5a284d77884d9b8cde0e +831edaf4397e22871ea5ddee1e7036bab9cc72f8d955c7d8a97f5e783f40532edbbb444d0520fefcffeab75677864644 +80484487977e4877738744d67b9a35b6c96be579a9faa4a263e692295bb6e01f6e5a059181f3dd0278e2c3c24d10a451 +aae65a18f28c8812617c11ecf30ad525421f31fb389b8b52d7892415e805a133f46d1feca89923f8f5b8234bd233486a +b3a36fd78979e94288b4cefed82f043a7e24a4a8025479cc7eb39591e34603048a41ee606ee03c0b5781ebe26a424399 +b748b3fc0d1e12e876d626a1ba8ad6ad0c1f41ea89c3948e9f7d2666e90173eb9438027fadcd741d3ae0696bd13840f1 +acdd252d7c216c470683a140a808e011c4d5f1b4e91aeb947f099c717b6a3bad6651142cde988330827eb7d19d5fb25c +b9a25556a6ca35db1ed59a1ec6f23343eab207a3146e4fc3324136e411c8dba77efd567938c63a39c2f1c676b07d8cdb +a8db6aef8f5680d2bdb415d7bcaae11de1458678dcb8c90c441d5986c44f83a9e5855662d0c1aace999172d8628d8fe1 +af58147108e9909c3a9710cc186eab598682dca4bfd22481e040b8c000593ecb22c4ede4253ac9504e964dfa95a9b150 +8dd8bb70f1c9aec0fcc9478f24dfc9c3c36c0bf5ff7a67c017fa4dab2ec633fbd7bc9d8aa41ea63e2696971ed7e375f5 +aa98d600b22aff993a4d7a3ccabd314e1825b200cb598f6b797d7e4d6a76d89e34a4d156c06bddfc62f2ef9b4c809d1d +8a8fc960d6c51294b8205d1dabe430bef59bda69824fa5c3c3105bef22ac77c36d2d0f38ffc95ce63731de5544ccbeff +b6d1020efe01dc8032bd1b35e622325d7b9af9dcd5c9c87c48d7d6ebc58644454294c59b7f4b209204b5b1f899f473bf +8a750dc9fe4891f2dfe5759fb985939810e4cdc0b4e243ff324b6143f87676d8cb4bcb9dfb01b550801cedcaaa5349e2 +98c13142d3a9c5f8d452245c40c6dae4327dd958e0fda85255ea0f87e0bcbaa42a3a0bd50407ed2b23f9f6317a8a4bc5 +99f2b83d9ec4fc46085a6d2a70fd0345df10f4a724c1ba4dee082a1fde9e642e3091992ebf5f90a731abcb6ec11f6d9b +b218546ab2db565b2489ea4205b79daa19ef2acbf772ccaaa5e40150e67ea466090d07198444b48e7109939aa2319148 +84f9d1d868e4b55e535f1016558f1789df0daa0ead2d13153e02f715fe8049b1ce79f5bc1b0bbbb0b7e4dd3c04783f3f +80d870d212fbddfdda943e90d35a5a8aa0509a7a1e7f8909f2fcb09c51c3026be47cc7a22620a3063406872105b4f81a +b5b15138ff6551fac535d4bbce2ea6adc516b6b7734b4601c66ec029da2615e3119dc9ad6a937344acfd7b50e4a1a2ae +95d2f97652086e7ceb54e1d32692b1c867ffba23c4325740c7f10d369283d1b389e8afa0df967831ade55696931e7934 +8a5b580403e1a99cd208f707e8ce0d3f658c8280417683f69008d09cc74d835a85f7380f391b36ead9ac66d9eedd1cbe +a8b0c90bff34c86720637b5a2081f0f144cfe2205c1176cacd87d348609bc67af68aed72414dc9aa6f44a82c92c2a890 +865abbdd96c496892c165a8de0f9e73348bf24fce361d7a9048710178a3625881afb0006e9f5ee39124866b87904c904 +ace67bb994adef4b6f841cdf349195608030044562780a7e9b00b58a4ff117268a03ff01e5a3a9d9d7eff1dd01f5f4bf +b9371d59185b3d2d320d3fefeadb06ba2aa7d164352fb8dc37571509509fa214d736d244ac625a09a033a10d51611e2e +a8ef992771422dcf2d6d84386fde9fe5dba88bfded3dfcd14074ca04331b4fd53a7f316615cdfaf10ed932cbb424a153 +868cbc75f8f789ea45eded2768a1dac0763347e0d8e8028d316a21005f17be179d26d5965903e51b037f2f57fe41765d +b607111bcdfd05fa144aa0281b13ee736079ebbbf384d938a60e5e3579639ed8ef8eb9ca184868cdb220a8e130d4a952 +aca55702af5cae4cae65576769effd98858307a71b011841c563b97c2aa5aeb5c4f8645d254f631ed1582df3dbbf17da +b9b5cbace76246e80c20dfcc6f1e2c757a22ab53f7fd9ff8a1d309538b55174e55e557a13bf68f095ff6a4fa637ef21a +8571b0a96871f254e2397c9be495c76379faf347801cb946b94e63212d6a0da61c80e5d7bebbabcd6eaa7f1029172fe5 +902540326281e6dc9c20d9c4deaaf6fbbbcc3d1869bd0cf7f081c0525bea33df5cfa24ead61430fda47fb964fcc7994b +841af09279d3536a666fa072278950fabf27c59fc15f79bd52acb078675f8087f657929c97b4bc761cbade0ecb955541 +a1f958b147ddf80ab2c0746ba11685c4bae37eb25bfa0442e7e1078a00d5311d25499da30f6d168cb9302ea1f2e35091 +863d939381db37d5a5866964be3392a70be460f0353af799d6b3ed6307176972686bd378f8ad457435a4094d27e8dfb7 +835cd4d7f36eff553d17483eb6c041b14280beb82c7c69bca115929658455a1931212976c619bafb8179aed9940a8cc6 +8d0770e3cb8225e39c454a1fc76954118491b59d97193c72c174ecc7613051e5aed48a534016a8cf0795c524f771a010 +91aa4edb82f6f40db2b7bd4789cc08786f6996ebed3cb6f06248e4884bc949793f04a4c5ea6eefe77984b1cc2a45d699 +8fb494ca2449f659ff4838833507a55500a016be9293e76598bbae0a7cb5687e4693757c2b6d76e62bd6c7f19ed080bb +b59b104449a880a282c1dd6a3d8debb1d8814ef35aab5673c1e500ee4cb0e840fb23e05fa5a0af92509c26b97f098f90 +aca908e3bad65e854ae6be6c5db441a06bcd47f5abafdfa8f5a83c8cd3c6e08c33cab139c45887887a478338e19ceb9f +806f5d802040313a31964fc3eb0ee18ac91b348685bed93c13440984ee46f3d2da7194af18c63dea4196549129660a4e +ae4b2dca75c28d8f23b3ab760b19d839f39ff5a3112e33cb44cff22492604a63c382b88ec67be4b0266924dd438c3183 +99d1c29c6bd8bf384e79cd46e30b8f79f9cbc7d3bf980e9d6ffba048f0fc487cac45c364a8a44bb6027ad90721475482 +a16e861c1af76d35528c25bf804bfc41c4e1e91b2927d07d8e96bffe3a781b4934e9d131ecf173be9399800b8269efac +a253303234fb74f5829060cdcef1d98652441ab6db7344b1e470d195a95722675988048d840201c3b98e794b1e8b037c +905ac8a0ea9ce0eb373fb0f83dd4cbe20afb45b9d21ae307846fd4757d4d891b26a6711924e081e2b8151e14a496da18 +b485315791e775b9856cc5a820b10f1fa5028d5b92c2f0e003ba55134e1eddb3eb25f985f2611a2257acf3e7cfdfab5e +b6189c0458b9a043ebc500abc4d88083a3487b7ac47ed5e13ab2a41e0a1bee50d54a406063f92bc96959f19e822a89a7 +a30e15f995fd099a223fc6dc30dad4b8d40bee00caa2bc3223ba6d53cd717c4968a3e90c4618c711ed37cc4cd4c56cf3 +a1b1ed07fcc350bb12a09cd343768d208fc51a6b3486f0ece8f5a52f8a5810b4bc7ab75582ec0bc2770aed52f68eace5 +88aa739fbae4bece147ba51a863e45d5f7203dbc3138975dc5aef1c32656feb35f014d626e0d5b3d8b1a2bda6f547509 +ab570f3c8eabfca325b3a2ea775ef6b0c6e6138c39d53c2310329e8fb162869fde22b0e55688de9eb63d65c37598fca3 +89d274762c02158e27cb37052e296a78f2b643eb7f9ae409f8dac5c587d8b4d82be4ef7c79344a08ebec16ac4a895714 +99c411d2ad531e64f06e604d44c71c7c384424498ecd0a567d31ec380727fb605af76643d0d5513dd0a8d018076dd087 +80d0777fa9f79f4a0f0f937d6de277eec22b3507e2e398f44b16e11e40edf5feff55b3b07a69e95e7e3a1621add5ed58 +b2430a460783f44feb6e4e342106571ef81ad36e3ddd908ec719febeb7acaf4b833de34998f83a1dab8f0137a3744c11 +b8f38ccfc7279e1e30ad7cefc3ea146b0e2dff62430c50a5c72649a4f38f2bac2996124b03af2079d942b47b078cc4f8 +a178a450a62f30ec2832ac13bbc48789549c64fc9d607b766f6d7998558a0e2fad007ae0148fc5747189b713f654e6ba +98c5ede296f3016f6597f7ccc5f82c88fd38ed6dc3d6da3e4a916bfd7c4c95928722a1d02534fe89387c201d70aa6fd2 +a8cc5e98573705d396576e022b2ba2c3e7c7ece45cd8605cb534b511763682582299e91b4bb4100c967019d9f15bbfaf +848480ea7b7d9536e469da721236d932870b7bbee31ccf7ae31b4d98d91413f59b94a1e0d1786ee7342295aa3734969c +b88ea38f9ee432f49e09e4e013b19dff5a50b65453e17caf612155fff6622198f3cba43b2ea493a87e160935aaaf20a9 +949376934a61e0ef8894339c8913b5f3b228fa0ae5c532ad99b8d783b9e4451e4588541f223d87273c0e96c0020d5372 +96f90bb65ca6b476527d32c415814b9e09061648d34993f72f28fae7dc9c197e04ef979f804076d107bb218dfd9cb299 +a4402da95d9942c8f26617e02a7cef0ebc4b757fac72f222a7958e554c82cc216444de93f659e4a1d643b3e55a95d526 +81179cbc26a33f6d339b05ea3e1d6b9e1190bd44e94161ae36357b9cdf1e37d745d45c61735feed64371fe5384102366 +ad4dc22bdbd60e147fdac57d98166de37c727f090059cfc33e5ee6cf85e23c2643996b75cf1b37c63f3dc9d3c57ffa18 +8a9b1b93dc56e078ce3bb61c2b0088fd6c3e303ba6b943231cc79d4a8e8572f4109bbde5f5aa7333aae3287909cb0fe2 +8876ef583bc1513322457a4807d03381ba1f4d13e179260eaa3bddfede8df677b02b176c6c9f74c8e6eab0e5edee6de6 +b6c67e228bf190fbaeb2b7ec34d4717ce710829c3e4964f56ebb7e64dc85058c30be08030fa87cc94f1734c5206aef5f +a00cb53b804ee9e85ce12c0103f12450d977bc54a41195819973c8a06dcb3f46f2bf83c3102db62c92c57ab4dd1e9218 +a7675a64772eefddf8e94636fb7d1d28f277074327c02eea8fae88989de0c5f2dc1efed010f4992d57b5f59a0ab40d69 +8d42bb915e0bf6a62bcdf2d9330eca9b64f9ec36c21ae14bf1d9b0805e5e0228b8a5872be61be8133ad06f11cb77c363 +a5b134de0d76df71af3001f70e65c6d78bed571bc06bfddf40d0baad7ea2767608b1777b7ef4c836a8445949877eeb34 +aeadbc771eaa5de3a353229d33ed8c66e85efbd498e5be467709cb7ff70d3f1a7640002568b0940e3abd7b2da81d2821 +8c28da8e57a388007bd2620106f6226b011ee716a795c5d9f041c810edf9cf7345b2e2e7d06d8a6b6afa1ee01a5badc1 +8ed070626a4d39ffd952ddb177bc68fd35b325312e7c11694c99b691f92a8ea7734aeb96cf9cc73e05b3c1b1dcad6978 +ada83e18e4842f3d8871881d5dbc81aed88a1328298bfdc9e28275094bd88d71b02e7b8501c380fa8d93096cbc62f4fb +8befc3bec82dcf000a94603b4a35c1950ba5d00d4bed12661e4237afa75062aa5dcef8eac0b9803136c76d2dd424a689 +97c6f36c91ca5ca9230bfcbf109d813728b965a29b62e5f54c8e602d14a52ac38fa1270de8bfe1ab365426f3fc3654c7 +b01d192af3d8dbce2fe2fece231449e70eb9ac194ec98e758da11ca53294a0fa8c29b1d23a5d9064b938b259ea3b4fb5 +819a2c20646178f2f02865340db1c3c6ebc18f4e6559dd93aa604388796a34bd9fed28ad3ccc8afc57a5b60bb5c4e4ec +a9ffc877470afc169fecf9ec2dc33253b677371938b0c4ffa10f77bb80089afa2b4488437be90bb1bcf7586a6f4286e3 +b533051c7ce7107176bcb34ad49fdb41fac32d145854d2fe0a561c200dcf242da484156177e2c8f411c3fdf1559ecf83 +8fe2caff2e4241d353110a3618832f1443f7afe171fd14607009a4a0aa18509a4f1367b67913e1235ac19de15e732eb1 +84705c6370619403b9f498059f9869fdf5f188d9d9231a0cb67b1da2e8c906ead51b934286497293698bba269c48aa59 +899dddf312a37e3b10bdaaacc1789d71d710994b6ee2928ac982ad3fd8a4f6167672bc8bf3419412711c591afe801c28 +b2f7916d946b903ded57b9d57025386143410a41a139b183b70aeca09cf43f5089ead1450fce4e6eb4fba2c8f5c5bbe5 +8d5f742fe27a41623b5820914c5ca59f82246010fa974304204839880e5d0db8bc45ebab2ad19287f0de4ac6af25c09e +b93d4a1f6f73ac34da5ffbd2a4199cf1d51888bc930dc3e481b78806f454fcb700b4021af7525b108d49ebbbaa936309 +8606f8d9121512e0217a70249937e5c7f35fbfe019f02248b035fa3a87d607bc23ae66d0443e26a4324f1f8e57fd6a25 +b21312cdec9c2c30dd7e06e9d3151f3c1aceeb0c2f47cf9800cce41521b9d835cb501f98b410dc1d49a310fdda9bc250 +a56420b64286bdddda1e212bba268e9d1ba6bdb7132484bf7f0b9e38099b94a540884079b07c501c519b0813c184f6b4 +80b2cf0e010118cb2260f9c793cef136f8fa7b5e2711703735524e71d43bce2d296c093be41f2f59118cac71f1c5a2ff +adcb12d65163804d2f66b53f313f97152841c3625dbbda765e889b9937195c6fcd55d45cc48ebffabb56a5e5fe041611 +8b8a42e50dc6b08ab2f69fc0f6d45e1ea3f11ba0c1008ee48448d79d1897356599e84f7f9d8a100329ed384d6787cfc4 +aaa9c74afa2dec7eccfbd8bb0fc6f24ed04e74c9e2566c0755a00afdfdf3c4c7c59e2a037ec89c2f20af3fae1dd83b46 +aa9f6e8fd59187171c6083ae433627d702eb78084f59010ff07aff8f821f7022ef5fbbe23d76814d811b720a8bfa6cc3 +a56a3ded501659ad006d679af3287080b7ee8449e579406c2cae9706ef8bf19c1fc2eb2a6f9eaf2d3c7582cded73e477 +81971e077c1da25845840222b4191e65f6d242b264af4e86800f80072d97d2a27a6adc87c3a1cb1b0dd63d233fbafa81 +a6fa5453c4aaad2947969ee856616bf6448224f7c5bf578f440bcfc85a55beb40bef79df8096c4db59d1bd8ef33293ea +87c545adbfaaf71e0ab4bac9ae4e1419718f52b0060e8bb16b33db6d71b7248ae259d8dd4795b36a4bbb17f8fae9fd86 +b4c7a9bc0910e905713291d549cec5309e2d6c9b5ea96954489b1dff2e490a6c8b1fa1e392232575f0a424ba94202f61 +802350b761bcaba21b7afe82c8c6d36ee892b4524ab67e2161a91bbfa1d8e92e7e771efb1f22c14126218dd2cb583957 +b4e7ddb9143d4d78ea8ea54f1c908879877d3c96ee8b5e1cb738949dcfceb3012a464506d8ae97aa99ea1de2abf34e3d +a49a214065c512ad5b7cc45154657a206ef3979aa753b352f8b334411f096d28fd42bca17e57d4baaafb014ac798fc10 +8a80c70a06792678a97fe307520c0bf8ed3669f2617308752a2ab3c76fdf3726b014335a9b4c9cbcfc1df3b9e983c56f +a34721d9e2a0e4d08995a9d986dc9c266c766296d8d85e7b954651ad2ca07e55abb1b215898ee300da9b67114b036e0d +8cfce4564a526d7dca31e013e0531a9510b63845bbbd868d5783875ed45f92c1c369ce4a01d9d541f55f83c2c0a94f03 +ab3f5f03a5afc727778eb3edf70e4249061810eba06dc3b96b718e194c89429c5bfbec4b06f8bce8a2118a2fdce67b59 +aa80c2529fc19d428342c894d4a30cb876169b1a2df81a723ab313a071cba28321de3511a4de7846207e916b395abcc9 +82b7828249bf535ef24547d6618164b3f72691c17ca1268a5ee9052dba0db2fdd9987c8e083307a54399eab11b0f76b1 +8fbcb56b687adad8655a6cf43364a18a434bf635e60512fad2c435cf046f914228fb314f7d8d24d7e5e774fb5ffb1735 +a3010a61a2642f5ebbce7b4bc5d6ecb3df98722a49eb1655fe43c1d4b08f11dfad4bcec3e3f162d4cc7af6a504f4d47c +b3dcc0fdf531478e7c9ef53190aa5607fd053a7d2af6c24a15d74c279dbb47e3c803a1c6517d7e45d6534bb59e3527f5 +8648f6316c898baaca534dff577c38e046b8dfa8f5a14ee7c7bc95d93ae42aa7794ba0f95688a13b554eeb58aeedf9ba +89fca6fc50407695e9315483b24f8b4e75936edf1475bcf609eed1c4370819abac0e6a7c3c44f669560367d805d9ba63 +a367a17db374f34cd50f66fb31ba5b7de9dbe040f23db2dcc1d6811c0e863606f6c51850af203956f3399000f284d05f +91030f9ca0fff3e2dbd5947dcf2eba95eb3dbca92ee2df0ed83a1f73dbf274611af7daf1bb0c5c2ee46893ab87013771 +84d56181f304ce94015ea575afeef1f84ea0c5dbb5d29fb41f25c7f26077b1a495aff74bd713b83bce48c62d7c36e42d +8fe2f84f178739c3e2a2f7dcac5351c52cbed5fa30255c29b9ae603ffd0c1a181da7fb5da40a4a39eec6ce971c328fcf +a6f9b77b2fdf0b9ee98cb6ff61073260b134eb7a428e14154b3aa34f57628e8980c03664c20f65becfe50d2bdd2751d4 +8c6760865445b9327c34d2a1247583694fbeb876055a6a0a9e5cb460e35d0b2c419e7b14768f1cc388a6468c94fd0a0f +af0350672488a96fe0089d633311ac308978a2b891b6dbb40a73882f1bda7381a1a24a03e115ead2937bf9dcd80572ad +a8e528ec2ee78389dd31d8280e07c3fdd84d49556a0969d9d5c134d9a55cd79e1d65463367b9512389f125ed956bc36a +942c66589b24f93e81fe3a3be3db0cd4d15a93fb75260b1f7419f58d66afaa57c8d2d8e6571536790e2b415eec348fd9 +83fe4184b4b277d8bf65fb747b3c944170824b5832751057e43465526560f60da6e5bbee2f183cb20b896a20197168c7 +88a71aada494e22c48db673d9e203eef7a4e551d25063b126017066c7c241ee82bedaa35741de4bd78a3dd8e21a8af44 +8c642a3186ca264aac16ee5e27bd8da7e40e9c67ae159b5d32daa87b7de394bf2d7e80e7efb1a5506c53bfd6edd8c2c3 +81855d6de9a59cef51bef12c72f07f1e0e8fe324fcc7ec3f850a532e96dcd434c247130610aaee413956f56b31cbb0dc +a01e61390dcd56a58ad2fcdb3275704ddfbedef3ba8b7c5fce4814a6cdd03d19d985dba6fd3383d4db089444ea9b9b4d +96494e89cbf3f9b69488a875434302000c2c49b5d07e5ff048a5b4a8147c98291ae222529b61bb66f1903b2e988e5425 +b9689b3e8dddc6ec9d5c42ba9877f02c1779b2c912bba5183778dc2f022b49aed21c61c8ec7e3c02d74fe3f020a15986 +a2a85e213b80b0511395da318cbb9935c87b82c305f717a264155a28a2ea204e9e726bae04ce6f012e331bd6730cbb9d +91b70f44c7d8c5980ce77e9033a34b05781cbe773854d3f49d2905cc711a3d87c20d5d496801ad6fd82438874ce732b8 +884596417ff741bb4d11925d73852ffeea7161c7f232be3bdce9e6bbe7884c3a784f8f1807356ae49d336b7b53a2b495 +ae2aed8ab6951d8d768789f5bc5d638838d290d33ccc152edfb123e88ba04c6272b44294b0c460880451ad7b3868cc6a +89d8ebfb9beebc77189d27de31c55f823da87798a50bca21622cbf871e5d9f1d3182cf32ee9b90f157e6ce298e9efccf +afd00a4db4c2ed93cf047378c9402914b6b3255779f3bb47ded4ab206acb7eaebba0fd7762928e681b1aebcfee994adc +a2e49b6cd32e95d141ebc29f8c0b398bb5e1a04945f09e7e30a4062142111cd7aa712ac0e3e6394cfb73dd854f41ad77 +ae8e714ab6e01812a4de5828d84060f626358bb2b955f6fb99ae887b0d5ce4f67ebc079ab9e27d189bf1d3f24f7c2014 +a3100c1eebf46d604e75ebf78569c25acf938d112b29ccbe1a91582f6bd8ef5548ae3961c808d3fb73936ac244e28dbc +a9a02dcff0e93d47ead9cdddc4759971c2d848580bf50e117eb100cafca6afeaa7b87208513d5f96b1e1440ffc1b0212 +894ab01462137e1b0db7b84920a3b677fbb46c52b6f4c15320ef64f985e0fc05cec84cd48f389ce039779d5376966ea3 +b1e40e8399ee793e5f501c9c43bde23538e3ce473c20a9f914f4a64f5b565748d13ab2406efe40a048965ee4476113e4 +a5a7d97a19e636238968670a916d007bf2ce6ae8e352345d274101d0bbe3ac9b898f5b85814a7e4c433dd22ac2e000ff +b6394c43b82923231d93fd0aa8124b757163ba62df369898b9481f0118cb85375d0caac979a198ece432dbb4eb7cc357 +82d522ae3ff4fe2c607b34b42af6f39c0cf96fcfe1f5b1812fca21c8d20cece78376da86dcbd6cdb140e23c93ae0bcb2 +b6e0d986383bc4955508d35af92f2993e7e89db745f4525948c5274cfd500880cb5a9d58a5b13d96f6368bb266a4433e +b0b4325772ec156571d740c404e1add233fb693579f653b0fae0042b03157d3b904838f05c321d2d30f2dbd27c4d08ad +ac41367250263a2099006ef80c30bac1d2f25731d4874be623b6e315c45b0dc9a65f530fce82fb3dc25bd0610008c760 +b6c0b1ed7df53da04a6f3e796d3bfa186f9551c523bc67898bc0ecfc6b4a4a22f8c4d3bfc740ebf7b9fa5b0ea9431808 +8e78fca17346601219d01e5cd6a4837161a7c8f86fe2a8d93574d8006da5f06ae7c48eea7d2b70992c2a69184619663c +a21f91f47e04fafbfafacf3185b6863766a2d0c324ccac2c3853a4748af5897dbbe31d91473b480f646121339c9bae2d +a464d68786ab1fc64bd8734fce0be6fbe8dc021d3e771ff492ada76eedff466577c25e282b7c8ab4c1fd95ef5ff3631e +829a24badc7714081e03509ccfb00818ce40430682c1c0e4a399cd10b690bda1f921aabcbf1edfb1d8a2e98e6c0cedd6 +87ccf7e4bbcb818ef525435e7a7f039ecbb9c6670b0af163173da38cbdb07f18bc0b40b7e0c771a74e5a4bc8f12dfe2c +94087bd2af9dbeb449eb7f014cfbf3ee4348c0f47cde7dc0ad401a3c18481a8a33b89322227dee0822244965ae5a2abb +896b83ed78724dac8a3d5a75a99de8e056a083690152c303326aa833618b93ef9ec19ab8c6ef0efe9da2dbcccac54431 +821e6a0d7ccf3c7bd6a6cc67cde6c5b92fb96542cb6b4e65a44bbc90bbc40c51ff9e04702cb69dd2452f39a2ff562898 +b35b2096cda729090663a49cb09656c019fef1fc69a88496028d3a258ad2b3fd6d91ab832163eaa0077989f647e85e7e +b7857ef62c56d8bce62476cdb2ab965eddff24d932e20fc992bd820598686defe6cc0a7232d2be342696c2990d80721a +b343d974dfda3f6589043acd25d53aecf7c34b1e980ae135a55cda554ff55e531bc7c2dfe89b0d2c30e523c7b065dad1 +8d139e16a73cd892b75f3f4e445a10d55d1118f8eeafc75b259d098338419e72e950df6ca49cb45677a3c4e16fb19cdc +817b8535bd759da392b2c5760c51b3952ecf663662a137c997f595c533cd561ed7e655673c11144242160e41d1f2dd71 +817ee0f0819b0ccb794df17982d5b4332abff5fec5e23b69579db2767855642156d9b9acccf6ceab43332ccc8d2744dc +9835d2b652aec9b0eba0c8e3b6169567e257a6a3f274ec705dbc250ee63f0f8e4b342e47b9e0c280c778208483d47af8 +b78c40177f54f0e6d03083a4f50d8e56b5aafdb90f1b047bb504777d6e27be5a58170330aee12fbaa5f1e9d4f944acfc +ab8eebacf3806fac7ab951f6a9f3695545e2e3b839ca399a4ef360a73e77f089bb53d3d31dbd84ddfde55e5f013626e0 +96c411fc6aecca39d07d2aff44d94b40814d8cfc4ee5a192fd23b54589b2801694d820a0dd217e44863ccff31dda891b +8249c424a0caf87d4f7ff255950bbc64064d4d1b093324bfe99583e8457c1f50e6996e3517bf281aa9b252c2a7c5a83a +acf6ed86121821a3dd63f3875b185c5ebe024bdb37878c8a8d558943d36db0616545a60db90789c0925295f45d021225 +a37f155621a789f774dd13e57016b8e91b3a2512b5c75377ec8871b22a66db99655d101f57acaecd93115297caabfc21 +92e60ee245bd4d349f1c656e034b1a7f0c6415a39ac4c54d383112734305488b3b90b0145024255735e0a32f38dba656 +acec614e562ccfc93366309cfdc78c7d7ee0a23e3a7782a4fc4807b8803e6ebfb894a489d03e9a3c817ff2ec14813eba +b912f9dd26ed552cb14b007b893e6ed2494d12517e5761dbeb88521270144f8c3eb9571a0ad444b30a8a65e80bd95996 +8375408dae79c547a29e9a9e5d4ec8241b36b82e45e4ca3b0c36d2227c02d17bb171528d3778eac3bbdc75d6c4e8a367 +8c2d0e6e4406836da112edbbb63996408bb3cda4a2712fd245e4bb29a0100fdc89a2746d859b84a94565bc1cfa681813 +a7431bf59e111c072d28c97626cd54fcdf018421d053a787d2aef454b91251ee8ff9d3702d06b088f92b9ad2bbebff15 +8f3659b0fbeb90b7f30b7a49233325e806551a32911a654dca86e290b314483bbb33fe6482387bc48c35d85c1dd0441c +8dca5ba23f0bb76f7dacabf12886053552ba829a72827b472a2f01e19a893155cdce65f1fb670000f43e8c75ba015a31 +8c1514c083c77624eeb5d995d60994a2866192e15c4474d0be4189fae0e9dbd62494ebb4c02fbc176b53be548abbc5a1 +80498d2ed153381baf3b0f81da839ed0eea6af5796c422b8e59be805dba48c4395bb97824ac308170bb4f14f319c5ddf +84f5ebc3bf96362457993e9fa31493c31c4283075e2403f63d581b6b0db8a3df294b2085643f2007f4de38cb5d627776 +958e6e38774da518193a98397978dbc73d1c3827b4996ec00b4183da2c305a187a0ada9aa306242814b229a395be83c9 +ab8b8fbf73845615e7fab3e09e96cc181159eab09f36b4c1239b3c03313c9aeb4bbb51e16316fe338b2319ed2571b810 +977e4e33b33bd53394e591eba4f9a183e13704c61e467d74b28f4ad0b69aa51501a5221cb1e0e42bcb548ca518caa619 +a9bb7ecb9846cc30d04aad56d253c3df7004cebb272f6adf7b40a84adef9f57291e0d08d64c961b9fc406cdb198aab9b +8d2b72dc36406a545a9da44e1fddfb953d4894710ca026d6421a4ac91e02d0373a599f2acfe41d8258bc9679cf6f43d3 +904192fc8fe250f61ecb8a36abbbccae85f592bbf00c10039c30b5a1c733d752a04e4fd8a1000c6578616f8a16aa83a3 +87f5fdfe20bbbf931b529ec9be77bbfcc398cad9d932d29f62c846e08a91d2f47ae56ad5345122d62a56f629f9a76c4d +84cc3a53b2e7b7e03015f796b6cb7c32d6ded95c5b49c233ac27fafa792994b43c93cda6e618b66fce381f3db69838ba +aab58da10d7bbe091788988d43d66a335644f3d0897bbc98df27dcc0c0fcee0ac72e24f1abdd77e25196a1d0d0728e98 +a10ea8677c2b7da563d84aa91a314a54cab27bb417c257826ebdd3b045d2a0f12729fe630bbbf785d04874f99f26bee8 +acc4970ef2a4435937a9b8a5a5a311226ca188d8f26af1adfcd6efb2376a59155b9a9ff1cff591bde4b684887d5da6e5 +8dc7cf6fcca483c44eb55e7fb924bf3f76cf79b411ae4b01c6c968910877ac9c166b71350f4d935f19bdffb056477961 +ac2dd1182ded2054c2f4dbf27b71a0b517fb57193733a4e4e56aca8a069cff5078ffd3fd033683d076c1c639a4de63c7 +932ec87c450cd0dc678daf8c63cd1bf46124fa472934e517fbbfb78199f288ff7f354b36e0cc6c8739d3f496cfe0913b +b0d631ced213e8492be60ea334dbe3b7799b86d85d5e8e70d02beef3ae87b1d76e1df3bdb5f7ba8a41904c96f6a64455 +929d7239ead7575867e26b536b8badf2e11ca37840034d0e5c77039f8cce122eff5a1bf6e0bcadde6b3858e9f483d475 +aaae5d372d02ee25b14de585af6fbc48f2c7cd2a6af4f08352951b45aa469599eff41e820df642ca1a0f881120e89dbe +b23c411741a6b059f04fa4f5fd9dd10e2a64915f2de6ea31e39c32f2f347a776a953320e5f7613fcb1167efe502f5c5c +a4581b0ae633fe29c6f09928e5efb16db019eeac57f79fef2fa1d3c9bee42ce0e852bc60b9d0133265373747e52a67a4 +81b33afffd7b2575d4a9a1c5dd6eee675c084f82e06b9b3a52a3c9f76e087f12dca6e0ffddc42fb81ce1adb559d47a38 +89cc890f06b424591556aabdfdbb36d7a23700425e90c9cfed7d3da226b4debe414ac5bdf175273828ce6c5355712514 +a4399438be75cfae2bf825496704da5ed9001bed8538d8ac346c8cf0d4407808e9ee67573eb95fe1c6872ac21f639aaa +ad537f7ce74a1ca9a46fc06f15c1c8a6c32363bd6ac78a3c579ed8f84252e38a914cac16709fe65360e822ef47896de4 +8e53b69f5e3e86b86299452e20ea8068b49565d0d0ab5d50ce00158a18403ae44e1b078a3cfd3f919aa81eb049a30c6e +a59f2542c67a430fd3526215c60c02353ee18af2ff87cb6231a2564fe59b8efec421f18d8b8cc7f084675ecf57b3fd05 +b8d9bac93ef56cb4026dd1c731d92260a608fd55b8321e39166678e1dab834d0efddb717685da87786caeb1aaf258089 +aa2df56f4c6fe9e0f899116c37302675f796a1608338700f05a13e779eb7cf278e01947864a8c2c74cc9d9a763804446 +b0108ff2e327dcb6982961232bf7a9a0356d4297902f4b38d380ff1b954bfbcae0093df0f133dd9e84d5966c7b1aada7 +b06b813b01fe7f8cf05b79dc95006f0c01d73101583d456278d71cd78638df2b1115897072b20947943fa263ddab0cd6 +aa41e6c4d50da8abf0ea3c3901412fe9c9dff885383e2c0c0c50ed2f770ada888a27ea08bbb5342b5ff402e7b1230f12 +a48635dbb7debac10cb93d422c2910e5358ba0c584b73f9845028af4a763fd20da8f928b54b27782b27ca47e631ebf38 +80a574c208e994799e4fa9ef895163f33153bc6487491d817c4049e376054c641c4717bda8efbeb09152fa421a7268a7 +b592bfd78ae228afc219c186589b9b0b5c571e314976d1ed5c1642db9159d577679a73c049cfc3dcfefcd5a4f174eeea +aa1f08af3918c61eadf567a5b1a3cdcdfb1b925f23f1f9e3c47889762f4d979d64686ce1ce990055ef8c1030d98daa3b +857df4cfd56d41c6d0c7fcc1c657e83c888253bae58d33b86e0803a37461be5a57140a77fb4b61108d1d8565091ada1c +8fae66a72361df509d253012a94160d84d0b2260822c788927d32fd3c89500500908c8f850ef70df68ddaeb077fd0820 +aa1dbefc9aef1e7b896ff7303837053c63cfb5c8a3d8204680d3228ac16c23636748fe59286468c99699ae668e769a0c +b64b1cb2ba28665ed10bad1dddc42f3f97383c39bad463c6615b527302e2aaf93eb6062946d2150bd41c329697d101be +b6d35e3b524186e9065cee73ea17c082feff1811b5ab5519dd7991cdff2f397e3a79655969755309bd08c7d5a66f5d78 +a4dae7f584270743bbba8bb633bdb8bc4dcc43580e53d3e9e509ff6c327e384f14104b5bdfe5c662dc6568806950da37 +aae84d3d9ad4e237b07c199813a42ed2af3bf641339c342d9abf7ebec29b5bd06249c4488ce5c9277d87f7b71b3ddd37 +b82a463cf643821618a058bddf9f2acb34ac86a8de42a0fa18c9626e51c20351d27a9575398a31227e21e291b0da183e +8b6c921e8707aded3ea693f490322971b1a7f64786ef071bc9826c73a06bd8ae6bf21bc980425769627b529d30b253ce +80724937b27fc50f033c11c50835c632369f0905f413b1713a2b0a2274bec5d7a30438e94193d479ba6679dbe09a65ef +a1d9b259a2ca9cff8af6678b3af0a290c2f51e9cf26d5fe3c6a4fa3d28cbf33cb709b7f78b4f61cb9419427983c61925 +96a3e69a5ed7a98ce59c4481f2ffb75be9542122ad0eb4952c84d4536760df217854d4ec561ce2f4a79d3793c22fa4f4 +990c4d9a4a22d63a8976d34833cafc35936b165f04aed3504e9b435f0de1be4c83b097bbaa062483cf3dee3833b4f5b6 +b9bf5e4b270aec4a0dc219457b5fed984b548892c4b700482525ba1a7df19284464f841dab94abfabcaa9a7b7a757484 +acaecf49cb4786d17cf867d7a93bd4ffee0781766e11b5c1b29089ae0024c859d11b45828fbff5330b888543264d74a9 +b0e1a0865b1e6f9e4a0e31d0c885526ac06678acc526fda5124742a2c303bd0e8871a0cb7951ec8ed9540fc247c8d844 +82b3d327b3d1a631758451e12870816956cd0cef91fcf313a90dd533d5291193a0ff3cc447054564ce68c9b027a7ffd7 +a2843602abb98f0f83e000f3415039788da1e9a096bfe8fed6b99bab96df948c814560424ffebe755cb72f40436fb590 +ab1c7b43cf838798d1e314bc26e04fc021e99a7bfbfc8ffde62fa8d7f92139de86a377289d5177021154229de01ede15 +95e5cf5dd87ae3aed41b03c6c55f9dfad38dc126b17e7e587c156f7745c8da0bd1d60acb718fc1a03b61344f01e3de4d +86f021a3762bb47167f80d4ef1b1c873a91fe83409f9704f192efeebbc3ece0729cd2f92f63419907ea38ae47bc907d2 +aaa1445dafbbcd645d4332d9806225e9346ee5ac6b22ad45e8922134fe12f3d433f567a6a4c19efdd9d5775a7de1e92f +8fd7e15688eef75df7b8bca3d61bc9fca4f56e047cdb6d0b864e7d1c4966eac27d6094b0c8482b49739f83ec51050198 +80aab8b4d394eb011d4ec6a4c2815617308c9b847c6fa6a3d7e6af1c79420ef6ff2a13934a398581c40ee4cf1cac02ac +8970b97ac076a1d8a321ce00eada0edf974a46bf3cc26f6854e4218cdfc8d2b0c32199d9658f254b4fbae5a2c5535f41 +a1aa2ec5b03df0a630e73dd048680ed6d3032c324941423f45cd1f16038789e5e75b876a13948732e9079a422f66a9fc +b5fe5f5e2f2ae2beeb8e95859a02fc45f01f9fb0ebb2bd8ec9ec976b3e806228821a9775096d341d662bc536c4d89452 +a2bc1f170b62d0d5788b02391337b2ab157c38e725694e80aeead7383e05599be0e2f0fa27ef05db007061809356e147 +a8a69701d4a8d0d972390e9f831fd8e9f424b2c2ef069e56bd763e9e835b3ce5f7cf5de5e5c297c06ace4aa74df1067c +b43d551af4ff3873557efe3f3fb98e5ede9008492f181f4796dd1a6bcda8b9445c155e8146966baa812afae1abe06b48 +b4b1dae44fd596813f30602ab20e9b1fb20cb1bd650daacc97b7e054e5c0178b8131d439a9e5b142ca483cc012a362b3 +b95b8a94c30a831eaaebea98c65cc5d0228c78afd6603d4aa426d8186aecc951f1a11c33951f51df04c7e6fa43ffb5ae +b100059624cf9db371bec80013a57a8f296d006c139a8766308f1ea821c7eccc26cad65bc640ab3f6cef9062653bf17d +8e5a2cb76716e0000d13bce5ef87acac307362a6096f090f5f64e5c5c71a10fddfdee8435e7166ba8c3ad8c3f540f3e4 +93d2c43e21588c1e83c4255c52604b4ac3f40e656352d1827e95dd5222a45aebff9674e34fbbe7ed21eca77bd9b8dcbc +8aeaed611546bb9073b07512a9a1f38a7f436ab45e11775a0f9754baaf63e9bcc7bb59b47546a5ded5e4ba2f698e3b5f +af9e6792e74a1163fe27612f999a2f3cfa9048914c5bef69e3b2a75162bb0ce6ece81af699ad7f0c5278a8df0ba000d2 +850bf2d5d34791c371a36404036ad6fdcd8fb62d1bb17a57e88bda7a78ea322397ce24d1abf4d0c89b9cf0b4cc42feb3 +87f7e2a1625e2b7861b11d593aaac933ed08a7c768aebd00a45d893ed295bbb6ed865037b152bb574d70be006ddc1791 +8dcce8f4ad163b29a2348ea15431c2c6ea1189ece88d2790e9f46b9125bd790b22503ec391bc2dee8f35419863b2c50c +b4bf5266c37f12421dd684b29517982d5e4b65dfdfba5fc7bd7479fd854aabf250627498f1e1188a51c0a88d848ec951 +8651623c690247f747af8fdffdc3e5f73d0662bc3279fa2423a3c654af9b6433b9e5e0155f1ce53857e67388e7e3401d +b155120f196d52760129dde2e2b1990039b99484cdc948fa98095cd23da87679850f522e5955eae34ac267d2144160d3 +aec8115e8d7b6601fbceeccf92e35845a06706d46acd188452c9f7d49abef14c6b3a9a9369a8bab2fd4eb9288e2aaca5 +998a8ca4dc0f145f67a8c456f1d6a7323c4836fe036dcbb0f27eb1c596d121eb97369638a9908cfaf218c7706f266245 +b235fbafac62802742ee3d26b1f4e887f7d2da4d711ba7f9bb6ca024de7beec1de66bb830ce96d69538f7dcb93c51b26 +9258d2ddc21ab4e3edcde7eb7f6a382a29f1b626003cc6fdd8858be90f4ad13240072d8a8d44ef8de51ca4f477fa6c45 +99d038487821c948142c678acd8c792960993dd8cb5e02cb229153a1ee9f88249f4ad9007f08e5d82e2a71fb96bb5f32 +a88ee9dbc73d3d8e0f447b76fdb3a27936bde479a58d5799176885583dc93830ac58bca9087075950ea75100cf51af23 +88b9b15816e5a0387153c1f4b90f613beb3ea4596037da01a81fdd2bcbd0baf5598db99f77e7694e5a0d35e822758108 +907ae4b637d06b15846ee27d08c9c9af42df261c5bdd10cf5bc71f8e5ca34b33ac2405307023c50bdb8dc7b98a2cd5fe +9393d6900e1d2d1a1e42412fefd99578d9ac1d855c90a3e7930a739085496448609d674ca9b34016ad91f22d1cac538e +a28ac56b216730b7dcdb5ab3fc22d424c21a677db99a9897a89ed253ea83acfd9d83125133f5be6d9cd92298df110af8 +b027590ee8766f1e352f831fda732adbaf77152485223ad5489ef3b0ce2d2e9f98d547c111fe133847ebb738987fb928 +a9cc08fbd5c3fee8f77cf6eb996a5cafa195df5134dab000e4d0312f970a5577942ee89794e618074f49841f1f933a42 +a8b3535c3df0b1a409d3fc740527ee7dd5ac21756115cde6f87f98cc7623f50cfcf16790689cab113ee7c35a5bd4879f +b61420227b97e5603ae8a716c6759b619f02b8fdc48acbf854352aa6519dad74b97bacc1723ca564cbf3ca48539ed773 +853762498de80eebf955a6c8ddd259af463e4e25f0b6ba7b6a27b19bdbf4c585de55760a16e2d9345cdba6b2a02610f3 +a711c1b13fc6c30745203c5d06390e6c82bd7c50f61734aa8d99c626faba30119bc910be63ec916c91ba53f8483c05a8 +b488c0a793f4481f46b5875d96eecd73e46209a91677769f0890c5e002ecd7d4b1c9f4ba68c47fbed40e3857b1d8717a +a651c5e812ae65b1c66d92c607e80be330737ea49c1dcfe019c0ecea0f41a320406935bb09206a4abff0d1c24599b9ad +85e34e7d96e4b97db98a43247b6c244383b11ca10bf4777364acf509a6faa618bc973e2136a4693fbc8ab597e308fd5a +99837214102b394fffa7f3883759554c6bb7a070f5c809303595a44195e02b9a169460dc6bbffb62bdc0e7ced5f0a5c1 +a952f89c0afb4bdae8c62b89cc3cfb60d0576ba4fe01a5d99534792f38d8848d919b3fc7577435d8443a044d2ee0bcfa +a1ac1f81acb29798acdfc493854663519e2d1b0e9d23d286ce33882c34b4c1c0bb43dd9638166d8026315a44d9ec92a8 +ac9c58aa38219ae659d23007cc7b97fd25b7b610b2d81a8f9f94ddb089efc49c049a8ea4c56e6eaf7b6498f422a97b3c +87e61d501c242b484fb9a937ef21d485f6678d75257fc8fe831b528979068cadbe7e12b49c34058ec96d70a9d179ab14 +aa45f6852f35cc8b65a4a8b5380641d2602a4fa4e3a035db9664df3ac2e170b1280c4a8b7b55161430063e54de4158a6 +a46975614ddde6d134753c8d82c381966f87203d6e5a5fb99a93b0d43aa461466b37f07b8d0973a1abd6ee2b40f24348 +8d35f97297773422351f4d99564c1359ef1a10cfb60aa0e6c8985a78f39b4268486312c8ebf9dd2ef50a771aa03158eb +8497c6242102d21e8b3ade9a9896c96308ab39171ab74cbd94e304c47598e2c2a7b0a0822492ac5c076ba91d4176481d +973f8fcb5f26915b3a3ef6fe58cc44bc7f4e115cd0ad9727d8d1b8113e126ae2e253a19922c5433be4ab2311a839c214 +ae3ee9f1d765a9baf54b4617a289c3b24930aa8d57658a6b0b113bbf9b000c4a78499296c6f428bbb64755dfd4f795d2 +a5be7a8e522ef3dcf9d2951220faf22bb865d050f4af2880b8483222ff7aad7c0866219fcc573df9d829c6efbb517f98 +a5f3c7fabd7853a57695c5ad6d5b99167d08b5414e35ed1068ae386e0cb1ee2afbbe4d2b9024379b6fc3b10c39024d36 +978d5592d4798c9e6baceff095413589461267d6a5b56cd558ec85011342da16f4365d879b905168256f61d36d891b1f +b7b6eaffa095ecbd76d6e1e88ceebabaf674d9ef7e331e875c6d9b9faa1762c800ff1ea597c214c28080f67a50a96c1e +8a1ab53ae5ceaa42e06e58dd8faf6c215fc09ba111ca9eeb800612334d30d5971448be90fec62ed194328aadd8c8eecc +a9ca532cac8ace9a9e845382f8a7840bf40cb426f2fcad8a2f40aadbb400b3a74021627cc9351b0966b841b30284962e +8dddeda8854c8e7ddc52676dd1d0fed1da610ed5415ddd7d25b835bd8420a6f83d7b67ec682270c9648b2e2186343591 +888906aac64fd41d5c518a832d4e044fdc430cfe142fd431caf4676cafc58853ce576f098910d729011be0a9d50d67b5 +96a3f886a2824e750b1e2ea5c587132f52a0c5e3ff192260d8783c666206bd8ebd539933816d7cdd97e4bc374e0b1edf +a150a29ffb2632cc7ec560983d9804cd6da3596c0c25956d27eb04776508eae809659fc883834269437871735de5f9ed +81f7ad4d2959d9d4009d1dfbc6fee38f930f163eb5eac11e98dc38bd2f7f224e3f5c767583f8e52d58d34f3417a6cf90 +97ccac905ea7d9c6349132dd0397b6a2de9e57fd2d70f55e50860e019de15c20171a50b28a5c00ef90d43b838253b3d1 +95694f00c21e8a205d6cbda09956b5b6ec9242ec8c799a91f515b07dcc7de3b6f573e2c0ba149f5a83700cda2d1df0f5 +82bbc3c4a3b3997584903db30fffd182a266c7d1df3e913f908d5a53122fa12cf5acd11d915d85d5bd110fcc43cee736 +8d3f24b4949aa1b4162c28dfbb9f813dd1d8b330f71325448dc45ea34d59b69ca95059402aae011e1b5aba6e536bc6ec +92c734c19752d24782331e74c9af97a8399ddfdd32954e91cda7363dba876aca4f730b451c50a8913950420682da8121 +8653d2c79f77b8c7dcdf7e8dee42433998aeedf1b583abfca686d47a854de1b75e9a4351580c96d1a2a9532659203361 +886f0e414cb558c1a534a1916d3531320a9b6024639712ffe18164ce6313993a553e2b9aafe9c0716318f81a5d0bb1da +b31b5efaba5a5020c3bcea0f54860e0688c2c3f27b9b0e44b45d745158f484e474d5d3b1a0044dd6753c7fb4bf8ace34 +b2d615bbdfdc042d6f67a6170127392d99f0e77ae17b0e1be6786ff2f281795f1bf11f83f2e0f8723b5cdd1db1856e09 +a6e014cca531e6ac2922239b5bee39d69d9ba6d0fa96a4b812217dd342657d35606f0b9c5a317efd423cdb1047815e3d +a8921736b69c9fbb29f443715174bac753e908251804620c542fad6cfbfda7bdfe287f2902f30b043a8a4b4818cfdeef +8d73a9949a042ec2dcefa476e454cd9877eee543b1a6b3b96a78ffcff87421e8b26dd54d5b3192ac32073cb36497acc3 +b936a71ee8df0e48867f3790adf55dc8efc6585024128de2495f8873bd00fd9fa0984472125e801ed9c3cdce6698f160 +82f69c06209c28f64874e850601dda56af44ffc864f42efa8f9c6a0758207bf0a00f583840982dec0a517ab899a98e5b +b7a0a14411101473406f30e82f14b13e6efc9699e7193c0be04bb43d1b49e8c54812ce0f9b39131a20379c4c39d3bbe3 +81159c969f38107af3b858d7582b22925a7ccced02fae3698482d7e9cdc6c568e959651991c6cf16c53a997442054b61 +8bf1116a206e0ce9199fcab6ed2b44a9e46e8143bff3ed3f1431f8d55508fe2728b8902670cfd8d9b316f575f288ed9d +a279b2149824b64144eb92f5a36b22036d34a52bd5a66e5da4b61fbc95af6eda8e485c7914f448abd8674fc14d268d9d +8b98279b5f3588d1a2f8589d2756458690a502728800f8d94b28e00df842a101c96ab9c5aee87c5bbe65552c0c383b80 +b4a27a351ec54420f94e0a0a79d7c7a7337940399646631baca93eeab5fd429d7fb39428be77dcbce64a13eaa3c8ca1d +90c08baa29ec8338ffce381eae3d23ce3f6ba54e5242dec21dc3caaed69cac13f2ab5e8d9d719bc95720fa182eee399c +85156d65bb4fef69ffd539ab918b3286105ca6f1c36a74351ab3310b339727483433e8f8784791f47b4ba35ca933c379 +923005013c27209d07c06a6b92b0cbb248a69c5e15c600bbcc643e8dcd2402adebd94dd4cafb44ec422a127e9780aaec +863b23eb5463a6ef5a12039edc2f8e18e3c97b244841bc50af02459b1bcc558367edf2f6e4fe69f45f37887469dd536d +87a4a7708a112724ff9b69ebb25d623b5cae362ae0946daed2ec80e917800dbfcd69f999c253542533242e7b9a5cc959 +8bf4347ceea7f94b53564f26b1a4749a16f13bf71a9e03a546f906f7c423089820ff217066159b0637d9d6824e9c101c +ab07eef925d264145971628a39e4dd93ff849767f68ed06065802cf22756fc6bf384cf6d9ab174bfc1a87bcc37b037aa +8e3f10a42fad43887d522dc76b1480063267991c2457c39f1e790e0c16c03e38a4c8e79a0b7622892464957bf517ebd8 +a8722fc7b1acf0be18f6ddf3ee97a5a9b02a98da5bc1126a8b7bf10d18ee415be9a85668eb604ef5a1f48659bc447eb5 +878d6b2a9c0aca8e2bc2a5eb7dd8d842aa839bbd7754860c396a641d5794eab88a55f8448de7dbddf9e201cbc54fe481 +ada881c167d39d368c1e9b283cf50491c6bfc66072815608ba23ab468cfbd31ca1bd7f140e158e0d9e4d7ebfa670bc2d +a2b48578fa899d77a7ee1b9cb1e228b40c20b303b3d403fd6612649c81e7db5a7313ba9702adc89627b5fd7439f8b754 +8e051280e10551558dcb5522120ac9216281c29071c0371aaa9bde52961fe26b21d78de3f98cb8cd63e65cff86d1b25c +a7c5022047930c958e499e8051056c5244ae03beb60d4ba9fe666ab77a913a067324dfb6debcb4da4694645145716c9d +95cff6ec03e38c5ab0f6f8dccde252d91856093d8429b7494efc7772996e7985d2d6965307c7fdfa484559c129cca9f9 +993eb550d5e8661791f63e2fa259ab1f78a0e3edad467eb419b076a70923fede2e00ddc48a961d20001aaae89fad11e8 +abb2826e4d4b381d64787a09934b9c4fe1d5f5742f90858228e484f3c546e16ee8a2a0b0a952d834a93154a8b18f3d16 +a922ca9f2061996e65ef38a7c5c7755e59d8d5ce27d577abcdd8165b23b4877398d735f9cb470a771335fc7d99ecb7fc +90f22862216f6bc1bbf5437740a47605d1ff5147b1f06f7b13fec446e4c5a4a4a84792cb244a1905f3478a36f8d7065b +87f3d9a86afef5b79ea1ca690ee1ee4bb9754b66f7c50a42ad6b99af7c222c853ca161f440a0a2a60b3b5a54e3493240 +80a9ca9a2d33b9cf61976b3860d79f5d00de89a06ef043d2a52931809018aeb4ce70423cbef375b29c2c750c2c8704c2 +b4e798ef1d615896108dae37ac50c1e859216ab6dbac11653e44d06ce5209057b4b0dd6d31dcfcda87664a23c8ef1cbd +aaed6d1e7c5b1db06f80dae6c24857daadfb0268f20e48a98fba4b76de1ebf65fb84c3be95fd6a418b498f8285ec63bd +aeceaa316c6369492c939f94809bc80e0857abac86c0d85be8066bbf61afbaaec67e28c572437a8d35c49dd596b3134f +b791c3d53ed34a7d1c8aa89b7953e3684c3cd529230824dc529739a5fbe74b58b87f01e56e7a169f61c508237ef67160 +9351f8c80634386c45c0050d2f813193f9d839173be941e2092d729be5403632a2f18dffdc323d69eb0dc31fa31c5866 +97693184d5c0056ae244dfb6709cafa23a795dc22d497a307a7f9cf442d7452024023c54a8d6bda5d90a355ba2c84f3a +85362daa003d23511ca174a8caafe83d52b6436dc4e43c4c049e5388d9211b5cbef3885896914d86d39be0dd1f910511 +a2511b5fa34b24eeb0e1bcbcf872a569d1ff5570fe7b0fb48f5542f7fe57bad808d34b50afa87580866a6cb0eba02f27 +b382e3327eb1401f2d378dbb56ac7250adde0961bd718575a64d264ffd44772c20752d4035c3ba60eb435e160b375e20 +afad8a5d40b536c0720556845a6b257ed42165c14fb4b4a874717d107752f49ed9380c5b048df3aca67287bb8fc411a8 +8fad0c98434ca5373c2d767868f679b76b4a8d04bca8240ea3f388558262c2d61b73b16fc1160932652b5688c25fffcf +83898008b5cbb6f08f8ef3ec179427869682bb4e8d38f6e6a687a214d4a307436afc64ee67d70a5a8ba9730bf839aecc +b85232e79913785fd82b06890706972b4ad7a309489930ae23390d51aa5189731f8a2df24800409a8c36b3dd6fc91275 +a24ff26ec792f3701da4c5638c1fca4fa4dae95b01827d6200d583c4caf17ea3171393ba2a8c23d1ee8b88402916f176 +adc5c7a7ff6b41d6cc386b7fc69d7bb04179bdf267864f9aa577f0f6a88438191fa81ebaf13055c2f2d7290be6421ace +a05e835abd502d31454d40a019010ff90b6b0b1f993075a35c9907aeab7a342ac0ba6144dc9379aada6119157970e9b2 +85ff07ba58463e7f153fc83f11302e9061e648a5cbd272bb0545030b20e11facd8b3ff90c9ac8c280a704fbda5c9d1b0 +a6c735ada8f4587da8cdad7ea3ada01650b5a3ecab8d81daa7a5f5de51ef4a6592b524692584306f06be3f6701f2870c +b138deee4e53ae8d677fae104f713ef1b8babfecec16b6a85785a66a72784eb09d44c3b63567222ade714e98f7d1604e +ae79c1a49dafcdd972acd95d8ad0a35c02adc7fd736d4c44c3cd13df5789d339b5ea16bddbbd43e486a061ab31baa5c0 +ab3cf2371a1d7dcd0ffe3869a0178230964b06694bf258b2073ea66a2afccd845b38485da83d02e1d607d4c5c36b78a8 +ab9609f28a325fd01cb39540e3a714506c44e52ef28ee640f361deb5760aadbb23e804663b0fa20a66e239c33f8d8bb8 +8ed95ea8e76e1b42823d7915a6aae77d93746f846bf602841dfce0e47543a36efb9ee7e5b42c73c3209d911225cc471b +a80b6162036d43811482323f0ce59eb18740e33a63d7c7bbbf3be206985919e5342d53a69df537d43e8b7d7f51e8892f +93c03d0a5083408ba00c125a8a9385213d4c860072f0297857b1235045819b904e07f2425c13a661d0a01d2e53347f4b +a6581200f00f96c461621e1d26b14a23687dd97eb9f7df4ba641a84340ee7306dc1796248fba4804f185947ad13b4385 +8be174018fa40f7e0cedc5ae68f38969eb7695f2205e9c573641e533d56f68c20abf38a23d2f0dcac371e60b21b18615 +857ad4ee3218c647c58f09b8ab22bcc8976f00a768ab1f708618e868e6143474be846422ce2710a0ed39b5155b6f13a1 +a490bec40f322d599f26bcefcdddd8f2ef6576aa737d5ce7e8d5d422741abe749e3e6a48489aed8c560633f72857e3c2 +a9c0ee339621f1c4a2410f9b4d2f03f1b558dae2973807b8bccd920e8feb7f65dfde3e79986b72ad21fcc4567240381d +8592251568e750a430f7d2c6ddbb3ec82a4dd9fd83efe389e69aa177fd97ac2c96c59a6e86db20d8e6f125d65b46c4d3 +a4e2f4aa6a682913b423b097c4069c4e46a1f3af9556b1bfd0580d0fc01e3991488458049e0735b2a629684a79271c8f +8c4f6a3e738cf74112b08b1680be08158013ef8a515a81215d8a36c9b756786d1b4cb4563923463f3329292f4b48bf6d +8bace547353c02ea00dd547eeda7259aa354d4772dd5e0c486c723cf88627b7112e196b879c3c92a9561b674d9fc486d +8d372f4901e25e8db64fa098148d4a4e709b0e9dcb756d0f90dad99dea393054193ae1a33d292a3dd772ff7ba05e4b71 +a8c7ea6a6a031ed23d65639f01f5423190775558f479700597df7ae7e338a6ae5e9b32f470aff20787ac8b7eec84df6c +b6e9dcba240fdbbf66033410a79a2dd3e9e1ffdf2eae949b3a9ed720e939d92339991dc3e70a5ac7d5253f317daf0b7d +974dec4cd61af75721071752c664d9c2a5121f06ff1515c56139a177a3ca825f763b69d431d4607e393fa74dcc91cc58 +958863e6ad583a9d370a6db3639066982e44766904e7afa849b132f6666b7d08ab931131b3bec7a506d6583e93d56767 +8b93a33b5da9b3300c20a96d80b894e3789c77041183c2cb21751579c8c96857f60cfc2f075201b64e95a78985c5b321 +b726cb9f7ef34ddbc2fad82b3b0af0b30cc913e26c5a614ae5c19cc9c55c8e6dae069db5315a8dcb6d987415bb550ca8 +a730f515398a71bddd66cab2ff996659d4e47dfbb08ce7958a41021f76d269b91c7498b708cd14b183a8ef469c772803 +a4eb3b18132eb0f5337f14e01d63ca0bec0db6a43870f800e5491db756c2f5fce519d8dba5528b4bcef550d06b33699c +b1ab6621eec1ee6784e632e214693f39a14f3715991996b883d66200963e065c86fa0667f7bc36b93b40b5d90ff708c2 +80486a26c3532ad6e19f76d8c9344e2626c07363fd495264927cb5935fa9565ece670dc98767afb04af6a9a5c9231075 +8ee20e0df3c84a1c6b0e21bcc325cf99235b747ffe47f17fdfba548a358ca75cbcc331dd50db2311b400ae882256a608 +aef4268959e5541e7ec69c921a1e81a8374d7e44bf1bb2debf4101cf3cd6b7d6ca7f441758b388de96b3e0edb5b97be9 +8793629bd29d689ec94b016de8886cac6e2ca6638911babb22db4a787661422da0639a4e4089ebeb689d173abfe75950 +b487b3551c20a29e9a5abbda8c50ff594826283e443c09e3ae09b914e46060b3f9abf70434444ce1487e2a74e562616b +8f11531cfc5997dd04b997cb87ba1831aa7041d5434fe72de66304e3f165d882fac891391fbb1eb955c65319e65293b6 +b195136875fd02a75676c33cb3e60504d5964f7a9e81f4c8c8fd38af62e2145c55f765b3158664566191188ac678f381 +b374174b0b3eb04fa49eb4ece45173f0db5d829eac370a20a62309566e0f98b18f72f3633626893c053b7be6bfbd2366 +b2a2f6b0cf652775679b2d677048f2ed8c31a3269e6cddcc7a10e3e6fee89e486b50d9d55fbe452b79c4157c0270fb77 +892177c364dc59032594e7a6fd032286ffdf4fa0b9e3baeb37ec839faebfd2fd46c57b2c9bfe9977b59c93a9cc0ead1d +8ab7c0038a7dbb2ef200dbbe9acbc875829ecad4883792d5c6ce283de67ccd9aa935a9cc7b30b2bd9de7fca7bf2a9a05 +83745cfc78ca709835aa6c6a233c2b86fb31e3f9f6a8becf63e501f2841c4366fb7d131b746c9d3291afda714ff05579 +a723dcb67925ef007e8339dc578d2622d9bb77cfda87cca0088854a59414c02338752c56116a6c1281917842e8467c38 +8a098142da0af2254c425fdbbd0d1b1a17b2bd781391ab37f181775524b8563c64ab8a1602aee2ac6c0a82ba11a8b1d1 +b13bd7529a9b351c5d395c794c28bcb0a3167f1c992e8c062eef47be9be27895945231d249c73a0b6949daa295e14944 +a20dcd2fc2222eaae467d9f5db861040f58bcb991a26e5663ac3aa5e1ff13d0010657c5af586cc4621757add2b905073 +b818f660c3cc4e9f273c25ceeabe562c8afa8ff88529c26f2cf45ae6b2813cca5f350e3cbd56f6257c4df41722dabd25 +b225d5987108b24411bc389276f12509a45e86d5ad6b6d929af5274df0be11109c0fed329669a0acafdf3b0beaa8f2ec +91fcb6d04576d3c6bae947bb7843b430e5fb0592ae49b0a65dfa5791f4eaa4bf2c7f436c8de7360f217001c2b4e5c67a +8821f7a1424ca3fdc5d4a5606ad10dfaba6094cf36669fa9f84cf7617e50425405d14980780e1e18a1ecea7913cda896 +990dcb7f38f56521a70cb71bf4522649fcd46ac052c7feabb0748dfcac9f9c0f95d29e070d32af3cd0adbf869535e17b +b0fac1029fe2c1100f24e2f4bf10c7672199fce53513c7dde2e8d9b00702edf0143e0e1dc7ceae7dcc6994edc2422b6f +a514ebb1a33451b4915c05114db0b10168393613744df848b24e43e09f0bda23baefd9d731075198aace586615ac7911 +8b77f7953c2e67049fdca3653b8d8cf3f799677f79b954da02bdad8cc4d6c855c1c7c16b4f6f9ba35f46426ec28b2d84 +875520cfbda16ec5b1d1d00f578a910d0fc052f17870ba093e22e310bb07648d34817cc2b8811b6f52de535f7046a0d0 +b8c77b4be0b430851c4ff69e91cb770db1935d848198601393810ef395efab52deb9d5c6525472bab720273d5e0e7a79 +b6d4d437146671bdea62fb6545395ea3df39f1cdef21b8476b68e7a25aa7354f847740576d6c9f187bbae9941f0ae450 +95c642f1bccdb62cd6a2212dcdd6ff8d49aee426ca08b7cf3a9d15249d24a9eed5533f92a70c84498c0797f8a57efa27 +b617978047ed0f748c305aa7f30c2dacd0db00baa67fe0c5ce346ef0e6991dc7e05f18dcb2702467421f8390f27aa815 +86411c7a00b3e8b43bf22fb061b1f54ad9bbf632cd74395a478218389c0f544668acf3dd7726532d080ca7da9a5f8608 +97bf684a8849626c4710a6992f6c11f6b5406fd4dfe9e6aa502425aaafe9827e2c435aaf9a5d3d2ba3a4c0e8aec79ba4 +8b178e2a125b461d3180906ffba0af3dce614c64058501fdd35243ababf892d6fcdea4834ce42c25d5569452b782a709 +8ebed2c8a25c61da6a6a8cb0d8f5ea179e28869753eacc728f2c076f7aed8598cd3aa0981f120f9e7ea55b3a689ae882 +a6f235b8e655ca3d634740b53d8c0a757ecc75d2b8838b7948997c1985473d01943d935f687b86cee56cd47c8e773443 +a7959c465a9646908b9d8032a589e41a7dd999f2ffc54bb42f22e5f8a4d8c493a31bcc7ea2cac6c8dbcc59acace7181b +96d0532df2e12da20a57cadb6cf5f6c4ee1aa4775629358c25f1d51677a3e96d1fe3b232532324b4f02f941952d4cc68 +90f493473d686b639a30d1ddc9c72eae6e983f1236e162e58e967a477c0654973ea2e1bdf4ba1a44d7247bc1befc2cab +8b2d87876d9c4085102a07ebb41c565ba69acab99ffc03efc18f20e48d3f3bbe4fc6ddab9c78fe479d9ada80504d85ba +829a0fb3200a28e09cacd6c5346000e7786116ddfd898f37dfd17bef454a8abc0fe939ed8735c00769f7f2f33cd4f906 +86194ec9e88ddb7150e8b03e7a535b6e99863fc6762835601efd03615aa97aaeb413cb210e86035086ed852b39c9d019 +b02efd116a7189cb317ceae392bc301ae55470f0489fa89934e182aeb8c67e280299b975786fe9a470bff46827defb9b +87d7c3903bd22b12d815506f150373f518d47dfc6e5fd74347d88b518124c9923d1e4c98defeb3a45d53d50b423e2175 +a1a430406b28254a7d6348bc98e697e9bab43839aa05d53faee97546f84541ea0b559162619b2045182938f69bf61cae +99d243c226c61c6697fb3d2594f3533fa5dfd7cfc87107908cacde337d7a077fa5a9dc702d26081b065edb1227498e65 +800ee5006ab6217161f42db0cfc552a81728bb4fbd7af6e4620ea099a65ef6664184af3f65a07fcec7e965529c5b49bf +91bfd307579cadc8f81009558605be3edbcb8dbba271475803484017f40130b2b216aef4f620d960193be681877d3a53 +96a060459dec458d19a6f8af6e49dc6c7c58c55dd18915c5fce5e0f4b4a422fce3b9632f6059388fe760289abf70f173 +9921a37f3e657222c7fda3588418a9071409711d9f1fccede7494429f02a45fbc52d79fbb64e9ccd518f60d06d0520d3 +81052b0d15773cb75975ca9230ebb2579700e489c7e3f07cd9cde206fef38b8139bd4976d2b4a7840495fc645f96df03 +88ac37ba66d1de5e23878c992e4d54023729e97e77351f50dc5918d738b5a73faf1dc6feec7e85784761836ba1c6f778 +ae1e6072c13060775f6086d1ae1f88b627ffcb810fc0e0e97deea1f3a15ef0aaa52a6dce2563e4beedadc131af2a8281 +8b60a340f5e4f90badf83001b495ac9f13974c3d2054ddcb3e6b8ca99dec5cd63a263e05c282454191ab2e087d5a2911 +832e2d56ba69dbf817b2b9dbd25c1538d5b8dbf5d9bc05e6be85054a423ebb66a71b157e166e0b9444ac171b34b7ccc9 +8586036fc7dde1e7e3ecb61663130c4529866ae9f5f5095b9fccd24a4c70eea899aae5f10ea1ba66d1665b2d83be35b0 +a77969453b5c083a207913272b5b69d4ccbd8718bdf54be8fbe11b4bd0a2168aae3ba8f9362afa69c0ffa28d7e5a2340 +b7fe9568c214baad0ac5f83745611b481f744ec1c4fa78a549b180dcf79633e5ba75dc20055012a13d849eb7a9be57d3 +b01cad1d2a6c51c0ce88243d1f52f95fb5ee315a905079688027511f0c4ecd0563a3a81846709d272fa5ccb9665e8043 +8eae0a21adfc569aa57237654021c2bdb2c6f0f52ccc90a126682c21a1f9413c63d285f92b2b2f8649150a9284bf70b7 +942acc947192b5f3cf60e92383e5d35f79e7a5904e8e9fd1c8a351676c83ad29b0afb6578d555457cf909f8f4d27adfd +a74e092f8628fba9abcabc27e2e9f3d5a9a941dfe50a2dfde2ad179aabc73afd196676925c2d98643ab8b3d02bdb66ad +896159daa2afd757cf3f9d34af248ad68bb3c62e4c9ac49919422727479cf669098f270b9e645607a7d11adad4c889b2 +a428d8370813d78e7a2a24eebd36e9da2f8bb3605e5a39b5fcda939b531c35a8ebaaa642ba556250a37bddeec90326fb +a5fa04eb60a1d5ee9820e78f42f7be15e1c02757b539aead995768c6209684d6c183c71d282e0c12a4c15c03f9a89d4d +93c77d5d220e40affa7269a6915c076c9aef4db552c643ae5d560a79c955b491c6346ca4cf11cbb7fe1894e28d47b065 +802e605d2de745eef6981d88e7a57ef4046a2062725e8080995374cea2b3273c27f35b7774d0dcba014710d8d6c501f2 +82f7169e6ec9b3e2bd450f35ea2e66d06bcf900acf5b73139677b48e078ce2e16599103027b2326770c99c0a690f2015 +b0c8581879439f9b997551233fe2de71aa03604f9cec37a7b18c5854342d9b67be468f3cac4bf6f64fe8a0066248c498 +a3f626848a4db6e9fb01cac90d3362ec521e969ebd5228af694ea3671061476149f13d652942ac1e39f65591fed740f9 +88a8e759b9cbe16a7c16e43f4afa2de6100d2eafa4dee75ccd653ec38c919013d0a6b35c1ee1eaee7c1985b58bcc9e92 +a3d5fc7aaea072798490616552d947e95f49cf02a420314307aafb555287ec607d75589ba24b009cd68299dc6f7942fa +a809cceeb84f9bcf3c3ddafde3041e7bc3b1d14df8830ab849002176a0725e6f16f70774d8962cb0b8ac0dc43c4ac66f +b8f2e46c031cc8fa160a08c2ebdfa85345ed14771b06daa9636b0e7792b7fddbc501dfc85cc626a01104a43a7d3230c3 +b5367e2a521c318b802ce16ceac80c4b8139f73ddb10ddf38433397cda70a86ea1f051cc55626a4e99d27f30f3975ff5 +96d963660121c1441cd13141279cd371a6a0aa18b6a20761b18df60aa9c14e13489afd83695a0921d5232efe72045f07 +80818d492fd85d666bd91aaf6257b86527fdd796773c793407df1d4a0f91d74649a6bab4d15155c36ed4c6e0a32c5636 +931e22918905fd6c230d3d867ea42861f3074d320d14e1929031924c8ac209a5c552b679b24563bb12f9749b4ee983bd +a4de2c333e74ed9bfa3c0bf6a0beb90427abd9aa4221294cda74331646b58ef46ed57cccc8798ba2b9309894b17cfd69 +883881554c1d88c0ed8d3b6dec3d200f6fea69a77ace3e4d6f86b41506a23724b4394ec8384075f9c75c3868ba8a8e8e +aa0539ecf6ec9bf06f24443027f8f24b6b3d8c5b2084248eecd4bcad3c9a69716e1a0d01057f09a65bff1006ac5e157a +856d74d44c943c9e809b42dc493dff20eca03cb0cf5ed45108c69b1f90d8592a53ae8100e99380a274fafad23e74cdfc +9188257446661c88da093b7c5ce998135913f63842d7c1586065377b169ee35b062d925367fb9b909ca971f1188667b1 +8d3aa57cdafbe998938787479f5d590c1484c6dbe94e6c487e57a746ef5252be0eaa5976d6270de7db64b6b92e57a0f7 +b8f4d6997240f9eda5aca0c43323a828d1563c491b3db2087f60ac4120a3fcd06075fb42bb19d0339ab5ee3fb7db25d2 +ad247ea94b8ae1e81eae4c9fd7b39e6601b53cff47b2547ff90a3cca87192eae28408082774a1fd14bf9ab459b7a4f1f +9598598070f8bdbcc49056c40971e673726cd8c1bc4baa0b5124dfb5fb750e7baa7a7df18eae2bd91955ddcb1ec67955 +b874131ab1608667fa60ea29092d090859eed1812e90c609afff96d79e82c5ba546f617f4c96fc32c9bba97431c1e9af +b00750a9cdc75c2a54f0d3cc99b0fe02300754f25166f7ac85ff41ab5e9cfcca33a29be76a480f12a2d410c7cd5032e5 +84b5bd1c90bb6c66755b28ba4af493ca1b0c3a4df9f436aac67d2e07289053f925cf6a149a84e74e1027dc8758150179 +99caf64bd9d193ff306e8ab5da3f1bb2a190a60c3a82099b8d03d17fa810dc53d176c21379f479e828f60d25beb3ffd0 +a8fd9de502f1c261d5733430e5a18d8b7892a98c9529a016fc2ee53892ae965dcd9c75850bcda4c7edb980b8d88e60ea +848c02cac636e047028a3fe8c1bf4066fb7591b96b0340f8fbd476ff01b35fa3e37d309333771a134f24800e5f3f9289 +a1eab1a06dcca3439f0166441e7e7f2f5b56f5f8aa9f45e411c561f556e0fb71c514c06c26ac53b49a576caca5faac3d +aa603f970dcbe953e700e61c151182c8d32cbbb53ceef572ac93383db33a4b098b5c7b267e42d514ca66b740c0925efe +b55fd5301bd700ddb0b4f72fabe9a91ad49759506101fa802ed1677e9553595aa4d2c66f7574e78d21ce882ce0120ae7 +829137bc4da7b4886d3d04d2c39cbf4b1dc40c813ac1adb425c7b9abf9142b516314cab79c68454df5d71994ce416144 +b83a3a22735001f783dd48a01c4fb3598a51ff3987e842b8045c71c035b9e43645a55254ca5911a5676ef4a8af12d056 +8ca8d463deb13f9eef5e533bc39efaeb0c15631282c5c0deee1673b0053a7cccd514af09801dd6c158caa159fe9351ac +a9ffb1427828f3c456b9c8cc50782de1ab0029b9233a0fd998bad0fd014d27e15c4a32d1e16ad41bff748378b5abdf49 +9627e29f725ddd86456aff813976bbc4a836f4deabf5ad9f73d1a260ceb30948824df9c8841e6b3c529652202be181b3 +b52c988647fe3d9276eed3c262e1044f57fbb116c64cf4f207235c205b3fda0f3d789bf90f5217401b468d85fdfda404 +833bbd6e2924f5c4446cb76b881d1434a5badce9eb9b003f85d076e297ad7ef45b822069fe54d17427a348c3263fb838 +a067a36352db6f82a116cb87d3db5f60b18576852409e2076cbbfc7843af78866313a4969385a40271051dd195d51116 +902b99545971f9a103f99d7399acc347ac46fe156166e51deefc0e92aebf5893460c69aeeae11f5af9f49418e289ce6c +9206a0e9ce9b9880f29ef0417c96931985f5d83bb17cebdbba4ff2af81a3d37155b04649426f698aed372e4f669599e6 +b54a5d7c976e45c0b1d44433595eae9d1ae9aeabfd58cd5ecb0c5804756a7b01c9a517754423b4714a3695533a3114c8 +91b612131e84580ece228b81ace83da0269b53f94d3c02a1a0879ebbd81bdc252064b3d03a7e140b43a90f237d9a45a0 +a6cead3b8607eaeafe37135bd6de8fbd16f806c131eb71c8d36bfbe295d45b070255e50dabf076e2c3f6b8699be71d6a +931da21e67b11ba6ce438546a24d063bcd51aebe39b4220a78d9c0aab88b2d37969b5ef3502d835507f9c8d6d006714c +8fda408caa9daf01122a2308b7b9d328f52e1e2f138a8bec30492488f4d710e5e52524a6455a3a2ae2818ec8a610b650 +ad8ad5c189644352d90c462731c46145410e5adf38682bb80f95495dd64d9d13782537d68690847bbb06c6be7175dbc7 +87bb5cc466ade60feb0961421c3fabdc8a7e20f11df8437bfff63d3f8bd25305002a396c9d0fa4fb9a9986d4717f12c4 +827cff72870ba00c29064a7d2b4973f322d6b6de7924c93d8bf8825e7a0e8478c7748f90f5c716bf83c55b2795d315d8 +a225895a8e94229776ceb51b05356291f2dce748be17a60d5aeb33ef8507c368bafe5d1d6eea927f28b9d1422b661b9a +8e011323ce670ff51c964241a6b72e0e0ffbb3ff9bb2762492323fc3a4abf4718091be0945287c7329850e4f74462cde +a2c03c2e5f4e9d3ef361f68b188451994ad1b24de9f323370559c8abfcdc7bffd289d92e78a5f6b104b0a12c84dab2ef +a22b4771116ce22276fab1fec6826610707ce8a342f9f60b079c4e0259dac3cc41c96c560dfd0ada6edd2828f7c0e8d6 +97c17441d0af9be83b42097aa8b7cec84a253b9a2b957214b8fa93c26d2add46144faffa7b8a55312059b10690f711f1 +94bdf348849f31a2737cbae5e5848aee711067bac85c11c2e68b44c398cfafbf3493a3226cd1ddf7a916e7613fc7b6f6 +838f59c6e8469a8ec6fd40b978a3607439aaebe1e50ff707eec72c0b8278af05b477bf12a384b56d03e3d4eb91e56f67 +a1940f0db58185e2b3aedd2b0bc2b73b4a65c68e09b046f38e9dcd4e13c94f5406bea92635190bf315e48ec64eceef2f +b2f4e0ae44e1f1210a91d8f280f17091fa994034ba8c991583f8182a323e9b3001a712e3584fc2d64ecbf2d319d076b2 +9342b89c721338d02c7854cd7466fb24d93d7313b6114ea591e6607439c8ddb911d1cf35f01898e9c557982bdff8f9b6 +8583fcab15be1dd14d5a415f4b14d706c8c62f058500f1344b37730c8be6741779691f87ded3cbcf6516468b373cafb0 +8fa9587c7989646571ad9032f34cedd353caee14f5be5cde1e9e0a1710f90c08faf6fa96a60e1f150f761c9c8ae7417d +8d9ff904cc08141f5a9879f5f77dc600e6edbe859082231a4d819953890199bcc5f940b730ea688332f07e5279d49e1c +b5f82b46e5ef9a2df8d144202d6e2e4f3bdae8e2048d2af5ea7deb3f722fbe6d370401954e74ff0d8cb1010ffb1f38d5 +a3b5b57d435b06ed70530e060002a8fea71746ad07d969ca23f22b5e52624527595b6a6d54b4e953fb7b7596bac378f0 +b90f89390df6d4b7879b915aa3c29b8d779d035033f8873bb7ac54a14ec98f0d08c0e3bf696e2ffa7b5730d736f571f8 +8e81e371b92887e43d95c0dbdcc9575282b26ccebdc8cbf46587e4f2a83b61e9bc0c6d7d1f114b9d21e04fd6c180b12a +8d682947c51dffc6e0fe0a486293c9ed121f441805168236393087cf62f2a429cca60bf0e472564844347d32c6bea27e +a8341ec7dd189fa7168759240224192c58209b53fc961c18082deba217928c399bde08ceae42bffd37c1135b4d14a845 +a94bb076dcc5ee5ec82fac57c5b384c690df12631882bd1b960e1eb8c04f787bc22b7bac315b9dc5a8a098f17f051a0b +ab64e1c6f01b87706c88a3bd974454a438722768de7340b834ccf93ea9880c14ee7c2181432acf51f980d56de73832ee +b7b0058bb724d879e5ad7aed6230297c54cb599ef659e86bf2cc84c38225899fb388391df9b2e6fdf063171937fd8c72 +ae856f4fb74c27cc98b67429186e7df4feb01278cd57bfd3170af6e52e0a23b9e926bf9565a890cfb4ae8f2d590b2cd5 +804b9c6702f0596d328f92fc1ed5a30a7ba17b9204524135001b569233fc4937035031d079f52fd04968f37c24013898 +84274ed1af6bd6a968583995622b4d18c6a2bc703ce0d0edce45bb736529b4836343dcd11911a94a134dca7877e6cab8 +88808098463f7505034c3b6328c8a08186b33f7a981c08376e429dd64b79b97753170531ed078dd265ded4ec0a1ed8d5 +92823bfb23a4eb84d3759e7d717f0c8641ece0927cd2ba8c728c26bb35df2629a838002f353c8d3d75eb19520aab5f25 +8db36bae4d960cdb9c51f419d7ddc81f372e56be605bc96a9d4072b829f05527c37c8f255cc6115300a2a0d2e6568d89 +a8fcdbd7f3b4d7ff04149a209feb75e97149e7efceaa42d66a6b8e432590fe7bd01f1a77fa8b47108f670b612e33fee9 +a9f4c53c62db7e5dbdea6918862d3c6d24b5bd8732a218edf0ba61e9d1861182323d8ecd7bef8f895b42970b492f6e40 +8b95bc7f07818f4d7b409aff8da0b2c2ae136cde386f53a71565cae9fd14c73c13cc1cfd79c0f97cd77839fb738c5b9a +adbd1d11adc756b51a571ddbcbf4392415231ddad93da09acfafee03a9e4f9e1ce3826110619e5271feadfaffce3e793 +95d327c8bb195cdf25fd79c98f9406a6b0316214b1630ebcce95bdaeffafa36fc1accc6882e0e5d13a8db5c0f3c0e61c +8cb2f1e2fb25558869afdacc7bb866544cfdd566cefcd048b48d458a886130bd086ecb7600a960a7f2563c61cb326510 +b3aa8c4bf5b933d89cd74ca7f7176d6624d562d7d58b041328b49d7562a30b489cb606abb3c49e85baf04c28e9cd1f44 +97f9053a85250c420599827297453c2cfde087065b823d9e43139e6a9cac3a2ec40a1b6e2f0726bdc870fff215462f0b +878d5dbe6b881389c2ca126ff66d87127c9aaa3f62f0d2c1ec0ea2b279ac95f8a06710dce166415db227655e2345a04d +b2c33a6b4203e3ca5247f0890e475518317ffc44cfbb1da9a1ba02114e8b752bea618050b876de5cf3b1906140a64471 +a56170c8313d2b5541a795bea9934d4425b185b5c409f0484df6f44f0e4bcbf50b860ff46b7245cd99c1cfa8fc1965b7 +96e2b658e2876a14147385fc423d2702a3cb76962b6b437222cf9cea39ebf4bdc03bbf434b747866d4bf72b4ceefa639 +89c4a74fa2f067e7ae49c84ef782c331bcc9245db7e941804e2e99d12e987b4d25cb827778ad4c3566c4fc68018650b6 +a01d30cea7d01c80ff26650020fab02e78fc3842e2398a81b44b21d58d4e9816166ff4ed2418831fa995a28ff35cb6f1 +b960c80b55a8845bbf24bc3f23b0110ca701f9544ab6a5bb7929330213cb471321e55c390ceca3e24bff69bdb0d331c0 +802c5b13f22be7be0e5db11eb3be0f0ea7f9182c932265060ba05fba20ea093dd2810d3b969ee3e387e60fe6ee834e8d +92478f88ef7435d15e39a97916c736abb28ea318394b88678fddbbaab3eaf31776110936abad116a8ff6ca632dd12043 +a6d3da0370c303001d5ed99d1db8bce1f26b0e442f0f042e36db9674e92dcd6e80465e772f1e669f99221caee3392fe9 +938f04f70a8f947d6df2f0c0e9af3cce0c06edbb3c131970dd60884fc0b0a0959c504a2a36c3ff76dfe919905671626a +a7117e55224230822e9983df2132347eb7208cb6798f291df926ab51e04b1a1f78d5568c9a8924ee6f57426134360f20 +b91074c77ad93fe48dc2b10c0c5a62ca3ab7d98345b919c52d84a9dc419b59fc1b267e1c2d4b2e120016ef84bbdb0cbe +aa175c6b6edf02fe8778762c9575581c0ee6efc9dbf99c291a41444a23a056b893be6c45333d907d0bbe9fb0eef84d08 +ad36dcb4e2ab425aa339ae464b038d550cb11186741dcf257f1b8b80ed4f32ffabbece45e2dc1525d4c3eeed819ea04f +91cb35c1ffa9cd5aebef523edb8325078da3eb5cf9e95c675a76446fc7692aaee6f949de064ca2f3e0f082cc3fa93e20 +82622f9410c143a86bc4d756b3c7b324dc295231ce865de020d61cc0868f2c150a473cea3a5b756b36771ce1032415a5 +a5c29996ad3a53468ece9356a5b4ccb68971ea1c89cf39644f1da2d4a477c2ea99bf791ef902b87c225d8c53d67c4c92 +92893eceed1af34fa92b23dcbab175b6a0188a27dbac9ad3317c4e39955a763cb383ab13fb1c519cde311d8a4d12e8b3 +8a093cb191b94b0200e38d31955f9d240e2be1edcd6810a2396a061f17c3ddc9c4f4d56766ddff4e121be7110e03b869 +93981473df0cb1f4b47c7d9b64e3123dcf1593845b401e619f5d7c70b5dbea375d1ca43fca65845fcf0a6b2e0af43791 +a6beb6b0697070f9562910add88d9ba91992f8da127b27be81868b1596d1012f09ea7ed601b4a6474c921a1a1a6d866c +92026b1ee30f2ed61c9f30337c3356844217926aabdff383c19ca3c21e0bc49811ca5b308012bee4ef250cfae1615800 +ac0ebaea6d35f84dac4ce648af096305ba68a7a0aea0a11ab2fbe3162075444a158433c98141bc92ef3b3400d6deb46a +83046f482dee24ac3ca83373f0d1b82ac1c4beda0f229a9011a81ec659ff5fc1fb105e219975b5c744308c77a24f71e4 +aa5a312c47ff7248dcb9c6ffbe5a0628ccd565c07365c4413734d415cd4fb35772622ed833862dddff520a67c509c6a5 +a02fb88805c34018ac33582e19ed0a7e4616acc3dd0867e5f21914c2031c05c6dca30b8b35b57c2b137750f3878a6f8c +a60528f1f14bf0c496491d46a0fbbd6c343e4eb3f1631e92f96a3c5e5c684091aabe5801df7a67f7c6dfd1b0d35269d4 +a1fd8e7fad8ca05a340c05a051bb0eb4197eed345f4104629a9e38e234b09d789cc5537024615feb4a6177d32d39e39e +8e70e36c1aa070815440e19443f1f04aae23b1b59fdbcba43b47b94a026c82c8f66c5dfe54f826f4d95ee1930cdb8008 +8234c1969fa7e9079661e4ca309b71b1aaa10f4372be0b963205c23a81f5a3d52ec08ba9ff65b37f832b52d631580d61 +a18cb4134127fb37c4abca328cd0047378a2e1423490af2bd3eba9ffcc99ca81a3c22404c0886f21f65c7b93c41d7981 +b46fa45fe538816de776eec086e040005706cb3eca097e290abfb6864e745c879868aac8361894f3c3564373ef9ad55c +b96ca43b96c59e95439f75d1e726a35a9362f0dbd34963b156e103e080a8126a8dc3501f9fd541ff3bcf4677f5c4a86b +a8e8c87c7301613818d57387009e601a7ab5cbdc2890f63d985c30c74f9cea2d0584c116baf0d9cd5594386ee93fc661 +b47e4f1b9153ef0981f813948150f283b47a7346fd9921d51fe8e4daedaef78ddeb4fd467c2ccb7cebd9816243da1c6e +a370c202a99c8441ffe96fad0f801086d4d7cc7b960f6e98cca29ceedf492afddfd0f351c9c4d29ac008bc255ec1a2a8 +8f5e6ce1655d1c059b006174e3f5a55c88e1821c97f9702ad8e8455d46c2a83ae4482f2d43edda74a835686ec45a8a15 +a30421e694930a3b65d397b2720d5f8e1eec2b6e2bb5a28d3f9b0a84db9aabd83850268bae64c2b10e313cccf120151b +8abe87163046f7a9b18e2a3c0b66e258facc1b31431420e0b70354b7a60ebd250a784634a76692e7d6f4330b62114945 +894f033cf077d4eb312e3258d9dca414356271abce1d6094ecce6d018c5fadb1c15d8d69451574ad0701a2876db191c5 +b0923d64f88ffc872654e1a294bb1af8681689c21cf08f39afe51448a68e60a9a0a74ccce9969276a932a52c07d095a3 +b9ca23b5be8725fae7fa710eefd45522889c50c29c26384e00b78a962384f0aeff9d15cb5910e9565da12a577eb7e5ba +b242ccf292757197a9f470f2d80ccddc48c7f1235ba026bc68a93be2738bc968e8a200aff3e2f4807216442eb3fc50dc +adc2c3b375b308524b79a024ff87d122055440643fea6fc0a651bdb312c7cbe6a456afa9d342bc76446d77d8daf08bc2 +ab645955356c2ebf2f3df9da275e01daf0b44a52afc309277d6d9ad1b05484e5ae0d9d41ad485fe481e5e362826a86ae +8de96ac587a4449fcc8b7fd0a51b4b5185d9c2eb3434f94cbadd092de1e26b0f6b3f7b15a37e8424b1429121ddca0ecd +94c70ad4e9b871566f3da98170b665a09788d421818299857cde0853789fb943cbcf7d4b2c95246ea7b72edc56a8e36c +b2574be63497843340700b701d5cc8be6d23125bd62058802ee67cce1f3b5f5602b27c93fea5611f27dc695ac563f042 +869ec89da7850cedd88bcb3a50a15cece233119b31b64a61bf6b2310892ce42d8b473b584b11e61db29ed24ce8033f83 +8fbaa269da8e28e9adf4c1b08f109da786dbe9cba871c32eecbfb10619b7a5d65a26f9bb33e201a8ed20b3de94003fbb +8bf7a059c37242caf7f821a6314e4e4adf799e0dd86b37892a7172598892c07272acebd05b534755c57b51556b2d610f +b4e72645fca459898cdd9214892ed08b5c99f82049c0a30d72bac0b9717caa9c6cc16c3dc7aa6ea4d42dcd2a6c175df6 +a39170da87a3495da55bbb9701c5461f3403447174ed6a4af75712f7ba4ac35f51a4234bc4b94da888a0959ee109c0c7 +b45675b2774ea7696089dbf7a0afe6c22e85fd0e4ef3db508fbaf96c9d07f700c991789206da9309fd291be696357c5f +b52899e3e3f6341eefcbe1291db6664bf3b6e8021d32fb9c3e37b6258a35c1da927747b2ce990937d6f4c6c3e7d020d2 +84e5bdb3dfe19700d79dd3fabb0159ccfa084f7288db836c855b827613ce8071067c8d7ac5cc2b4e88ed7f84b690f6e1 +801477d200b6d12fc6e0a9bab1c8211193ab06e44551e037a9b4c36fc2d4f67760b9ff4eba9a3bc7b6e177e891f64ff6 +b6b71a5116d3c22af26a7530f535e9b7851f25a84e562a8f17a125d55b9b3fc1bd8cfe65bdcbeeb328409521e802051c +8687e21c34d7804c12489d30680d131ce2133e2981bfa993afd8a8eeda958ebd5e6881d342d725338659882d9f21cf98 +a024e97a7c4de32b6383c34431994abc533ecdbd6be9bff836ec1af022f5a86773bf345c6f33273797a61fb70a8fd5d6 +83f784f095da20ce5b31f54d6cb14b32a8a12675f0029289c9cd036b7c87a8077be2d04a62618685720e6ee69c875e97 +b4e9dfe7cb9d9efd3fe00d99ae5e48769d4af4bf43d4e05c0b54c9cfd8bc854de96b8d3ebf4dcc06b9dac66b7471a0de +a08b79f9d4673afcf7f38b57f484f88feb7c908f597663a2417f92c348150c2be6b5603f914eba0d9d5bdd4e5c5572c1 +b0eaf919589988798cb01ba0610cd1b7fa3c08715675ece8ecd5f9ef6d5d7b2c4c8ae1ea7dfd202237171aa3e6f9de74 +abff99a98baae4dd0954052503ce81827781694a5ea8c1149f96a3adde75dc2d630e138598cd2ae7fdc7a654aa17df8f +83e369b8680d8b9d995222b033b4f4f3e3b20e782113c941325c7fa9c742feef8747e4a212d9aa23285a259cc4faef8d +b16d5855dd2716613697eba36e2fae0872aaea6999e91cf6552f93f9a0b85ed4f6ff922a91b50816bd6cf8e7a4513fc9 +848373db600e32e741aa1d37726bbb28956783f89ce2d781e95fb1ee1adf4359968a141678af268077eae4c25503204e +93a0dd0fdac18a31875564505b4e28f9e8bb2915faae666538597731ac56cd77f23f2456461e2f672983fb24ad91f6e0 +ab1ebbe49fa56524b564bc2e43784147073e6ea5d27a9540fbf2e04d0f87c645ed2fd28b3e4982cc4c0af1734ee47a6f +b3ee30b733839edab6f61f0738e3f4afaeccf700d8dc7415684f193b36d70d07acd5780cf539f12e0fbf8d4683be773a +88388f2cbdec47a6b3ae460b69eb0d2130ac14de950c22fd86de03e40d02292bb93cebe62432da39d509c1289f785fef +9370c41a54b68ff486b4cc6329c3a851716ebf1d088d77a6c56dec93a18b8a77b596cde74cc17d2adb2b2f411a2e4bbb +b9083b60dc16531f77b05a955b51a237a8f8c0173d72c352c5ca441b55abbc890b14937e457aaec4be5cbbf80cae0099 +aafff8f6c6ebaad952c65054dfc7c829453ec735331bf8135e06406b7a9f740c9a200dc48bb2175516b41f77dc160121 +b43d31fbbaf10526809e9e5bd8bb47a76e0fabd7852ee7744404559ab89f0f215ff518f3271a6aa972a459cab82ac558 +b581ede48c6ef34e678f91dc4b89507413e00e70712e3e8c32a80eed770ec8d8b98caee9702d068aeaca6f704be57bd8 +8cb0a137e68b001a5ccac61de27cac9fb78d4af7b2f5a00b8d95d33ac19cc50c69e760c5e0330a85c0ded1edce0fe6f9 +b947fca07c7aa6c2bf13048275402b00b77b28f1d0ba4b589fbcede13f93b5b931c588560ab8ceba23bb8e748031b55d +81753cced5ff819901740a9a584334e355b497cb699f0be5a52cd555a4c9f149535c7bb355b54407f7f0ec27de6c2e19 +b3d59273951ce97838c4853ec329782a255b5fc7c848e7992ded1be28a5ada7fa3254123afe32607b9991ec6e0659b08 +86b253de246f82be1cb0cef01e87c3d022ca1829d2cc7e6a160a5afbd3ca6b94d75739b122e3bb16f8bde28a8f3223ba +b728b659fa2d8487e061a37f7d14a4c2d70cc37497a8715695d8d332cb274deee2ce23b9b5f6a7408516c02c3d526a49 +81277b46d98848a45abfbe39842495659dcbb80dee985a4fc91d77d52b815487aa8bb455f411fcce4c3879c7a075a93f +b05b6f1fb4a6e654f0ee6b83e08b58b57059bb0b7c490405bc8d963c4a2d6be39c558917977e554e1e9e3169961cbf3e +88f75fa7d016fb6442551ec071cc1e2beeb3ccd213d16d744f573a82f5d70f41dd1b18af71d5f9e73d87f2f6b7dbe889 +81a46434f1bbd65a661a0ff45a0295b8fd8a42a7969c5953721bc98698b64bddee3f806876d1e9983063fdd0c11f99df +8b4f6d33c510a4c9c7d623d9ae0c9aa631fcb987704726b2a4d8519372123bce3c439202f25b5b47045ec14ce39a21a8 +8d5112b330fb63cf6ef3d2164b404c14ff9907d685015701399a260951912b19b8f270f869df317e9050a127763d7980 +aadab394e84dfb82db15ecd2427f39b62352c3e1647c3bcd14fb24ae830ad0116f0fed87ddb63963b424a4741961386e +81ca4e5600d00a3bda24cbdea7a532a4cbbd893c10e7ff10667c15ffa8138b91667abe5466b31a3dcdd60155c48538c1 +ad943af1b8a5fcfcf309ed8f2f916339f254cd555c71a407a47365a139306286a05a8314e1c70e20a65fccd75d36fa12 +b16597a0b437060a390467bbfab94c0bdd695ae898894f4689f939e30cc2119cc08ecb594546304adf876f4e275ebcd9 +a44a4e0a6693be356065891c27eefa040a1a79475be53d54d5fdcea7e0668ff9b35f850974000ed119f6865aa6faa721 +adef27d1b6e6921f4eaf69c79e2e01f5174f7033eaafdd33edcfa5119af23f3a834ffe1bdf19576581b797abd1865b34 +90c1e9202f3ffe28f8e1f58e9650dc4ff4dbc158005b6f2296ec36147e524b4f2f87f8aafc39db5b006fe0c491c92f45 +ac817cd54288b6f7fe6338415344fc9e7b669414051631ab2f27851c052c044be06bf7235d668e194bef695923256368 +ab14944ef653a14456d4ebc12e3196df3f1b4707c4e50b317b5ccc8ca3a0720f0330609f0e7e71793f6ca01583f38c70 +ad5353f2f380837e5ffdf079350b3d42935a0517861d03af98db5ed3ea8501abd68885c8c65f5a66e944b1874826a450 +8b5583863f84af8443ce8970b02e26cc5d959e47efbf8a66a54106ab165f1f76b36423aee74c7b5402fd1c4d7c1adfe6 +b3b46037eed9fc30e4f8f0da8bdbdcc40a38e22e876ce9fde981883017854aba82c18eb00887d92ad847d30082fe7271 +98a2b6fc90b7ad172e4368c1e54675b75c8bf2096d91c9f2b60b3397d3be3b705aed5389845dbd68f0f84438cd0f7687 +b155e800852a5f90a2eac69cc4483428da1dc2c31588a13c924e60a7616ce9baeb7d4b829c772b260277cadd8ed84719 +b8b92c520a1302b0cf7d993a52e1dacd7f27bda9868d59c55687d995ae676b7070af4c0792a9bc1c2635d44a4fee01bb +96dfe9bde526b8fc829eda825f55168b88e8f4e43d4d708cc3060df03437b46e12a8ac70d7788aa75760f6294d3e84d8 +a3fa66c54e2fa084ced3bd838614c6c33042f492a5745d167a723c60d5e7d6020ffd1747981a23f8b68df21ad8f0fa77 +b573ca10cc41fc04a642f6f62c355a4fda69b94b8e95dbb02fd1ccce4bce1191356e1fd66d372159944eb36a7071f005 +acd0a1c9abddfd0ea223eda1722aaada362d34234455bd1c6be115d41e535b16f12ca428da7820a757fa4c98884a385d +96f242eee99c4db383b8754fa7987c0c159652e1866faec905a8d3f010e0a1ad05bd77b9ea8dfd653738959180f58430 +9215a9b672a5d6e435e0e0a45156e0e20f75cbbdf1d14940fed3ddb63d433bef643796c7a4fff881829ebb2b2eba9460 +b8ad9bfceaf08dc5a874387219ddd1170bc3a5e25ed72d321d59ae713be5ddf9fdfbd3aa7ab163be28dfa0dd14614e19 +a19a1050590bc500b32c502f393e407abc3d8e683d6f6b978873aff3e3299b18b1f6b59e2b0fe237d819dbdfcfdc98ca +a6870fb11d4429686e52e1f44c8dcfc7ea24a020df9570c021578dbc1f9bdc8cf797cb3a72d7fc52805dba35d59f2cd0 +a7be733b64d5c06c127bd1c87250e42bfe30ca91ed8ce51e0b6e377f454e8f6fef7f99bff650695df2fd10c375da349b +a1b97145dab30330eea2cdc8739b2446a3704b64505fcea3dd8a9b4a72edf222e98d967d6fd7f76794acfd97aa091065 +b2127049907d2a3b654d1c940b740bfba3dbaf660f86ea79c2f909af7c9fe2a07a1caeb1be12370aeffaf8faa50f1582 +8a207701214bb28e99b0784e9228b1c34afa701966267fe7110f6f29f5bb41eaae6cdb98844d0400787978fabd224de8 +9925147a383b6f5f814520220ffdbf20b214225882c3ef49b1a1ca677709176ec82466fb9c4be2dfbe5640afb63b014a +8416ad93871623fb555b5390b80de99edaaf317350cc0c1ae9d54d59517074d40061f315cce8ba2026d9c1e6f6a1009f +a315f943deebbf0a2cdbcf3f8323e215a406e9cbfbcc3f6288714cb3a6befb1bf71b2a21ff7a2ec4731c65044c45b6b5 +8213e0c2539c24efd186ffa8b6dd401ad2233bc19166a0623b26dd1e93614bbf792823f5599ac116231e2efde9885709 +8e5cafd2f34a127a4a896f05e4d929eef06972a1826b3566446942198df26d62f7679b987db2b3765d9d8058b1cd85c2 +b5302b399c9cdf912fd59007ad4737255552663b1e56dbe64a7b2ddd88d2093c73ea319b45db2dd49d1e03f5bef1a0ae +a0c2bcfbed4b008e1a56e5d2f2419aa59d7dd0ebd990f1c18588de702ad0fa79f445d69965fa9381e700eda13b309378 +80a44eea1ffe24c26b16b8e2e70ee519258b9ad4b3e83cc4e5cca88ebc48d0160066f8b91d0581095b0de2428390c8b3 +84a90cb9c7d2f799f1c4ed060387a4b793ab41c5c3eaffd3b60face9b9c3bae93cd2017283bf3de1e3dac63d0d84dd42 +81d22febca276a05ba9bbc5591ee087b0491beb35b4d9f8fc0d041d642a574667ddc57660b20f5c568f7d61fdcb41bda +a3ac965ac27a28e102a439b74fbfc157e75fd57620e4c0750a466165f8aeecb2191dcf8e656f7525aa50d9c7c69b0b5c +913c17434ff0d9fc52e2ece4fec71b37d4474a18f3ea26925c1be2b250434d49759f58033ba0fce1c6862c6197930dc4 +ac430559c151a5e461f67b49c7786c97e1653fa8698e9759ddbdd99f5daf17fc5a012ae6330739440880728f24eba7c9 +b10d8e9f8aed9361b042d1398ec74364f7c7c1cc5c7f917060572761138bdbe89bf409389ee3879f93bc8032dd67b308 +937271005a4cc6a6ec134870c1b56471aa84ed4f4af1b3d5f334bc0c42762fae0c9a6a2828d3de6151a76dad7b72781c +a10e4dcf51889f69e6bd4c052f8d4036b9571ced98a3d7d779cbcb9fa5c3a82228566ea7cc1d012bf56dea0a40c5a64c +a0ed026528d9a8bb3201bc9dcd20598933e8c72fd315deea8da63d06e97392aa729d98a55a8a60fa4d5573513ba5c9fe +b723fcd04cddbd4c36feae827a03746ffef251c4f4c55a88beedaeeee194430a99f566f483668a0d88b13e7a4a37f1de +84a2cdceed44828c7c05a6a762edec0165e434e7029df617d6646aba48776e6c3b823f40689cee136536f8c93e08a629 +b786264e3a237ac3a1d56c9f4e87438dfed620c867100fd38b01287f5b755c7820937403bfb86644e082094d3e410a00 +92cc35b2065fca157c7bba54410f8bd85907a01c9f760aa0ddb7a82cb55811d24cb4dc6b725367a6a1c293b809a48ead +a12bbf22b117f00164a42515bc57cc9e6c43cc77fb737ee3d0c0cad94cb50cd3847d61cab469cf8ca76f7958bdcfc771 +85985b00de533bde2a757eddf53be79ea39091d16af3fc92327bcd1cd59bf2bf4411a334da29ad775e8ffaf3cea7d7b8 +af9eb24185b0d330d0ea1d0b0fa78af0dcf42ced81cb0128f16cafdea687a9c5582bb6d7c5744117b271cd0b3303f0b5 +8c8aaa1d85ed6327f85d579767c7a9158d209171b3efcb3e8a9d9e534c078e821b6aade255101d2c9ef6d67ba66f10be +a450518a03ffb40e1df89e0f88fd55b5b06f4872cdfb7ec55f40dc40d9424b3b289866336c195bdd54597d95569e0096 +81e61cc69f93c435bd77f155e80626a9c764dd92b6c76af15c41346527948d8a6ca87d6351a0fe7987e2ee3aa66a9625 +b615e0cebf4fdff4cb23a20c8389c370915ba26aa703b28efe4ab070b1603d1c5b6541684acf46b52a915f6aee447539 +a7f51885c7a71885cc84ef734ecd107e8bf5f7a25131415f671d143cc1de92859e65001125323c7985799993af6c410d +abfbf7a46f32066989c32f774edcc68163f085ca81e94fe8c9fb32f8d451bbb2c20ac45cd8d97f9e618ab40186933b1a +8cf35a522b5cac1934004aa9dd236bc77198d43272888afa860cfc79b4b28dabf7a3c74098f84510897566fdd609aa45 +86aa927df78f7a06a4985eb0a4f0b93529cef14f9fd2812d46abffbf25e618ead14d99c70e3c3bb2e17f3f7fabc9c264 +860f1b4f4a398e9a8bb4739587cf96979cfbbe1687b7e91e5bd1198db726391b09b1a261bf12e96698818f60b5bd3537 +8e7c4ee19ff115881051e8637dce1f5d6c65e865d0c757e8ce41b6d7bcd86c7070cce60649692bbf28c868c7e2e1e2f4 +acf7ba01b0220419f09169ac8d16e5cc13dce08e88c90b8fdfaa33aab417f011a20b79a178d8a9f7211589d2e0affd7d +b404bde8e715aefbb9f20a353b911b79173ef3e2cf0aba98b5ae6190b90597d65043b0b4e014ad9ea6c77da2d213ea12 +97e3615d1c77a402253bb55da2d1cdf82de316cefffe42b1022c94b4818d6dc4a313731db85321c537914bdf716a875c +940e950b96a4096a578c6874d747515936652b9b113a5f27f5a834a610867b05f9881e2679b0b289b8527baa0009b6dd +8de15a13ca236a3a285ce6e6826c502ae7365bbe468b6e8ac67b15b0bb49be0e996f1eec81ef69e4b7f54f8e4779a054 +a12244777eacb08ecd42b5676b3a51153022ab97e9353ace0f47c6054c22de9ba60d2a60f59a36841c2a791cb1b7c288 +94f7580203e39a2642ee2e7c969b9911f011d7f3a90c398e1302d26edb3df03df1d0c43baa1c6cf90dde95296d49e742 +82ead33144aaecab965faf63af384565992f38fc1066e71e33d53f43ac93892e27fe78c4eaca1cccbc53364e26ff31e9 +a0c129e9706d354249a7f8aa664ccd7ede89aa1445c5547410814b56d10dc086720953363ab1da8ff5f1ed5d8e575104 +93b3057bf3f74edc95237781ae012cc4b1d3fd0455565ceaac7110290aa518ac32478ba4eb9851555fa87270fcc84f1f +949c2fd0b94f31f7cbf00c679bd3f6ec1a2f4056654708d39edf1a450b4e19a6e251d0bb24eb765087e698f61d3fca2c +99fd2e50e211ccb66b895eb2fc42f260f3ad5767f04c2fe238b81dae98aa6e3977443a51f4fe7b43f499caabe45699a5 +84fe19626503218f327b5325bfd7c0c3d2614b47d34964aa0259d564e769c6c81502132cc1765b0b31fbe39852706927 +b43287ec29d9010bec4284de58fed48dd1e129bac79f09d45153c9949131782f77b11b0c9f8ee06a39e5e9bbaa8e2c6d +908902f3ed45482df2f94415fc8e5a308057a40c8905d7cbbd58ec4848e19276577b7f7e69e5e684a8b981738e10f7ef +85cc7d9c1eae372b4f88758cd6e21604b4bc9f0794e1e74b6d9de96347f81944d01331385fae7a38e5f6096c1dc23465 +af60288c702082fc258b3dbd6952c6b75c1641a623905f491b1e72f49b9d39b33d150a336450abd3911a4c128166acdf +a7d8ac7e589558c4014369ab6f4c1f2196205b03e4278152ec0dbbd7ba54e803c3369a71d364a773aac8dbbd117e4a13 +9833aed34e48c206e9328073597aee1123f5bec085339b4e6839a389a429bf3042798a31fac1464ce963204adface76b +84631a4f012bbb62133030224b57deb32dcf464cacc8ffde7775adbe68707263ab5527a1c75e597e03aa703ba658b889 +a686a61f6467858a2a4c13e70ad81b1901290d3e51bbc0c6e366f9e652f575e91b11c75f640ccef8b0c6c1b05a43c9a0 +b585f0ffd5144907703b41539bfad7f9f058f5985f63db911064ba6b07af8da2796b84b16db42b8d11135c3f846cd9e2 +b525539516c7bb25f1d7e165f269dc8c9eedbba74df44887e178ab8fd798e2a31f39812ca922d6b64d91564f14012a64 +91e480d7568fd2fae39c35b0a8d623e66a3160fee1dd4e9097255004938b11ac1cd3918dc6a1e5fbcb700c95a547e5e8 +936ef55c69b842b6177de71fa48dc5442bf5132116b214302f8f242ca36a273a6bbfbfaf373777104dadbe8e7da5e970 +8e950c0f6688abdff8a3b8bd77be6da6f2565c7b55711f5860ea62a3ab1d51aac31821c602bc11a45e33c69e7dde3ea4 +90eed4595104a0527f8db1e028ff622ff70db4eae99cf47f6c2a0246ec7b103570a6a9a877e32e9647cc74969006743d +b756344f6c4ea05b792e416d9bd9ce9dd4bd904e7622761f28a85628506bfc9d88a25e5f04db62fad30a92fb1d8d8556 +ad79ba76534c1a02ac3e9b7308d390792984cd75b7e1d0e5e4ff123642d99d4ea1825643091aa8117336333c40d5bd94 +832b08144887de0c0341d84f6945450af8d7a4eb32367d7703118186c1be525df9382ce61fed5f3b65a0bb3449185f7f +a322fb944e46d8e47994820890c94af423674716da810ea1da71e0a7733ad72c22114ca39a4b59c98ce4291a5684c154 +b982851a65140dbea79bd3b5487e236feccee051deddcc17c2853032efca289ddb6eaf64be3dd85a73012fdbe9d2d4f3 +8eed5e230e201830b44b9fadca4e156fe1a16bf840cf29da0f381ea0587b20c226de2465c67e6268973e776809af68e1 +81c8f1c04490f36e41a53ee1b5185cb8adbb37c258fd6c3be8c56835bf574c37183a94d55b6554fca35d6e6dd9af0133 +8c4928724107cc16d36f2976677eac0b852fc4c3c0bb2f9cd4d59cd24a113faf33b2faf405c3fcce25be51d41e42c2c4 +8e4ba842636fdfc4d71f0983538ea5037d420acd26abd12efca48c252eea85544b2fa9fccdfec4e7c2a6359baffa112d +b4315b84700e26dec26f3488d308430fdff4809c10d4c24309627911cbb769ffaad0d1ecccd622dd02194eaf5ba59f91 +ab888308f757faef32648c1db01650dbc9aea248b09d06e6efcc996d395f48ec96f2d54a02de441d753fe8737862d991 +805094cfd77e207d5c75f3cad99f41f763ec15443052cfd758c6a82ba422d831a1103a7f9b100da49c28198279c3d3dc +ad857f33243e4a2cd2a773700def21fc7f94939d1a6d2c2125ecd58fc206ccafb07a2c02a1cfce19857d3654aca2c70c +a4d12d40149953daa70b89a329e918e9d93efb4e8004a9357fe76682dab9662c8507e16db83e849340f05cdb4933a373 +a0dbac2ed4b5d03606524245e8a31080eb5bd3e9a0c51dad88c3b18e3e6bc5d64953a81c8e60425b80107ee6b62b1fb4 +86da05355900f327164a78901f6e3db857531b33b1e855df1a67a9ba222c6b05fdb6b0ffbacaeb1ba5b45ff8979b6b68 +932c9873aa3e226dd922b5a616c75153bd0390ce8f332a414b9c8cb6606c2501a37a2aa88097bc7d8e2c4261706eb38c +accd9cdf07ccdd42033ce3b105e00bfd39e2304b1e3d66f8b1128645634452c20f759ec45adcef2fdf04408f62c4cc04 +b75cfdfc1cb48918752eab17eb579820ee6e71e6667abdb64df834ffc8c1362fbbc23ca2c80dee248fe1fbb72d87dfc8 +88b998c73b00638fde7d3dd650a08c5ab996dac6ac34251337fbff3fb5ae4a25dd20c1a16c987ad7ded19eca23cea891 +8afef0956c942571a27f504553fb312cca9e50ce41b44e0466d0516c5abe4d8acf4594cdb03b1ccdbe3f2e6a9093b713 +9042cd83c5ff261e9ebda26398caa16cac2cb840d19062fa8ae50e044c27104972948318f4c866dc4d578798272d3e49 +ad536719a64570a2cd1d72b6590ea1d02c8c49f259a7867be26c8191445165954bcfad50ea12688ace3fdfb0e98143bd +97c86328d63d297b6bc9718dc1ad5a05b908a750d1c455c700d84315589128ce4eea958aef2bcf0fcf4adbd8e3ce58d1 +8e592cf0802e6a9541eeb654dc55055e11f3d757847285197132935ca35bbb1a9156829a39384dfa6f645ff89eb36738 +ac16c614998944f77590bf3913a010e13f2d3bbf6a172293baf5983506c1a2d89989fb72e598f5bba1ea10a691377c93 +ab8e6f5b46baa6632de3621497bcbdd584decb999fe7d8a3364843a1e0b76497600630b6a24dd30119d8bcbfca29f335 +abe1d3af5279e60122d9cea8cc6581c819d7a0e20e3715da0f6da7e02d13a7653db643bd946e2fa9ba338eca81fbe140 +8c33bd831ecfb18d1d0713e16beba768e9c42df62170c1f8a16764912be77f2ac5915623d1d25e8c462aa9c2f6669ca4 +903692becae4a6409f7bdb127d9b11de57a5739fe24218dcbaa0092648d5332dfeef29a908ee9e43e5e0a51a4c3639bc +92591e90347ae286acd365eba32cd9ad8f20f4c9cad2dc579b195147ff290adf0d776bcb3d4b04a25d68a941fc0c781b +b64bbccf860299aec16e1f95c768a1f337c740bde612e6ba260e393edb8b04540127194761c42597abb9bcb771c576c3 +9194f056ccfdfeb78a11c5347e2255d7a7ebd1251f9aebc0b58feb68d3e03a7dbbb74e3ef7309455853adfb4694bd01a +aa4f15f6d6a53ae65b7f6f91e8981d07a5919d2138679a561f7bb608dc4596e45ca06c9441d51fb678b2ad89ae7a17ae +90e3d18507beb30bde08c5001faf489a19ab545c177efb3f73fbf5605f9a0abcdc8bfbc44f832d6028e3e0a834bea98f +8f31dc0118c8c88a6e79e502d10e57652b7aba8409a5bf572ca63fed6b7cbad7f28bbc92ac2264f649792fc1d0715085 +a307d1067ea4c56437b6f8913aa8fcbf4a24580fc1e3336e7f6518f0f3adb9c4733090e459a3f737414ec0048179c30a +b7cc41fdf89595cd81a821669be712cd75f3a6c7a18f95da7d7a73de4f51bb0b44771c1f7cd3cd949e6f711313308716 +a9dc74e197fe60e8c0db06b18f8fe536381946edecdf31e9bd90e1ebfcad7f361544884e2fe83c23b5632912ec284faf +8b3e1e81326d611567e26ed29108f33ddb838c45bbd1355b3ae7e5d463612af64b63fff9fa8e6f2c14c8806021a5a080 +92f6537bca12778866335acc1eb4c3dfc2c8e7e5cf03399743dcea46aa66cac92ac2963b0892784263ad0ebe26ffdbf6 +b5cc0061f7a3e41513199c7dd91ac60d727366482a4c7328527f7bd4fc3509412f711bb722b4413b3736a219b843d15d +b3e9711d68d2c6f6e2cc27e385d5f603d9a1c9a96edeefa1ffdf390439954d19504d6aadc566b47e229ad4940ef020d2 +a09d0d3f0e5dc73a4a0827b72710b514bbfce4a7fcd5141d498a5aad6c38071077f50d3f91af897d9ab677b7041dedda +b177fe260f3b86e9ac21f1bfbe2682ae5dd8c9aecebb84f37054bdab6e39094e611ce582210ceeddde66adf759dadb6d +b0ac6595eba9f5dc4b2fd21856267cfbcfb5b12aa34ec69ca32b80071c5b652e85c25a224d80443d503bf25fbbfe07e9 +81f3c0e11b196bd4a2e8f07f8c037002566dc9037da81f3988add458a520c24dd1be3d43d851e28c0c6a85de4b57a542 +a44308c95615f7fedb2d2127012924468c015df9f48359cc2e36ab4223870b0bfc1e9040baabefdf5266f93afaad896b +8493ec4c32d5a13b81039f1b436eb83f259945dc950e3c6c2ccf5087ec56dd2f60890ed4edf01728b6a54950e19b35c6 +a1a439ec2a6a95bdac9aaa925ff337ba956c0d236ab5318354270e73ed6b73b4ae2d27b4c1686cf97b6526d04e65be81 +b4659b7b53c55a4b2bbe210b53520b392f893500e18990d843b72d7379d45fb44dd1dd2184348d6fd853d6b9ecc6b7c6 +afb2c68d75d00130b0e1b4f250001920213121791698ec04262db714cf7b1408d39f6cc10421f954845aad5b8250b77e +b22b843b40a97210f94043b552f348f66743055a3f274856a738e7d90a625b80e9bbb80cbbb450e1666eb56b8bd5c60f +800895ced82fe13d5fff65a93b0051c3df698bf1221b682accfdb63e3970f669ca37025750697f4e8ff2a3322ad57be4 +b21f598c50d7b9f4a584d548f85e42055ef8e24991906d973749090261584c7f4f5e984b528926f7e75375dd84d51af8 +849b1c68192d18274598dd6d0bf48fb5ee3b1ba25b331cff2d06f345bef3bed49760ca5690848cf33388f6a9a32cd646 +aeb6fd9478b10ef456f6bbb1e6dd19b14475e65497772d12cfc097948383d3fbd191bf95f046b8bf1989954118e483d0 +b1b5e0ea2835f7fc8b66e7731e392b43d16cbce04b52906b6751ab1b91978899db5fecbdabc23a19dabb253005468136 +91b6b1284770cf6f7ef35bc0b872b76c7763ffcfa68f9c8cfabcb2f264a66d47598bb9293f6a40f4c3dd33c265f45176 +b9ffed029846487c2cfb8a4bb61782bd8a878f3afdb73c377a0ebe63139fa070e3fcdc583eec3a53fdc5a421ff1fa877 +998007249d041b0b40ff546131cfc86d0b3598dcedf9a8778a223f7ed68ba4833b97324cbb1de91292b8ff51beab44b3 +8eb77ce9e0e406bf6f002870fb2fd1447646dd240df9bd485f8e0869298a1fc799d8a41b130c04370e9a9cc5c7540ca5 +853db8157462c46f2af7e8f94f2ed1c9b9a7ba2896b4973296898ff3d523d6e29e0b63a5d26cecd5e490b33c87a4cecf +b1436b6f3278768f0979ee852944258f2599977d255bea6fc912ba17c5dff5bdc850cf3e1fc52be9d6d188e868670f4f +a76acbc5832019b3b35667ab027feff49f01199a80016620f5c463dfcbfb51bf276ed17b7b683158ba450660cc7973eb +94540cdb051faf3ae8b8c52662868c2dab66bd02505c4f5f8eb4d6b2e2e5fd9a610890c5dcf8fd887eee796d2b5753a8 +aa35099666bceccf4eb3b65b13bba88e30a8be93693ab6761d8e5523343e8d6dd42d977e66499352fe4e9e9784a1dd0d +894471aad17be54319083c4b5e40adcfacf7c36c4aab0b671030b7ef321c53590a25eccd836efd20f32a93185fd315bb +8f52a9f705bb0dea958fcfbd52e2b6c08ad0f89a07a6b2942c1b4c37eead0d97a38a9e9aeb08d5d59b7fa2a9347f738b +9031c16b4f936c9cab55585dc5064739f696c3347ee2c0792320c9f749e760d120e396e8485ffc79d81c9f3337ad3d1c +82090a0d0d9b05459ec1c328ecd4707c333b784e3aaa0ef0072cee1eac83f9a653a75d83b9f63512a8c41200494826b4 +92c3a9553001f9ea4d67236b8ad1a33275378202cc1babc03f313895458f4b2549bfbbbdd37bfb8fbff0decb6b9f820a +88651868f4da37338a22bc553388df5dd1dd0cb78c4d7d07c637d8f6faef4bed72476fdcd4304d5bedf3514011135f08 +83fa0141bfebd88063f1d787719721b4c6b19ecf565b866de9d7d5d1a890e0e3d859b364bb65f8f8e688654456a40263 +90a7fab753e5d56dfc0e53a6b4e6ab14508220f3a62b3f3f30570c4c9ad225e74122635826c92e8e3227ec45e551432a +8fa375b0345bf6e5e062d108f9feaec91029345ecac67ccf1264eac77b8654cbfdda1f10579f481889c0e210254eadde +b83f06116da9daebdb013b26724523f077debaf6bc618b48a7a68858a98d275f7899c4ec73a0a827219b9248dd81c8c9 +8be1cada55e0c5ebb4fd460b2d209ae5326285a20c8bdd54ed9d1a87302f4063c8730bfda52d9d40e0d6fe43a0628465 +a68ad6f813743ec13a811f2ef3982c82d9d9ac1f7733936aa1e122f8dc7f4a305cc221579ab8fc170c3f123a1576f9ab +8878f1128214fdbbb8a0edd85223741e021508ab6d36c50d38680f2951ee713ea056ed03f62b9461897963d50ceefe0b +acc0d43d1b0260528b7425b260a5dea445b232b37240759fc65fe26f7c9d8e51569c5722bc33e94de6492f4ba1783504 +ad80b1dd717b076910ee5ceabcb762e75e4d094dc83b93b65c16de1f75bc712cef223c05d5579c1561829406c07a97d9 +a6fc9803f9c09d95fc326cc284f42ea5566255eb215dba8a9afb0be155ea11bcc55938b2d16f01cd2f2eda218c715efb +83ad733dbdfbaae8095a403dbf09130513f4ed4f08dcf8dd76ce83d1ea72999b7eea3a7b731da0d2bc80a83c6ee0e3e0 +8748912fbd08cb34a85416b0937d9c4327e9eed20d6e30aeb024a7253f14f1e0d774f3326e54738d71aae080e28da0fe +8997e78d8acf23051428af67183ae9b2c4aa42b503745ffe33df35a35103c589987e1473ab14dcd28ee78ebcb10d8e95 +a2f340502a7eb3c4a36412e6f028321372c4fa18a4743945607424e932af1271fa3e6598a162c872072529576eba6283 +868ccf19b5044ab93b45c9ed3ae34fcb504fe1453d6c4a1d12c325032cf01eb90356de82080ed897e97dba13cae33a02 +ac8867005fe4354d67aa37b866a7e581d2f94f7bd0b9f4efb5c2d1370ec13147a60692051b02fd00ae60b512bce9b1ff +8fd01886b046819c83c12bb779e432b25ba13713f9227be702074ec3abb2bba6be37220a0a26a4bd4171b99b14e32bc4 +a128981ed199f92b5959975c150a93a62fec50b61c80a3fa0634d90fc8058f76f5cbee77aae6889af12d296b30e613cd +81fe618552ff7a36c9235c6d4066cf2f930b5b38de4089e18166e4a06ca5723eadd1976d25e34b74b3ce942300b23e5b +ab1223ea049e6e0fbf9b611de7fd7c15e5e9637cbd73aa0e36aea08a7503ba6804f2aa807186fdc9aa7f4f9195f72e24 +b97285286981b2665f898abc13f3243b63005bef8db4cab3f658bf6167036b61af400f08db0fc3c640a9c623b760690d +ae3ddff7c1f0fbb6a13dbbc667a61e863c2c7c51c2051e33cd61620142e7e30a7e0c4c1f8fbb512aa3a8640267c6ac26 +99c2a89d5bef236060e51c4f952664094c20fbfca647e5d24a55c1fb8df2f3df58244fbbf3635db07b1c29ee3234fa6f +a5010764d4b9cd3b410638334d1f70c5f4843f45b4f4a9316aaea5fbb2c510a97449dd7a07b49f47334a69d37d9955d3 +86706d011dcdc9e9d165d01fea1df68dd74bedaf15a39f92893c030cafe96f4498c4c1fec2d2136354341b3f440a1462 +88fd57eb62bd7dc35722f3a0576c2138403a2f663a2603482e8974a895cf56ddbb02657dc6b89eb2cf5c1f9d1aff6426 +b0dfd4c68e3acb6bb8a776adaa421fc5e268ed4d5964bb90a727091e5113b55b3f9c6d33cedb3ee47ff7acc5df8b1749 +93b92bc942e1a636fc5c2dc1840de5faf158a113d640d5a475b48e2c56ccccaf9db0e37e90ce74c4b3f5c9ac3b2eb523 +b29a16fa1ea95cbfc1873c435ad40dc8495ba6341801b72bd95d908147dcffb1b4bb426dd635f3af4c88984f56594dd8 +b8f367105e1a2d554ac30200c66aeb579d3d30a8953d20fb6ebba2d876ec39c52ea5d654f1bb89b8ddf3d9d651f31cdf +b5fbc228c983d08adf8612eba5b3db3acff604439226f86aa133b02cce4ffde2f977c8dbb8b446b4375673f71634c89d +a399bea37d3056e0559f6644faa0af93063b4b545d504d7e228d3dbbc294af83d3c4cf37fe026b63899b4e7d50fd08f5 +928ef411a36414b24aea26fdbed4bdb1bb6bdc2d967e2553ce54c7c4e077e76869cea590257645c9129dd55ce025295c +9684a4adeed416a9ce82ad79b55c4a3adcfbd43950bc442ed8a340381caedb70f4baaaf821e3a152f483f965d8f56162 +92558a37f214d6f4cb6d72cd2f4ad24dff9d17611b9e4a41ee5c741a5d1ca9e4053b0584533ef4da206110b5dc3e2a35 +973bf0724d1785cc5e85d2a8ee8c354ad4cf557217ced0b7940f6f064024c20b2bfc5b144c820b5083da4bf70690de4d +adaf1389dfa528210ca9c2657c5ff10d51f7e3b18e93a59c37211be0506c3576cb2c04ec80cd0f82605e53c5a3556620 +85b58b223b09fda6f3ab674d75e780c49eb2167837243df049281e8f4fed653811138b398db9cdfe7405fdb8485602fe +849504d3db408d80745a07e850b0a804607b91a59922a5d3bc40da2748c029c029419cda38d2a4485cc0824c6b2504f0 +a3f4afcb353bc2582a02be758ebf0cd18752410ca2e64231176bfa23828423e0a450a65f241a9ed8eab36cae8d9c567b +ae362786cdf121206537af9590d330abbc6dc328b53cdd145dbed0e5df1364c816aae757c4c81f9d619e3698dd32bcdf +9024cfa5b0101eb02ab97866d5a3832944e5aa6888484cfba3d856576b920787b364fba5956bd7c68a305afedc958201 +8a116df09fed923acefb2aecf38a4fbc4b973ee964d67f03791d70bee6356af43ffca117d4e9463ffaf0e0d5d5e5a69f +9163016175c73f1bbc912ddfe03bd4e1db19c64951c8909ee6befe71a1249d838e0db49f03670bb4c5c9b2ab0fb4fef3 +8f6357318d8d16e7240a02b05ce5a4976b6079d49daa258789c6dbf4a47950ebe9de6411780fab06c7c1f35651433380 +8e63cbae8be7341892dbedee3111adf0307c4ee9e375181aa53478f5ba9cdce164d6ae890e5f480119a3a51c6e989165 +a9782f30674a4874d91bfba7eda63aeb5dbe66b040c768d6a925d8ee135f0655ea56276b105239cc0668fc91ddb68cd1 +8d9d94b61ab84ec08665cbe0244ea41756785df019e453ef078c19380bd44c39d2958e8465c72eacf41eed5696037805 +b1470e6f5d2e314474937cb5a3bc30c8bf5fc3f79014945f6ee895fe20028ffc272f9d3a7320aac93e36c96d8a5454e3 +a444911bbafc71179766594f3606b6eaff041826607fd3192f62dec05cd0f01b78598609a530f6930e8440db66f76713 +a9823d44e2638fca7bcc8796cc91c3eb17f46ad6db9f7f6510e093727614aa3a4f9b2c4011ef91dc1c2d224d08d8d05b +ab86020972c359ab98294212558b4b14862040139876c67fc494184b5c9bcea1dbe32fe0c8dd9e60be9daa304acd599a +b7e5cb685bbdcfdb1e48259a5d68d047846c8a35c5b3f90172fb183d1df40d22eaf0edaca2761a07c29c577000ccfed0 +8c88319dae4b28989817e79e6667fd891181e8d2ed91b9c6b614985bca14b12982462ec58b17be0463c24bbb79dd62a1 +8c1c6867e7107fb2178157c991b9c8b0f90c8d57a51220bf3650438ccabccf62da4db8a9916491e730ff3d0c106496e3 +a00a79bd58da6528b9af033087260f9f3d00519eafb4746b355204ee994e89481591b508eaa5402821083e250d38467b +8785abd7c37690f6aa870ee5c799eef72e398a7898b6767f698515be277b9c2fc1af12ea89b0620a848221343a3b5ec3 +8aadae68543db65cef71d0e230a09508d72061398ef2fabec0f856aacff2125b79c70e620744aaf331faf3dfc8afb9bc +8ff0cd437fcad9630b8a2333176a55e178db4142ec841581590594d74d5b53baeac5fb903fdf7bcf83e245b95b58285e +af274e8fad6b190be4e5dc92d2705ba6ac0d7e1ea29e958a5cdd4cb764de46a56d9eef62c999a16e7c50a50b2d9fe3a8 +865e6ec7d1aa848786d6a7a4e87a24d442311f0810b01ef5a74928ab59fdfd651e48880b49680047e5b0df6b3c7c2ecc +800706baaeb35bf3bc33bdea9a8b5cb00d82df407b3b7e1b781a9359cf44fb410ed311591080181b768aae223d9246aa +a9496389d0780b309c6998374ae159f58a8d0fe9a1c24c36cebcb45b27d818e653b51a8ee1f01e30a9b2c46a548126ef +b5fccf4fc3186661939fbee2e89c2aa0e3a6ad4907bcc98c7750520540c4c183b1bbfcdf47f2f1c5e75c3a30cdf30c75 +a90028e39081b736e628c2230cc1338f9210ed01309a40fdf08d39c10cced2cdf71271013bea6dba3a0444fe47963106 +a0815cbb325a8fecf2e1bcc5046644be32d43a8001bd5d8cf0022e4572cd0d481b3e717002f7ab21e16da5f5d16886d6 +b2024787fcda52abc4138150f15e81f4a5be442929b1651ddccbfd558029912be4d61c3c9b467605fff640edf7392494 +ab5aa60032304a584cc9245a33f528eae7157808dedd1ad83ebae00aadc25dbe1cd5917eb8b6b2c800df15e67bdd4c4d +866643847ef512c5119f2f6e4e3b8d3f4abb885f530bb16fcef0edb698a5b0768905e51536283925b6795a5e68b60ddc +806aa99c9a46ee11cc3ebf0db2344b7515db8c45b09a46a85f8b2082940a6f7263f3c9b12214116c88310e706f8e973a +a6eada8b9ff3cd010f3174f3d894eb8bb19efdbff4c6d88976514a5b9968b0f1827d8ac4fe510fb0ba92b64583734a1e +98480db817c3abbc8b7baedf9bf5674ec4afcfd0cd0fd670363510a426dad1bcf1b1cb3bf0f1860e54530deb99460291 +81ab480187af4a3dfbc87be29eca39b342a7e8e1d1df3fc61985e0e43d8d116b8eac2f1021bde4ae4e5e3606c1b67a21 +8a37df12dc997bf9b800f8fd581a614a1d5e32b843f067d63d1ca7fde2e229d24413d3a8308ec1e8389bf88154adb517 +b045a55ca0bb505bd5e8fcc4cfdd5e9af1a7d5fe7a797c7ede3f0b09712b37f493d3fcf6ef0e759d7e0157db1f583c95 +ad502e53a50691238323642e1d8b519b3c2c2f0fd6a0dd29de231f453be730cf1adc672887d97df42af0a300f7631087 +80597648f10c6d8fcd7421caf4e7f126179633078a1724817d2adc41b783723f302eabc947a7ba7767166dacf4ce8fa1 +aefb56427966c81081999dffbe89f8a0c402041929cd4e83d6612866cfbb97744f4ab802578349fbecc641fa9955e81b +a340e493fb3fb604eab864d4b18a6e40ba657003f1f88787e88e48b995da3d0ab4926ce438bdc8d100a41912a47dace0 +a6d777bfc0895eac541a092e14499ff8bf7156689d916a678b50a1460583b38e68158984bea113a0a8e970d8a6799a85 +90ce469410f0e8cfff40472817eb445770833cdcf2895a69bc32bcf959854d41712599ceb2b0422008d7300b05e62e02 +815c51be91d8516d5adc2fd61b6600957ed07cf5fdc809aa652b059bea8ed179638a19077a3f040334032f0e7900ac8b +b3ec6c0c3c007c49c6b7f7fc2ffd3d3a41cdff5ad3ac40831f53bfc0c799ffeed5f440a27acc5f64432e847cc17dd82e +823637abeab5fb19e4810b045254558d98828126e9a2d5895a34b9e4b4f49ab0a5b3ee2422f1f378995ea05df5516057 +ac05412bcf46c254f6548d8107a63928bba19ab6889de5d331eb68cf4d8ce206055b83af4cb7c6c23b50188391e93f84 +88514163c587068178302bc56e9a8b3ad2fa62afd405db92f2478bb730101358c99c0fe40020eeed818c4e251007de9c +b1e657d0f7772795b3f5a84317b889e8ded7a08ea5beb2ab437bebf56bcb508ae7215742819ed1e4ae3969995fe3b35d +a727d4f03027fe858656ca5c51240a65924915bd8bd7ffa3cfc8314a03594738234df717e78bb55a7add61a0a4501836 +b601682830fc4d48ece2bdc9f1a1d5b9a2879c40c46135f00c2c3ae1187c821412f0f0cfbc83d4e144ddd7b702ca8e78 +b5cfea436aa1f29c4446979272a8637cb277f282825674ddb3acac2c280662fb119e6b2bdd52c4b8dbf2c39b1d2070d6 +85c211645ff746669f60aa314093703b9045966604c6aa75aae28422621b256c0c2be835b87e87a00d3f144e8ab7b5f0 +867628d25bab4cb85d448fd50fdd117be1decdd57292e194a8baa0655978fae551912851660a1d5b9de7a2afbb88ef5c +a4e79c55d1b13c959ff93ddcf1747722c6312a7941a3b49f79006b3165334bab369e5469f1bddebadb12bfaff53806d5 +ac61f0973e84546487c5da7991209526c380e3731925b93228d93a93bce1283a3e0807152354f5fe7f3ea44fc447f8fe +a1aa676735a73a671a4e10de2078fd2725660052aa344ca2eb4d56ee0fd04552fe9873ee14a85b09c55708443182183a +8e2f13269f0a264ef2b772d24425bef5b9aa7ea5bbfbefbcc5fd2a5efd4927641c3d2374d0548439a9f6302d7e4ba149 +b0aacdaf27548d4f9de6e1ec3ad80e196761e3fb07c440909524a83880d78c93465aea13040e99de0e60340e5a5503cd +a41b25ae64f66de4726013538411d0ac10fdb974420352f2adb6ce2dcad7b762fd7982c8062a9bac85cdfcc4b577fd18 +b32d87d5d551f93a16ec983fd4ef9c0efcdae4f5e242ce558e77bcde8e472a0df666875af0aeec1a7c10daebebab76ea +b8515795775856e25899e487bf4e5c2b49e04b7fbe40cb3b5c25378bcccde11971da280e8b7ba44d72b8436e2066e20f +91769a608c9a32f39ca9d14d5451e10071de2fd6b0baec9a541c8fad22da75ed4946e7f8b081f79cc2a67bd2452066a9 +87b1e6dbca2b9dbc8ce67fd2f54ffe96dfcce9609210a674a4cb47dd71a8d95a5a24191d87ba4effa4a84d7db51f9ba0 +a95accf3dbcbf3798bab280cabe46e3e3688c5db29944dbe8f9bd8559d70352b0cfac023852adc67c73ce203cbb00a81 +a835f8ce7a8aa772c3d7cfe35971c33fc36aa3333b8fae5225787533a1e4839a36c84c0949410bb6aace6d4085588b1e +8ef7faa2cf93889e7a291713ab39b3a20875576a34a8072a133fed01046f8093ace6b858463e1e8a7f923d57e4e1bc38 +969ecd85643a16d937f148e15fb56c9550aefd68a638425de5058333e8c0f94b1df338eaab1bd683190bfde68460622b +8982f4c76b782b9b47a9c5aeb135278e5c991b1558e47b79328c4fae4b30b2b20c01204ff1afb62b7797879d9dee48e2 +b5098b7ba813178ced68f873c8c223e23a3283d9f1a061c95b68f37310bca4b2934a3a725fff1de1341c79bb3ba6007e +97b160787009f7b9649ed63db9387d48a669e17b2aba8656792eb4f5685bb8e6386f275476b4dfbb1b4cb0c2a69bc752 +88b69369c71daad6b84fa51a0f64a6962d8c77e555b13c035ad6fa1038e7190af455b1bd61ae328b65d6a14cf3d5f0d5 +af88b87801361f0de26bd2533554ee6f4d8067e3122b54161c313c52cc9eafea00661c5c43e2d533485d1f26da4e5510 +98ab18e3bbcb23ac1e34439849e56009bb765ab2f2558ebfd0a57cbe742169f114bceb930533fb911b22cb5a8fe172bc +9027507f1725d81e5ac0f0854c89ab627df3020fe928cb8745f887bf3310086c58fca1119fd5cd18a7d3561c042d58de +a676583f8a26e6f8991a0791916ce785b596ce372812f5eb7b4243ba9367ea95c797170fdac5b0c5e6b7f6519cc2b026 +b91b0ab32638aef3365035a41c6068e36d2303bfee8640565e16c9a56c21703270fd45946ce663238a72c053eb3f2230 +aaf4cd1ac0a30906dcd2b66b37848c6cc443da511e0b0367fd792887fdaf1500551590440e61d837dbee9d24c9801108 +a06f20a02d3cd76029baad5a12592f181738378a83a95e90470fa7cc82a5ae9d2ed824a20eeb1e96e6edc0619f298688 +a465d379c3481b294efc3f2f940b651c45579607cf72d143b99705eae42103a0279eb3595966453130e18935265e35d6 +892a8af7816a806295278027a956663ea1297118ede0f2a7e670483b81fb14dccacc7a652e12f160e531d806ca5f2861 +b480917c0e8b6e00de11b4416a20af6c48a343450a32ee43224559d30e1fecdece52cc699493e1754c0571b84f6c02c2 +b3182da84c81e5a52e22cebed985b0efc3056350ec59e8646e7fd984cdb32e6ac14e76609d0ffaca204a7a3c20e9f95d +a04ea6392f3b5a176fa797ddec3214946962b84a8f729ffbd01ca65767ff6237da8147fc9dc7dd88662ad0faefdb538c +95c0d10a9ba2b0eb1fd7aa60c743b6cf333bb7f3d7adedce055d6cd35b755d326bf9102afabb1634f209d8dacfd47f1a +a1a583d28b07601541fa666767f4f45c954431f8f3cc3f96380364c5044ff9f64114160e5002fb2bbc20812b8cbd36cb +a1a0708af5034545e8fcc771f41e14dff421eed08b4606f6d051f2d7799efd00d3a59a1b9a811fa4eddf5682e63102ea +ab27c7f54096483dd85c866cfb347166abe179dc5ffaca0c29cf3bfe5166864c7fa5f954c919b3ba00bdbab38e03407d +ac8c82271c8ca71125b380ed6c61b326c1cfe5664ccd7f52820e11f2bea334b6f60b1cf1d31599ed94d8218aa6fbf546 +a015ea84237d6aa2adb677ce1ff8a137ef48b460afaca20ae826a53d7e731320ebdd9ee836de7d812178bec010dd6799 +925418cda78a56c5b15d0f2dc66f720bda2885f15ffafb02ce9c9eed7167e68c04ad6ae5aa09c8c1c2f387aa39ad6d1b +87c00bba80a965b3742deacafb269ca94ead4eb57fdb3ed28e776b1d0989e1b1dba289019cfb1a0f849e58668a4f1552 +948d492db131ca194f4e6f9ae1ea6ebc46ebbed5d11f1f305d3d90d6b4995b1218b9606d114f48282a15661a8a8051ca +8179617d64306417d6865add8b7be8452f1759721f97d737ef8a3c90da6551034049af781b6686b2ea99f87d376bce64 +918e3da425b7c41e195ed7b726fa26b15a64299fe12a3c22f51a2a257e847611ac6cfcc99294317523fc491e1cbe60c4 +a339682a37844d15ca37f753599d0a71eedfbbf7b241f231dd93e5d349c6f7130e0d0b97e6abd2d894f8b701da37cb11 +8fc284f37bee79067f473bc8b6de4258930a21c28ac54aaf00b36f5ac28230474250f3aa6a703b6057f7fb79a203c2c1 +a2c474e3a52a48cd1928e755f610fefa52d557eb67974d02287dbb935c4b9aab7227a325424fed65f8f6d556d8a46812 +99b88390fa856aa1b8e615a53f19c83e083f9b50705d8a15922e7c3e8216f808a4cc80744ca12506b1661d31d8d962e4 +a1cbd03e4d4f58fc4d48fa165d824b77838c224765f35d976d3107d44a6cf41e13f661f0e86f87589292721f4de703fb +b3a5dde8a40e55d8d5532beaa5f734ee8e91eafad3696df92399ae10793a8a10319b6dc53495edcc9b5cfd50a389a086 +996e25e1df5c2203647b9a1744bd1b1811857f742aee0801508457a3575666fcc8fc0c047c2b4341d4b507008cd674c2 +93e0a66039e74e324ee6c38809b3608507c492ef752202fff0b2c0e1261ca28f1790b3af4fdb236f0ed7e963e05c1ec0 +b6084e5818d2d860ac1606d3858329fbad4708f79d51a6f072dc370a21fdb1e1b207b74bc265a8547658bfb6a9569bb3 +a5336126a99c0ecfc890584b2a167922a26cae652dfc96a96ab2faf0bf9842f166b39ceaf396cd3d300d0ebb2e6e0ebf +b8b6f13ce9201decaba76d4eca9b9fa2e7445f9bc7dc9f82c262f49b15a40d45d5335819b71ff2ee40465da47d015c47 +b45df257b40c68b7916b768092e91c72b37d3ed2a44b09bf23102a4f33348849026cb3f9fbb484adfea149e2d2a180ff +a50d38ee017e28021229c4bb7d83dd9cdad27ab3aa38980b2423b96aa3f7dc618e3b23895b0e1379ca20299ff1919bbf +97542cf600d34e4fdc07d074e8054e950708284ed99c96c7f15496937242365c66e323b0e09c49c9c38113096640a1b6 +822d198629697dcd663be9c95ff1b39419eae2463fa7e6d996b2c009d746bedc8333be241850153d16c5276749c10b20 +9217bc14974766ebdfbf6b434dd84b32b04658c8d8d3c31b5ff04199795d1cfad583782fd0c7438df865b81b2f116f9c +93477879fa28a89471a2c65ef6e253f30911da44260833dd51030b7a2130a923770ebd60b9120f551ab373f7d9ed80aa +87d89ff7373f795a3a798f03e58a0f0f0e7deab8db2802863fab84a7be64ae4dcf82ece18c4ddbefccd356262c2e8176 +a3ba26bd31d3cc53ceeced422eb9a63c0383cde9476b5f1902b7fe2b19e0bbf420a2172ac5c8c24f1f5c466eecc615d4 +a0fe061c76c90d84bd4353e52e1ef4b0561919769dbabe1679b08ef6c98dcfb6258f122bb440993d976c0ab38854386b +b3070aa470185cb574b3af6c94b4069068b89bb9f7ea7db0a668df0b5e6aabdfe784581f13f0cf35cd4c67726f139a8c +9365e4cdf25e116cbc4a55de89d609bba0eaf0df2a078e624765509f8f5a862e5da41b81883df086a0e5005ce1576223 +a9036081945e3072fa3b5f022df698a8f78e62ab1e9559c88f9c54e00bc091a547467d5e2c7cbf6bc7396acb96dd2c46 +8309890959fcc2a4b3d7232f9062ee51ece20c7e631a00ec151d6b4d5dfccf14c805ce5f9aa569d74fb13ae25f9a6bbe +b1dc43f07303634157f78e213c2fae99435661cc56a24be536ccbd345ef666798b3ac53c438209b47eb62b91d6fea90a +84eb451e0a74ef14a2c2266ff01bd33d9a91163c71f89d0a9c0b8edfcfe918fc549565509cd96eed5720a438ff55f7f2 +9863b85a10db32c4317b19cc9245492b9389b318cf128d9bbc7ec80a694fcbbd3c0d3189a8cad00cc9290e67e5b361ee +8a150ee474ebe48bdfcac1b29e46ac90dcded8abbe4807a165214e66f780f424be367df5ef1e94b09acf4a00cd2e614d +a6677a373130b83e30849af12475e192f817ba4f3226529a9cca8baaefb8811db376e4a044b42bf1481268c249b1a66e +b969cbf444c1297aa50d1dfa0894de4565161cb1fc59ba03af9655c5bf94775006fe8659d3445b546538a22a43be6b93 +8383167e5275e0707e391645dc9dea9e8a19640ecfa23387f7f6fcaddff5cde0b4090dfad7af3c36f8d5c7705568e8d8 +a353ddbc6b6837773e49bb1e33a3e00ca2fb5f7e1dba3a004b0de75f94a4e90860d082a455968851ef050ae5904452e0 +adeccf320d7d2831b495479b4db4aa0e25c5f3574f65a978c112e9981b2663f59de4c2fa88974fdcabb2eedb7adab452 +afa0eacc9fdbe27fb5e640ecad7ecc785df0daf00fc1325af716af61786719dd7f2d9e085a71d8dc059e54fd68a41f24 +a5b803a5bbe0ca77c8b95e1e7bacfd22feae9f053270a191b4fd9bca850ef21a2d4bd9bcd50ecfb971bb458ff2354840 +b023c9c95613d9692a301ef33176b655ba11769a364b787f02b42ceb72338642655ea7a3a55a3eec6e1e3b652c3a179e +8fa616aa7196fc2402f23a19e54620d4cf4cf48e1adfb7ea1f3711c69705481ddcc4c97236d47a92e974984d124589e5 +a49e11e30cb81cb7617935e8a30110b8d241b67df2d603e5acc66af53702cf1e9c3ef4a9b777be49a9f0f576c65dcc30 +8df70b0f19381752fe327c81cce15192389e695586050f26344f56e451df2be0b1cdf7ec0cba7ce5b911dcff2b9325ae +8fbbc21a59d5f5a14ff455ca78a9a393cab91deb61cf1c25117db2714d752e0054ed3e7e13dd36ad423815344140f443 +a9a03285488668ab97836a713c6e608986c571d6a6c21e1adbd99ae4009b3dde43721a705d751f1bd4ebf1ea7511dfed +b2f32b8e19e296e8402251df67bae6066aeefd89047586d887ffa2eacdf38e83d4f9dc32e553799024c7a41818945755 +942cf596b2278ad478be5c0ab6a2ad0ceafe110263cc93d15b9a3f420932104e462cf37586c374f10b1040cb83b862e0 +aaa077a55f501c875ceae0a27ef2b180be9de660ef3d6b2132eb17256771ce609d9bc8aaf687f2b56ae46af34ad12b30 +90ac74885be1448101cf3b957d4486e379673328a006ea42715c39916e9334ea77117ff4a60d858e2ccce9694547a14f +9256cdfc2339e89db56fd04bd9b0611be0eefc5ee30711bcece4aadf2efcc5a6dcc0cfd5f733e0e307e3a58055dff612 +a4c7384e208a0863f4c056248f595473dcde70f019ddaede45b8caf0752575c241bac6e436439f380ac88eee23a858e9 +a3aa67391781e0736dddc389f86b430b2fc293b7bd56bfd5a8ec01d1dd52ed940593c3ad4ce25905061936da062b0af6 +80299275ec322fbb66cc7dce4482ddd846534e92121186b6906c9a5d5834346b7de75909b22b98d73120caec964e7012 +aa3a6cd88e5f98a12738b6688f54478815e26778357bcc2bc9f2648db408d6076ef73cced92a0a6b8b486453c9379f18 +b07c444681dc87b08a7d7c86708b82e82f8f2dbd4001986027b82cfbed17b9043e1104ade612e8e7993a00a4f8128c93 +af40e01b68d908ac2a55dca9b07bb46378c969839c6c822d298a01bc91540ea7a0c07720a098be9a3cfe9c27918e80e8 +abd8947c3bbc3883c80d8c873f8e2dc9b878cbbb4fc4a753a68f5027de6d8c26aa8fbbafeb85519ac94e2db660f31f26 +a234f9d1a8f0cb5d017ccca30b591c95ec416c1cb906bd3e71b13627f27960f61f41ed603ffbcf043fd79974ec3169a8 +835aaf52a6af2bc7da4cf1586c1a27c72ad9de03c88922ad172dce7550d70f6f3efcc3820d38cd56ae3f7fc2f901f7a0 +ae75db982a45ad01f4aa7bc50d642ff188219652bb8d521d13a9877049425d57852f3c9e4d340ffec12a4d0c639e7062 +b88884aa9187c33dc784a96832c86a44d24e9ffe6315544d47fc25428f11337b9ffd56eb0a03ad709d1bf86175059096 +8492ca5afcc6c0187b06453f01ed45fd57eb56facbeea30c93686b9e1dab8eaabd89e0ccb24b5f35d3d19cd7a58b5338 +9350623b6e1592b7ea31b1349724114512c3cce1e5459cd5bddd3d0a9b2accc64ab2bf67a71382d81190c3ab7466ba08 +98e8bf9bed6ae33b7c7e0e49fc43de135bffdba12b5dcb9ff38cb2d2a5368bb570fe7ee8e7fbe68220084d1d3505d5be +ab56144393f55f4c6f80c67e0ab68f445568d68b5aa0118c0c666664a43ba6307ee6508ba0bb5eb17664817bc9749af0 +827d5717a41b8592cfd1b796a30d6b2c3ca2cdc92455f9f4294b051c4c97b7ad6373f692ddafda67884102e6c2a16113 +8445ce2bb81598067edaa2a9e356eda42fb6dc5dd936ccf3d1ff847139e6020310d43d0fec1fe70296e8f9e41a40eb20 +9405178d965ee51e8d76d29101933837a85710961bb61f743d563ef17263f3c2e161d57e133afac209cdb5c46b105e31 +b209f9ed324c0daa68f79800c0a1338bbaf6d37b539871cb7570f2c235caca238a2c4407961fcb7471a103545495ef2c +92ae6437af6bbd97e729b82f5b0d8fb081ca822f340e20fae1875bdc65694cd9b8c037a5a1d49aa9cae3d33f5bad414e +9445bdb666eae03449a38e00851629e29a7415c8274e93343dc0020f439a5df0009cd3c4f5b9ce5c0f79aefa53ceac99 +93fdab5f9f792eada28f75e9ac6042a2c7f3142ba416bfdb1f90aa8461dbe4af524eee6db4f421cb70c7bc204684d043 +a7f4dc949af4c3163953320898104a2b17161f7be5a5615da684f881633174fb0b712d0b7584b76302e811f3fac3c12f +a8ac84da817b3066ba9789bf2a566ccf84ab0a374210b8a215a9dcf493656a3fa0ecf07c4178920245fee0e46de7c3ec +8e6a0ae1273acda3aa50d07d293d580414110a63bc3fb6330bb2ee6f824aff0d8f42b7375a1a5ba85c05bfbe9da88cb5 +a5dea98852bd6f51a84fa06e331ea73a08d9d220cda437f694ad9ad02cf10657882242e20bdf21acbbaa545047da4ce5 +b13f410bf4cfce0827a5dfd1d6b5d8eabc60203b26f4c88238b8000f5b3aaf03242cdeadc2973b33109751da367069e1 +a334315a9d61b692ad919b616df0aa75a9f73e4ea6fc27d216f48964e7daebd84b796418580cf97d4f08d4a4b51037cd +8901ba9e963fcd2f7e08179b6d19c7a3b8193b78ca0e5cf0175916de873ca0d000cd7ac678c0473be371e0ac132f35a2 +b11a445433745f6cb14c9a65314bbf78b852f7b00786501b05d66092b871111cd7bee25f702d9e550d7dd91601620abb +8c2f7b8e7b906c71f2f154cc9f053e8394509c37c07b9d4f21b4495e80484fc5fc8ab4bdc525bd6cfa9518680ba0d1a2 +b9733cebe92b43b899d3d1bfbf4b71d12f40d1853b2c98e36e635fdd8a0603ab03119890a67127e6bc79afae35b0bef2 +a560f6692e88510d9ba940371e1ada344caf0c36440f492a3067ba38e9b7011caac37ba096a8a4accb1c8656d3c019b3 +ac18624339c1487b2626eef00d66b302bdb1526b6340d6847befe2fdfb2b410be5555f82939f8707f756db0e021ed398 +afd9a3b8866a7fe4f7bc13470c0169b9705fcd3073685f5a6dcff3bdbbc2be50ac6d9908f9a10c5104b0bffc2bc14dad +97f15c92fe1f10949ed9def5dd238bc1429706e5037a0e0afb71c2d0e5845e2fed95a171c393e372077a7c7059f8c0e0 +9453a1d4d09c309b70968ea527007d34df9c4cfd3048e5391aac5f9b64ca0c05dde5b8c949c481cfc83ef2e57b687595 +b80e4b7c379ad435c91b20b3706253b763cbc980db78f782f955d2516af44c07bbfa5888cbf3a8439dc3907320feb25a +8939f458d28fefe45320b95d75b006e98330254056d063e4a2f20f04bcb25936024efe8d436d491ed34b482f9b9ae49c +a9ead2e833f71f7e574c766440c4b3c9c3363698c7ade14499a56003a272832ee6d99440887fa43ccdf80265b9d56b97 +b6547a36934f05ce7b779e68049d61351cf229ae72dc211cc96a2a471b2724782f9355fdb415ea6f0ea1eb84fe00e785 +828bfb3099b7b650b29b0f21279f829391f64520a6ab916d1056f647088f1e50fac9253ef7464eceab5380035c5a59c4 +8d714b9ea650be4342ff06c0256189e85c5c125adf6c7aeca3dba9b21d5e01a28b688fc2116ce285a0714a8f1425c0b8 +8a82eda041b2e72a3d73d70d85a568e035fbd6dc32559b6c6cfdf6f4edcb59a6ba85b6294a721aa0a71b07714e0b99ae +af5665ebc83d027173b14ffb0e05af0a192b719177889fadc9ac8c082fda721e9a75d9ce3f5602dbfd516600ee3b6405 +a68fdddf03d77bebdb676e40d93e59bd854408793df2935d0a5600601f7691b879981a398d02658c2da39dbbf61ef96c +8c001ebc84fcf0470b837a08a7b6125126b73a2762db47bbdc38c0e7992b1c66bac7a64faa1bf1020d1c63b40adc3082 +8553889b49f9491109792db0a69347880a9cf2911b4f16f59f7f424e5e6b553687d51282e8f95be6a543635247e2e2c2 +a2c269d6370b541daf1f23cc6b5d2b03a5fa0c7538d53ae500ef875952fe215e74a5010329ff41461f4c58b32ad97b3d +a5dae097285392b4eba83a9fd24baa03d42d0a157a37fae4b6efc3f45be86024b1182e4a6b6eadcf5efe37704c0a1ae5 +89871a77d2032387d19369933cd50a26bda643e40cfd0ce73febe717a51b39fae981406fd41e50f4a837c02a99524ef9 +8a76d495e90093ec2ac22f53759dc1cf36fbb8370fb586acbd3895c56a90bbf3796bcc4fc422ca4058adf337ead1402e +ad4eb7576c4954d20623c1336c63662c2a6fb46ec6ef99b7f8e946aa47488dcb136eab60b35600f98c78c16c10c99013 +894c2b120cec539feb1d281baaadde1e44beafedeeec29b804473fe024e25c1db652f151c956e88d9081fb39d27e0b19 +9196bd5c100878792444c573d02b380a69e1b4b30cb59a48114852085058a5fd952df4afee3ecceb5c4ede21e1ed4a1a +a996fffc910764ea87a1eedc3a3d600e6e0ff70e6a999cb435c9b713a89600fc130d1850174efe9fc18244bb7c6c5936 +8591bb8826befa8bee9663230d9a864a5068589f059e37b450e8c85e15ce9a1992f0ce1ead1d9829b452997727edcf9d +9465e20bb22c41bf1fa728be8e069e25cda3f7c243381ca9973cbedad0c7b07d3dd3e85719d77cf80b1058ce60e16d68 +926b5ce39b6e60b94878ffeae9ff20178656c375fb9cfe160b82318ca500eb3e2e3144608b6c3f8d6c856b8fe1e2fbcf +a1ef29cbc83c45eb28ad468d0ce5d0fdd6b9d8191ba5ffa1a781c2b232ed23db6b7b04de06ef31763a6bfe377fa2f408 +9328e63a3c8acf457c9f1f28b32d90d0eeadb0f650b5d43486a61d7374757a7ada5fc1def2a1e600fa255d8b3f48036f +a9c64880fcb7654f4dd08f4c90baac95712dd6dd407e17ea60606e9a97dc8e54dd25cb72a9bf3fc61f8d0ad569fe369d +a908eb7b940c1963f73046d6b35d40e09013bfbfbeb2ccd64df441867e202b0f3b625fa32dd04987c3d7851360abdffc +b3947b5ed6d59e59e4472cdb1c3261de1b5278fb7cb9b5fca553f328b3b3e094596861ea526eca02395f7b7358155b7b +99da7f190d37bc58945f981cf484d40fcf0855cf8178e2ce8d057c7f0a9d9f77425fdbce9ef8366f44f671b20fd27d0b +913976d77d80e3657977df39571577fdf0be68ba846883705b454f8493578baa741cfaede53783e2c97cc08964395d83 +8d754a61e5164a80b5090c13f3e936056812d4ae8dc5cc649e6c7f37464777249bc4ae760a9806939131f39d92cca5bf +82ffd098480828a90cb221a8c28584e15904bad477c13b2e2d6ef0b96a861ce4a309a328fe44342365349456ad7c654f +89ae3ce4b0357044579ca17be85d8361bb1ce3941f87e82077dd67e43ec0f95edd4bd3426225c90994a81a99e79490b7 +a170892074016d57c9d8e5a529379d7e08d2c1158b9ac4487ac9b95266c4fd51cb18ae768a2f74840137eec05000dd5a +aafd8acd1071103c7af8828a7a08076324d41ea530df90f7d98fafb19735fc27ead91b50c2ca45851545b41d589d0f77 +8623c849e61d8f1696dc9752116a26c8503fd36e2cbbc9650feffdd3a083d8cdbb3b2a4e9743a84b9b2ad91ac33083f2 +ac7166ddd253bb22cdbd8f15b0933c001d1e8bc295e7c38dc1d2be30220e88e2155ecd2274e79848087c05e137e64d01 +a5276b216d3df3273bbfa46210b63b84cfe1e599e9e5d87c4e2e9d58666ecf1af66cb7ae65caebbe74b6806677215bd0 +88792f4aa3597bb0aebadb70f52ee8e9db0f7a9d74f398908024ddda4431221a7783e060e0a93bf1f6338af3d9b18f68 +8f5fafff3ecb3aad94787d1b358ab7d232ded49b15b3636b585aa54212f97dc1d6d567c180682cca895d9876cacb7833 +ab7cb1337290842b33e936162c781aa1093565e1a5b618d1c4d87dd866daea5cebbcc486aaa93d8b8542a27d2f8694c7 +88480a6827699da98642152ebc89941d54b4791fbc66110b7632fb57a5b7d7e79943c19a4b579177c6cf901769563f2f +a725ee6d201b3a610ede3459660658ee391803f770acc639cfc402d1667721089fb24e7598f00e49e81e50d9fd8c2423 +98924372da8aca0f67c8c5cad30fa5324519b014fae7849001dcd51b6286118f12b6c49061219c37714e11142b4d46de +a62c27360221b1a7c99697010dfe1fb31ceb17d3291cf2172624ebeff090cbaa3c3b01ec89fe106dace61d934711d42d +825173c3080be62cfdc50256c3f06fe190bc5f190d0eb827d0af5b99d80936e284a4155b46c0d462ee574fe31d60983d +a28980b97023f9595fadf404ed4aa36898d404fe611c32fd66b70252f01618896f5f3fda71aea5595591176aabf0c619 +a50f5f9def2114f6424ff298f3b128068438f40860c2b44e9a6666f43c438f1780be73cf3de884846f1ba67f9bef0802 +b1eee2d730da715543aeb87f104aff6122cb2bf11de15d2519ff082671330a746445777924521ec98568635f26988d0c +862f6994a1ff4adfd9fb021925cccf542fca4d4b0b80fb794f97e1eb2964ef355608a98eec6e07aadd4b45ee625b2a21 +8ce69a18df2f9b9f6e94a456a7d94842c61dea9b00892da7cf5c08144de9be39b8c304aeca8b2e4222f87ba367e61006 +b5f325b1cecd435f5346b6bc562d92f264f1a6d91be41d612df012684fdd69e86063db077bc11ea4e22c5f2a13ae7bee +85526870a911127835446cb83db8986b12d5637d59e0f139ad6501ac949a397a6c73bd2e7fba731b1bb357efe068242c +8552247d3f7778697f77389717def5a149fc20f677914048e1ed41553b039b5427badc930491c0bae663e67668038fd1 +a545640ee5e51f3fe5de7050e914cfe216202056cd9d642c90e89a166566f909ee575353cb43a331fde17f1c9021414e +8b51229b53cff887d4cab573ba32ec52668d197c084414a9ee5589b285481cea0c3604a50ec133105f661321c3ca50f5 +8cdc0b960522bed284d5c88b1532142863d97bbb7dc344a846dc120397570f7bd507ceb15ed97964d6a80eccfef0f28e +a40683961b0812d9d53906e795e6470addc1f30d09affebf5d4fbbd21ddfa88ce441ca5ea99c33fd121405be3f7a3757 +a527875eb2b99b4185998b5d4cf97dd0d4a937724b6ad170411fc8e2ec80f6cee2050f0dd2e6fee9a2b77252d98b9e64 +84f3a75f477c4bc4574f16ebc21aaa32924c41ced435703c4bf07c9119dd2b6e066e0c276ff902069887793378f779e0 +a3544bc22d1d0cab2d22d44ced8f7484bfe391b36991b87010394bfd5012f75d580596ffd4f42b00886749457bb6334b +b81f6eb26934b920285acc20ceef0220dd23081ba1b26e22b365d3165ce2fbae733bbc896bd0932f63dcc84f56428c68 +95e94d40a4f41090185a77bf760915a90b6a3e3ace5e53f0cb08386d438d3aa3479f0cd81081b47a9b718698817265cd +b69bd1625b3d6c17fd1f87ac6e86efa0d0d8abb69f8355a08739109831baeec03fd3cd4c765b5ff8b1e449d33d050504 +8448f4e4c043519d98552c2573b76eebf2483b82d32abb3e2bfc64a538e79e4f59c6ca92adff1e78b2f9d0a91f19e619 +8f11c42d6a221d1fda50887fb68b15acdb46979ab21d909ed529bcad6ae10a66228ff521a54a42aca0dad6547a528233 +a3adb18d7e4a882b13a067784cf80ea96a1d90f5edc61227d1f6e4da560c627688bdf6555d33fe54cab1bca242986871 +a24d333d807a48dc851932ed21cbdd7e255bad2699909234f1706ba55dea4bb6b6f8812ffc0be206755868ba8a4af3f9 +a322de66c22a606e189f7734dbb7fda5d75766d5e69ec04b4e1671d4477f5bcb9ff139ccc18879980ebc3b64ab4a2c49 +88f54b6b410a1edbf125db738d46ee1a507e69bc5a8f2f443eb787b9aa7dbd6e55014ec1e946aabeb3e27a788914fb04 +b32ee6da1dcd8d0a7fd7c1821bb1f1fe919c8922b4c1eeed56e5b068a5a6e68457c42b192cbaef5dc6d49b17fa45bc0f +8a44402da0b3a15c97b0f15db63e460506cb8bef56c457166aea5e8881087d8202724c539ef0feb97131919a73aefca8 +b967e3fead6171fa1d19fd976535d428b501baff59e118050f9901a54b12cc8e4606348454c8f0fc25bd6644e0a5532e +b7a0c9e9371c3efbbb2c6783ce2cc5f149135175f25b6d79b09c808bce74139020e77f0c616fa6dcb3d87a378532529d +a54207782ffc909cd1bb685a3aafabbc4407cda362d7b3c1b14608b6427e1696817aeb4f3f85304ac36e86d3d8caa65b +98c1da056813a7bfebc81d8db7206e3ef9b51f147d9948c088976755826cc5123c239ca5e3fe59bed18b5d0a982f3c3f +ae1c86174dfafa9c9546b17b8201719aecd359f5bbeb1900475041f2d5b8a9600d54d0000c43dd061cfda390585726ff +a8ee5a8be0bd1372a35675c87bfd64221c6696dc16e2d5e0996e481fec5cdbcb222df466c24740331d60f0521285f7d3 +8ddadbe3cf13af50d556ce8fc0dd77971ac83fad9985c3d089b1b02d1e3afc330628635a31707b32595626798ea22d45 +a5c80254baf8a1628dc77c2445ebe21fbda0de09dd458f603e6a9851071b2b7438fe74214df293dfa242c715d4375c95 +b9d83227ed2600a55cb74a7052003a317a85ca4bea50aa3e0570f4982b6fe678e464cc5156be1bd5e7bba722f95e92c5 +b56085f9f3a72bea9aa3a8dc143a96dd78513fa327b4b9ba26d475c088116cab13843c2bff80996bf3b43d3e2bddb1d6 +8fa9b39558c69a9757f1e7bc3f07295e4a433da3e6dd8c0282397d26f64c1ecd8eb3ba9824a7cacfb87496ebbb45d962 +879c6d0cb675812ed9dee68c3479a499f088068501e2677caeae035e6f538da91a49e245f5fcce135066169649872bee +91aa9fd3fed0c2a23d1edda8a6542188aeb8abee8772818769bdee4b512d431e4625a343af5d59767c468779222cf234 +a6be0bb2348c35c4143482c7ef6da9a93a5356f8545e8e9d791d6c08ed55f14d790d21ee61d3a56a2ae7f888a8fd46ca +808ee396a94e1b8755f2b13a6ffbedef9e0369e6c2e53627c9f60130c137299d0e4924d8ef367e0a7fad7f68a8c9193c +ad1086028fcdac94d5f1e7629071e7e47e30ad0190ae59aaebfb7a7ef6202ab91323a503c527e3226a23d7937af41a52 +9102bdaf79b907d1b25b2ec6b497e2d301c8eac305e848c6276b392f0ad734131a39cc02ed42989a53ca8da3d6839172 +8c976c48a45b6bc7cd7a7acea3c2d7c5f43042863b0661d5cd8763e8b50730552187a8eecf6b3d17be89110208808e77 +a2624c7e917e8297faa3af89b701953006bf02b7c95dfba00c9f3de77748bc0b13d6e15bb8d01377f4d98fb189538142 +a405f1e66783cdcfe20081bce34623ec3660950222d50b7255f8b3cc5d4369aeb366e265e5224c0204911539f0fa165e +8d69bdcaa5d883b5636ac8f8842026fcc58c5e2b71b7349844a3f5d6fbecf44443ef4f768eac376f57fb763606e92c9f +82fce0643017d16ec1c3543db95fb57bfa4855cc325f186d109539fcacf8ea15539be7c4855594d4f6dc628f5ad8a7b0 +8860e6ff58b3e8f9ae294ff2487f0d3ffae4cf54fd3e69931662dabc8efd5b237b26b3def3bcd4042869d5087d22afcf +88c80c442251e11c558771f0484f56dc0ed1b7340757893a49acbf96006aa73dfc3668208abea6f65375611278afb02a +8be3d18c6b4aa8e56fcd74a2aacb76f80b518a360814f71edb9ccf3d144bfd247c03f77500f728a62fca7a2e45e504c5 +8b8ebf0df95c3f9b1c9b80469dc0d323784fd4a53f5c5357bb3f250a135f4619498af5700fe54ad08744576588b3dfff +a8d88abdaadd9c2a66bc8db3072032f63ed8f928d64fdb5f810a65074efc7e830d56e0e738175579f6660738b92d0c65 +a0a10b5d1a525eb846b36357983c6b816b8c387d3890af62efb20f50b1cb6dd69549bbef14dab939f1213118a1ae8ec2 +8aadf9b895aeb8fdc9987daa937e25d6964cbd5ec5d176f5cdf2f0c73f6f145f0f9759e7560ab740bf623a3279736c37 +99aeda8a495031cc5bdf9b842a4d7647c55004576a0edc0bd9b985d60182608361ed5459a9d4b21aa8e2bd353d10a086 +832c8b3bfcd6e68eee4b100d58014522de9d4cefa99498bc06c6dca83741e4572e20778e0d846884b33439f160932bca +841f56ebefc0823ab484fc445d62f914e13957e47904419e42771aa605e33ab16c44f781f6f9aa42e3a1baf377f54b42 +a6e40271d419e295a182725d3a9b541ffd343f23e37549c51ecaa20d13cf0c8d282d6d15b24def5702bfee8ba10b12ac +8ac00925ac6187a4c5cde48ea2a4eaf99a607e58b2c617ee6f01df30d03fafada2f0469178dd960d9d64cbd33a0087d8 +b6b80916b540f8a0fe4f23b1a06e2b830008ad138271d5ba3cd16d6619e521fe2a7623c16c41cba48950793386eea942 +8412c0857b96a650e73af9d93087d4109dd092ddf82188e514f18fcac644f44d4d62550bfa63947f2d574a2e9d995bbb +b871395baa28b857e992a28ac7f6d95ec461934b120a688a387e78498eb26a15913b0228488c3e2360391c6b7260b504 +926e2d25c58c679be77d0e27ec3b580645956ba6f13adcbc2ea548ee1b7925c61fcf74c582337a3b999e5427b3f752f2 +a165fa43fecae9b913d5dcfc232568e3e7b8b320ce96b13800035d52844c38fd5dbf7c4d564241d860c023049de4bcbc +b4976d7572fd9cc0ee3f24888634433f725230a7a2159405946a79315bc19e2fc371448c1c9d52bf91539fd1fe39574b +a6b461eb72e07a9e859b9e16dfa5907f4ac92a5a7ca4368b518e4a508dc43f9b4be59db6849739f3ef4c44967b63b103 +b976606d3089345d0bc501a43525d9dca59cf0b25b50dfc8a61c5bd30fac2467331f0638fab2dc68838aa6ee8d2b6bc9 +b16ea61c855da96e180abf7647fa4d9dd6fd90adebadb4c5ed4d7cd24737e500212628fca69615d89cb40e9826e5a214 +95a3e3162eb5ea27a613f8c188f2e0dcc5cbd5b68c239858b989b004d87113e6aa3209fa9fad0ee6ecef42814ba9db1a +b6a026ab56d3224220e5bce8275d023c8d39d1bdf7eec3b0923429b7d5ef18cf613a3591d364be8727bb1fa0ba11eabb +949f117e2e141e25972ee9ccdd0b7a21150de7bbf92bbd89624a0c5f5a88da7b2b172ba2e9e94e1768081f260c2a2f8d +b7c5e9e6630287d2a20a2dfb783ffe6a6ff104ff627c6e4e4342acc2f3eb6e60e9c22f465f8a8dc58c42f49840eca435 +872be5a75c3b85de21447bb06ac9eb610f3a80759f516a2f99304930ddf921f34cbffc7727989cdd7181d5fc62483954 +a50976ea5297d797d220932856afdd214d1248230c9dcd840469ecc28ea9f305b6d7b38339fedb0c00b5251d77af8c95 +80b360f8b44914ff6f0ffbd8b5360e3cabe08639f6fe06d0c1526b1fe9fe9f18c497f1752580b30e950abd3e538ad416 +a2f98f9bf7fac78c9da6bb41de267742a9d31cf5a04b2fb74f551084ec329b376f651a59e1ae919b2928286fb566e495 +8b9d218a8a6c150631548e7f24bbd43f132431ae275c2b72676abbea752f554789c5ff4aac5c0eeee5529af7f2b509ef +aa21a243b07e9c7b169598bf0b102c3c280861780f83121b2ef543b780d47aaa4b1850430ee7927f33ece9847c4e0e1a +8a6f90f4ce58c8aa5d3656fe4e05acccf07a6ec188a5f3cde7bf59a8ae468e66f055ac6dfc50b6e8e98f2490d8deedc5 +8e39f77ca4b5149ffe9945ceac35d068760ba338d469d57c14f626dd8c96dbe993dd7011beff727c32117298c95ee854 +83bd641c76504222880183edd42267e0582642c4993fe2c7a20ce7168e4c3cbf7586e1d2d4b08c84d9b0bf2f6b8800b8 +a9d332993cf0c1c55130e5cf3a478eb5e0bfb49c25c07538accc692ef03d82b458750a7b991cc0b41b813d361a5d31e3 +a0fc60e6a6015df9bee04cea8f20f01d02b14b6f7aa03123ab8d65da071b2d0df5012c2a69e7290baae6ed6dd29ebe07 +a2949dde2e48788ceaac7ec7243f287ffe7c3e788cdba97a4ab0772202aeef2d50382bed8bf7eff5478243f7eabe0bda +a7879373ea18572dba6cf29868ca955ffa55b8af627f29862f6487ee398b81fe3771d8721ca8e06716c5d91b9ac587cb +b3c7081e2c5306303524fbe9fe5645111a57dffd4ec25b7384da12e56376a0150ab52f9d9cc6ca7bdd950695e39b766d +a634a6a19d52dcb9f823352b36c345d2de54b75197bcd90528d27830bd6606d1a9971170de0849ed5010afa9f031d5be +88f2062f405fa181cfdb8475eaf52906587382c666ca09a9522537cfebbc7de8337be12a7fd0db6d6f2f7ab5aefab892 +b1f0058c1f273191247b98783b2a6f5aa716cf799a8370627fc3456683f03a624d0523b63a154fe9243c0dfd5b37c460 +ae39a227cc05852437d87be6a446782c3d7fbe6282e25cf57b6b6e12b189bdc0d4a6e2c3a60b3979256b6b5baf8f1c5f +802a1af228ab0c053b940e695e7ef3338f5be7acf4e5ed01ac8498e55b492d3a9f07996b1700a84e22f0b589638909cd +a36490832f20e4b2f9e79ee358b66d413f034d6a387534b264cdeac2bca96e8b5bcbdd28d1e98c44498032a8e63d94d2 +8728c9a87db2d006855cb304bba54c3c704bf8f1228ae53a8da66ca93b2dac7e980a2a74f402f22b9bc40cd726e9c438 +a08f08ab0c0a1340e53b3592635e256d0025c4700559939aeb9010ed63f7047c8021b4210088f3605f5c14fb51d1c613 +9670fd7e2d90f241e8e05f9f0b475aa260a5fb99aa1c9e61cd023cbad8ed1270ae912f168e1170e62a0f6d319cf45f49 +a35e60f2dd04f098bf274d2999c3447730fe3e54a8aff703bc5a3c274d22f97db4104d61a37417d93d52276b27ef8f31 +859df7a21bc35daec5695201bd69333dc4f0f9e4328f2b75a223e6615b22b29d63b44d338413ca97eb74f15563628cb7 +b2b44ad3e93bc076548acdf2477803203108b89ecc1d0a19c3fb9814d6b342afc420c20f75e9c2188ad75fdb0d34bb2d +941173ee2c87765d10758746d103b667b1227301e1bcfecef2f38f9ab612496a9abd3050cef5537bf28cfecd2aacc449 +92b0bea30ebed20ac30648efb37bac2b865daaa514316e6f5470e1de6cb84651ff77c127aa7beed4521bda5e8fc81122 +af17bf813bb238cf8bb437433f816786612209180a6c0a1d5141292dc2d2c37164ef13bfc50c718bfcc6ce26369298a2 +8461fd951bdfda099318e05cc6f75698784b033f15a71bce26165f0ce421fd632d50df9eeced474838c0050b596e672c +83281aa18ae4b01e8201e1f64248cc6444c92ee846ae72adb178cef356531558597d84ff93a05abf76bfe313eb7dbe86 +b62b150f73999c341daa4d2f7328d2f6ca1ef3b549e01df58182e42927537fc7971c360fe8264af724f4c0247850ef12 +a7022a201f79c012f982b574c714d813064838a04f56964d1186691413757befeeaada063e7884297606e0eea1b1ed43 +a42ac9e8be88e143853fd8e6a9ff21a0461801f0ac76b69cca669597f9af17ecb62cccdcdcbe7f19b62ab93d7f838406 +80f1ca73b6ba3a2fbae6b79b39c0be8c39df81862d46c4990c87cbf45b87996db7859d833abc20af2fcb4faf059c436a +b355943e04132d5521d7bbe49aea26f6aa1c32f5d0853e77cc2400595325e923a82e0ff7601d1aee79f45fd8a254f6ae +87142c891d93e539b31d0b5ead9ea600b9c84db9be9369ff150a8312fe3d10513f4c5b4d483a82b42bc65c45dd9dd3bd +823c3d7f6dda98a9d8c42b3fee28d3154a95451402accadb6cf75fc45d2653c46a569be75a433094fa9e09c0d5cf1c90 +b3c3497fe7356525c1336435976e79ec59c5624c2fb6185ee09ca0510d58b1e392965e25df8a74d90d464c4e8bb1422b +88c48d83e8ddc0d7eea051f3d0e21bc0d3a0bb2b6a39ece76750c1c90c382a538c9a35dc9478b8ceb8157dcccbbf187a +93da81a8939f5f58b668fefdc6f5f7eca6dc1133054de4910b651f8b4a3267af1e44d5a1c9e5964dc7ab741eb146894b +8b396e64985451ac337f16be61105106e262e381ea04660add0b032409b986e1ac64da3bc2feae788e24e9cb431d8668 +9472068b6e331ea67e9b5fbf8057672da93c209d7ded51e2914dbb98dccd8c72b7079b51fd97a7190f8fc8712c431538 +ac47e1446cb92b0a7406f45c708567f520900dfa0070d5e91783139d1bfc946d6e242e2c7b3bf4020500b9f867139709 +896053706869fb26bb6f7933b3d9c7dd6db5c6bd1269c7a0e222b73039e2327d44bda7d7ae82bf5988808b9831d78bcd +a55e397fa7a02321a9fe686654c86083ecedb5757586d7c0250ec813ca6d37151a12061d5feca4691a0fd59d2f0fdd81 +ae23f08ac2b370d845036518f1bddb7fea8dc59371c288a6af310486effeb61963f2eef031ca90f9bdbcf0e475b67068 +b5462921597a79f66c0fec8d4c7cfd89f427692a7ce30d787e6fd6acd2377f238ec74689a0fdbe8ef3c9c9bd24b908dc +ae67e8ea7c46e29e6aae6005131c29472768326819aa294aaf5a280d877de377b44959adb1348fa3e929dcbc3ae1f2c0 +84962b4c66500a20c4424191bdfb619a46cda35bdb34c2d61edcb0b0494f7f61dd5bf8f743302842026b7b7d49edd4b5 +846f76286dc3cc59cb15e5dabb72a54a27c78190631df832d3649b2952fa0408ecde7d4dfdae7046c728efa29879fb51 +8f76c854eaee8b699547e07ad286f7dadfa6974c1328d12502bd7630ae619f6129272fdd15e2137ffef0143c42730977 +8007b163d4ea4ec6d79e7a2aa19d06f388da0b3a56f3ee121441584e22a246c0e792431655632bf6e5e02cb86914eebf +ac4d2cecc1f33e6fb73892980b61e62095ddff5fd6167f53ca93d507328b3c05440729a277dc3649302045b734398af1 +92d2a88f2e9c9875abaff0d42624ccb6d65401de7127b5d42c25e6adccd7a664504c5861618f9031ced8aeb08b779f06 +a832c1821c1b220eb003fc532af02c81196e98df058cdcc9c9748832558362915ea77526937f30a2f74f25073cb89afb +b6f947ab4cc2baec100ed8ec7739a2fd2f9504c982b39ab84a4516015ca56aea8eef5545cfc057dd44c69b42125fb718 +b24afacf2e90da067e5c050d2a63878ee17aaf8fd446536f2462da4f162de87b7544e92c410d35bf2172465940c19349 +b7a0aa92deac71eaab07be8fa43086e071e5580f5dbf9b624427bdd7764605d27303ae86e5165bed30229c0c11958c38 +b0d1d5bfa1823392c5cf6ed927c1b9e84a09a24b284c2cd8fcb5fda8e392c7c59412d8f74eb7c48c6851dff23ae66f58 +a24125ef03a92d2279fb384186ca0274373509cfec90b34a575490486098438932ee1be0334262d22d5f7d3db91efe67 +83e08e5fba9e8e11c164373794f4067b9b472d54f57f4dbe3c241cf7b5b7374102de9d458018a8c51ab3aed1dddf146f +9453101b77bb915ed40990e1e1d2c08ea8ec5deb5b571b0c50d45d1c55c2e2512ec0ceca616ff0376a65678a961d344d +92a0516e9eb6ad233d6b165a8d64a062ce189b25f95d1b3264d6b58da9c8d17da2cd1f534800c43efcf2be73556cd2ff +958d0b5d7d8faf25d2816aa6a2c5770592ad448db778dd9b374085baa66c755b129822632eaabcb65ee35f0bf4b73634 +90a749de8728b301ad2a6b044e8c5fd646ccd8d20220e125cba97667e0bb1d0a62f6e3143b28f3d93f69cdc6aa04122a +84bd34c8d8f74dec07595812058db24d62133c11afed5eb2a8320d3bfc28e442c7f0cfd51011b7b0bb3e5409cb7b6290 +aecc250b556115d97b553ad7b2153f1d69e543e087890000eaa60f4368b736921d0342ce5563124f129096f5d5e2ca9d +977f17ac82ed1fbf422f9b95feb3047a182a27b00960296d804fd74d54bb39ad2c055e665c1240d2ad2e06a3d7501b00 +af5be9846bd4879ebe0af5e7ad253a632f05aedfe306d31fe6debe701ba5aa4e33b65efc05043bc73aadb199f94baed4 +9199e12ec5f2aaaeed6db5561d2dcc1a8fe9c0854f1a069cba090d2dff5e5ba52b10c841ccbd49006a91d881f206150d +8f4a96a96ed8ceaf3beba026c89848c9ca4e6452ce23b7cf34d12f9cc532984a498e051de77745bdc17c7c44c31b7c30 +af3f2a3dbe8652c4bfca0d37fb723f0e66aab4f91b91a625114af1377ad923da8d36da83f75deb7a3219cd63135a3118 +a6d46963195df8962f7aa791d104c709c38caa438ddd192f7647a884282e81f748c94cdf0bb25d38a7b0dc1b1d7bbcf7 +86f3de4b22c42d3e4b24b16e6e8033e60120af341781ab70ae390cb7b5c5216f6e7945313c2e04261a51814a8cb5db92 +b9f86792e3922896cfd847d8ff123ff8d69ecf34968fb3de3f54532f6cd1112b5d34eeabdca46ae64ad9f6e7e5b55edc +83edfbcbc4968381d1e91ab813b3c74ab940eaf6358c226f79182f8b21148ec130685fd91b0ea65916b0a50bccf524ea +93b61daca7a8880b7926398760f50016f2558b0bab74c21181280a1baf3414fc539911bb0b79c4288d29d3c4ad0f4417 +ad541aeb83a47526d38f2e47a5ce7e23a9adabe5efeae03541026881e6d5ef07da3ac1a6ed466ca924fa8e7a91fcff88 +ac4bba31723875025640ed6426003ed8529215a44c9ffd44f37e928feef9fc4dfa889088131c9be3da87e8f3fdf55975 +88fa4d49096586bc9d29592909c38ea3def24629feacd378cc5335b70d13814d6dac415f8c699ee1bf4fe8b85eb89b38 +b67d0b76cbd0d79b71f4673b96e77b6cda516b8faa1510cfe58ff38cc19000bb5d73ff8418b3dab8c1c7960cb9c81e36 +98b4f8766810f0cfecf67bd59f8c58989eb66c07d3dfeee4f4bbce8fd1fce7cc4f69468372eaec7d690748543bd9691d +8445891af3c298b588dec443beacdf41536adb84c812c413a2b843fd398e484eb379075c64066b460839b5fe8f80177c +b603635c3ed6fdc013e2a091fc5164e09acf5f6a00347d87c6ebadb1f44e52ff1a5f0466b91f3f7ffc47d25753e44b75 +87ec2fc928174599a9dafe7538fec7dcf72e6873b17d953ed50708afff0da37653758b52b7cafa0bf50dfcf1eafbb46c +b9dbd0e704d047a457d60efe6822dc679e79846e4cbcb11fa6c02079d65673ee19bbf0d14e8b7b200b9205f4738df7c7 +9591ec7080f3f5ba11197a41f476f9ba17880f414d74f821a072ec5061eab040a2acba3d9856ff8555dfe5eaeb14ca19 +b34c9d1805b5f1ce38a42b800dec4e7f3eb8c38e7d2b0a525378e048426fed150dbfe9cc61f5db82b406d1b9ff2d10bf +a36fdc649dc08f059dfa361e3969d96b4cc4a1ebf10b0cd01a7dd708430979e8d870961fef85878f8779b8e23caafb18 +88dfc739a80c16c95d9d6f73c3357a92d82fa8c3c670c72bee0f1e4bac9ec338e1751eb786eda3e10f747dd7a686900f +84a535ad04f0961756c61c70001903a9adf13126983c11709430a18133c4b4040d17a33765b4a06968f5d536f4bfb5c5 +8c86d695052a2d2571c5ace744f2239840ef21bb88e742f050c7fa737cd925418ecef0971333eb89daa6b3ddfede268c +8e9a700157069dc91e08ddcbdde3a9ad570272ad225844238f1015004239c542fceb0acce6d116c292a55f0d55b6175e +84d659e7f94e4c1d15526f47bc5877a4ef761c2a5f76ec8b09c3a9a30992d41b0e2e38ed0c0106a6b6c86d670c4235f3 +a99253d45d7863db1d27c0ab561fb85da8c025ba578b4b165528d0f20c511a9ca9aff722f4ff7004843f618eb8fced95 +89a3cacb15b84b20e95cd6135550146bbe6c47632cc6d6e14d825a0c79b1e02b66f05d57d1260cb947dc4ae5b0283882 +8385b1555e794801226c44bd5e878cbe68aeac0a19315625a8e5ea0c3526b58cdd4f53f9a14a167a5e8a293b530d615a +b68c729e9df66c5cd22af4909fb3b0057b6a231c4a31cd6bf0fa0e53c5809419d15feb483de6e9408b052458e819b097 +924f56eda269ec7ec2fc20c5731bf7f521546ddf573ccbe145592f1c9fee5134747eb648d9335119a8066ca50a1f7e50 +b2100a26b9c3bec7ec5a53f0febbf56303f199be2f26b2d564cfee2adc65483b84192354f2865c2f4c035fa16252ae55 +8f64dbed62e638563967ec1605a83216aed17eb99aa618c0543d74771ea8f60bbb850c88608d4f8584f922e30a8a0a72 +b31b9e1ffe8d7260479c9413f8e680f3fe391ae8fcf44fcca3000d9b2473a40c1d32299f8f63865a57579a2d6c7e9f08 +a5b1d136142eb23e322c6c07cb838a3f58ab6925472352ebd0bb47041a0d8729e1074ca223922f3a7a672ced7a1e562d +8d9470a5a15d833a447b5f108333d50f30aa7659e331c3f8080b1e928a99922edc650466a2f54f3d48afdb34bff42142 +866368f5891564e5b2de37ad21ff0345c01129a14ea5667f9b64aad12d13ec034622872e414743af0bf20adb2041b497 +88ef9c2ebf25fd0c04b7cfa35fbac2e4156d2f1043fa9f98998b2aa402c8f9a4f1039e782451a46840f3e0e4b3fa47d3 +94ba04a4859273697e264a2d238dc5c9ff573ebc91e4796ea58eebe4080c1bf991255ab2ad8fb1e0301ce7b79cc6e69b +86b6bd0953309a086e526211bf1a99327269304aa74d8cdc994cee63c3a2d4b883e832b0635888dff2a13f1b02eb8df4 +843ea6ea5f2c7a1fd50be56a5765dcce3ea61c99b77c1a729ee0cd8ec706385ac7062e603479d4c8d3527f030762d049 +8d3675195a3b06f2d935d45becc59f9fa8fa440c8df80c029775e47fe9c90e20f7c8e4cc9a2542dd6bfe87536c428f0d +8978580b0c9b0aa3ab2d47e3cfd92fa891d3ddee57829ee4f9780e8e651900457d8e759d1a9b3e8f6ae366e4b57f2865 +890112ec81d0f24b0dfbb4d228e418eff02ae63dc691caf59c1d103e1d194e6e2550e1bec41c0bfdb74fed454f621d0c +97da00bd4b19d1e88caff7f95b8b9a7d29bc0afe85d0c6a163b4b9ef336f0e90e2c49ce6777024bb08df908cc04ea1ca +b458268d275a5211106ccaa8333ce796ef2939b1c4517e502b6462e1f904b41184a89c3954e7c4f933d68b87427a7bfd +aac9c043ba8ba9283e8428044e6459f982413380ee7005a996dc3cc468f6a21001ecaa3b845ce2e73644c2e721940033 +82145013c2155a1200246a1e8720adf8a1d1436b10d0854369d5b1b6208353e484dd16ce59280c6be84a223f2d45e5e2 +b301bafa041f9b203a46beab5f16160d463aa92117c77a3dc6a9261a35645991b9bafcc186c8891ca95021bd35f7f971 +a531b8d2ac3de09b92080a8d8857efa48fb6a048595279110e5104fee7db1dd7f3cfb8a9c45c0ed981cbad101082e335 +a22ac1d627d08a32a8abd41504b5222047c87d558ffae4232cefdeb6a3dc2a8671a4d8ddfba2ff9068a9a3ffb0fe99b1 +b8d9f0e383c35afb6d69be7ff04f31e25c74dd5751f0e51290c18814fbb49ee1486649e64355c80e93a3d9278bd21229 +8165babccd13033a3614c878be749dfa1087ecbeee8e95abcfffe3aa06695711122cb94477a4d55cffd2febf0c1173de +a4c1bc84ecb9d995d1d21c2804adf25621676d60334bd359dac3a2ec5dc8de567aa2831c10147034025fb3e3afb33c4b +b77307cab8e7cb21e4038493058fb6db9e2ec91dda9d7f96f25acbc90309daf7b6d8a205682143ee35d675e9800c3b08 +aaf7466083cd1f325ba860efe3faf4cebe6a5eecf52c3e8375d72043a5cfc8e6cb4b40f8e48f97266e84f0d488e8badf +9264a05a3abc2a5b4958f957f3a486a5eb3ddd10ff57aa6943c9430d0cfa01d63b72695b1ade50ac1b302d312175e702 +b3f9e4c589ad28b1eceed99dc9980fac832524cfcbe4a486dfeedb4b97c080e24bdb3967e9ca63d2240e77f9addfaefd +b2c1e253a78e7179e5d67204422e0debfa09c231970b1bfb70f31a8d77c7f5059a095ca79d2e9830f12c4a8f88881516 +81865a8a25913d1072cb5fd9505c73e0fde45e4c781ddd20fb0a7560d8b1cd5e1f63881c6efc05360e9204dfa6c3ce16 +ab71c2ea7fa7853469a2236dedb344a19a6130dc96d5fd6d87d42d3fffda172557d203b7688ce0f86acd913ce362e6cd +8aa2051bc3926c7bd63565f3782e6f77da824cb3b22bb056aa1c5bccfa274c0d9e49a91df62d0e88876e2bd7776e44b9 +b94e7074167745323d1d353efe7cfb71f40a390e0232354d5dfd041ef523ac8f118fb6dcc42bf16c796e3f61258f36f8 +8210fcf01267300cb1ccf650679cf6e1ee46df24ae4be5364c5ff715332746c113d680c9a8be3f17cacaeb3a7ba226ce +905ac223568eedc5acd8b54e892be05a21abbb4083c5dbec919129f9d9ffa2c4661d78d43bf5656d8d7aafa06f89d647 +a6e93da7e0c998e6ce2592d1aa87d12bf44e71bec12b825139d56682cdce8f0ba6dbfe9441a9989e10578479351a3d9d +acde928a5e2df0d65de595288f2b81838155d5673013100a49b0cb0eb3d633237af1378148539e33ccd1b9a897f0fec3 +a6e1a47e77f0114be6ae7acd2a51e6a9e38415cce7726373988153cdd5d4f86ef58f3309adc5681af4a159300ed4e5b5 +ad2b6a0d72f454054cb0c2ebc42cd59ff2da7990526bd4c9886003ba63b1302a8343628b8fe3295d3a15aa85150e0969 +b0bc3aea89428d7918c2ee0cc57f159fba134dad224d0e72d21a359ca75b08fbb4373542f57a6408352033e1769f72c6 +aad0497525163b572f135fad23fdd8763631f11deeaf61dea5c423f784fe1449c866040f303555920dc25e39cdb2e9b4 +8ce5d8310d2e17342bf881d517c9afc484d12e1f4b4b08ad026b023d98cba410cd9a7cc8e2c3c63456652a19278b6960 +8d9d57dbb24d68b6152337872bd5d422198da773174ade94b633f7c7f27670ff91969579583532ae7d8fe662c6d8a3b0 +855a1c2d83becb3f02a8f9a83519d1cb112102b61d4cdd396844b5206e606b3fefdbcc5aa8751da2b256d987d74d9506 +90eb7e6f938651f733cf81fcd2e7e8f611b627f8d94d4ac17ac00de6c2b841e4f80cada07f4063a13ae87b4a7736ca28 +8161459a21d55e7f5f1cecfc1595c7f468406a82080bfa46d7fb1af4b5ec0cd2064c2c851949483db2aa376e9df418e6 +8344ccd322b2072479f8db2ab3e46df89f536408cba0596f1e4ec6c1957ff0c73f3840990f9028ae0f21c1e9a729d7df +929be2190ddd54a5afe98c3b77591d1eae0ab2c9816dc6fe47508d9863d58f1ea029d503938c8d9e387c5e80047d6f1e +856e3d1f701688c650c258fecd78139ce68e19de5198cf1cd7bb11eba9d0f1c5af958884f58df10e3f9a08d8843f3406 +8490ae5221e27a45a37ca97d99a19a8867bcc026a94f08bdccfbb4b6fa09b83c96b37ec7e0fd6ee05f4ae6141b6b64a8 +b02dbd4d647a05ac248fda13708bba0d6a9cd00cae5634c1938b4c0abbb3a1e4f00f47aa416dcd00ffcdf166330bff9a +9076164bb99ca7b1a98d1e11cb2f965f5c22866658e8259445589b80e3cb3119c8710ede18f396ba902696785619079c +aacf016920936dae63778ad171386f996f65fe98e83cfcdd75e23774f189303e65cc8ad334a7a62f9230ed2c6b7f6fa4 +a8031d46c7f2474789123469ef42e81c9c35eb245d38d8f4796bba406c02b57053f5ec554d45373ab437869a0b1af3f0 +a4b76cd82dc1f305a0ee053e9a4212b67f5acc5e69962a8640d190a176b73fbc2b0644f896ff3927cd708d524668ed09 +b00b029c74e6fdf7fb94df95ef1ccad025c452c19cddb5dccfb91efdcb8a9a1c17847cfa4486eae4f510e8a6c1f0791a +9455e5235f29a73e9f1a707a97ddb104c55b9d6a92cc9952600d49f0447d38ea073ee5cf0d13f7f55f12b4a5132f4b10 +ae118847542ed1084d269e8f3b503d0b6571a2c077def116ad685dcca2fca3dcb3f86e3f244284bdcd5ae7ac968d08a5 +8dcb4965cd57e8b89cd71d6fc700d66caa805bfd29ab71357961527a7894e082d49145c2614b670dcb231ab9050d0663 +add6ed14f3183f4acc73feea19b22c9a330e431c674e5034924da31b69e8c02d79b570d12ef771a04215c4809e0f8a80 +96ae7e110412ee87d0478fdbdbaab290eb0b6edd741bb864961845e87fd44bcbe630371060b8104d8bf17c41f2e3fca0 +a20db17f384e9573ca0928af61affab6ff9dd244296b69b026d737f0c6cd28568846eca8dadf903ee0eecbb47368351d +937bfdf5feb0797863bc7c1be4dcc4f2423787952a3c77dfa3bfe7356f5dbcc4daebde976b84fc6bd97d5124fb8f85c9 +a7050cc780445c124e46bba1acc0347ddcfa09a85b35a52cc5808bf412c859c0c680c0a82218f15a6daeefe73f0d0309 +a9d9b93450e7630f1c018ea4e6a5ca4c19baa4b662eadfbe5c798fe798d8a3775ed1eb12bd96a458806b37ab82bdc10a +a52a4d5639e718380915daaefad7de60764d2d795443a3db7aeab5e16a1b8faa9441a4ccc6e809d8f78b0ac13eef3409 +8e6f72b6664a8433b032849b03af68f9376b3c16c0bc86842c43fc7bf31e40bc9fc105952d5c5780c4afa19d7b802caa +a107ae72f037000c6ee14093de8e9f2c92aa5f89a0a20007f4126419e5cb982469c32187e51a820f94805c9fccd51365 +9708218f9a984fe03abc4e699a4f3378a06530414a2e95e12ca657f031ef2e839c23fd83f96a4ba72f8203d54a1a1e82 +b9129770f4c5fcac999e98c171d67e148abd145e0bf2a36848eb18783bb98dff2c5cef8b7407f2af188de1fae9571b1c +88cc9db8ff27eb583871eeeb517db83039b85404d735517c0c850bdfa99ae1b57fd24cf661ab60b4726878c17e047f37 +a358c9aadc705a11722df49f90b17a2a6ba057b2e652246dc6131aaf23af66c1ca4ac0d5f11073a304f1a1b006bc0aa5 +ac79f25af6364a013ba9b82175ccee143309832df8f9c3f62c193660253679284624e38196733fb2af733488ab1a556e +82338e3ed162274d41a1783f44ae53329610134e6c62565353fbcc81131e88ce9f8a729d01e59e6d73695a378315111b +aa5ddcabf580fd43b6b0c3c8be45ffd26c9de8fa8d4546bb92d34f05469642b92a237d0806a1ad354f3046a4fcf14a92 +b308d2c292052a8e17862c52710140ffafa0b3dbedd6a1b6334934b059fe03e49883529d6baf8b361c6e67b3fbf70100 +96d870a15c833dddd8545b695139733d4a4c07d6206771a1524500c12607048731c49ec4ac26f5acc92dd9b974b2172c +8e99ee9ed51956d05faaf5038bffd48a2957917a76d9974a78df6c1ff3c5423c5d346778f55de07098b578ad623a390e +a19052d0b4b89b26172c292bbf6fd73e7486e7fd3a63c7a501bbd5cf7244e8e8ce3c1113624086b7cdf1a7693fdad8b5 +958957caf99dc4bb6d3c0bc4821be10e3a816bd0ba18094603b56d9d2d1383ccc3ee8bc36d2d0aea90c8a119d4457eb4 +8482589af6c3fc4aa0a07db201d8c0d750dd21ae5446ff7a2f44decf5bff50965fd6338745d179c67ea54095ecd3add4 +8a088cc12cf618761eaa93da12c9158b050c86f10cd9f865b451c69e076c7e5b5a023e2f91c2e1eed2b40746ca06a643 +85e81101590597d7671f606bd1d7d6220c80d3c62e9f20423e734482c94547714a6ac0307e86847cce91de46503c6a8a +b1bd39b481fc452d9abf0fcb73b48c501aaae1414c1c073499e079f719c4e034da1118da4ff5e0ce1c5a71d8af3f4279 +942ae5f64ac7a5353e1deb2213f68aa39daa16bff63eb5c69fc8d9260e59178c0452227b982005f720a3c858542246c8 +99fea18230e39df925f98e26ff03ab959cae7044d773de84647d105dfa75fd602b4f519c8e9d9f226ec0e0de0140e168 +97b9841af4efd2bfd56b9e7cd2275bc1b4ff5606728f1f2b6e24630dbe44bc96f4f2132f7103bca6c37057fc792aeaab +94cdad044a6ab29e646ed30022c6f9a30d259f38043afcea0feceef0edc5f45297770a30718cbfec5ae7d6137f55fe08 +a533a5efa74e67e429b736bb60f2ccab74d3919214351fe01f40a191e3ec321c61f54dd236f2d606c623ad556d9a8b63 +b7bd0bb72cd537660e081f420545f50a6751bb4dd25fde25e8218cab2885dd81ffe3b888d608a396dfcb78d75ba03f3f +b1479e7aa34594ec8a45a97611d377206597149ece991a8cef1399738e99c3fa124a40396a356ab2ea135550a9f6a89f +b75570fc94b491aef11f70ef82aeb00b351c17d216770f9f3bd87f3b5ac90893d70f319b8e0d2450dc8e21b57e26df94 +a5e3f3ab112530fe5c3b41167f7db5708e65479b765b941ce137d647adb4f03781f7821bb4de80c5dc282c6d2680a13d +b9b9c81b4cac7aca7e7c7baac2369d763dd9846c9821536d7467b1a7ec2e2a87b22637ab8bbeddb61879a64d111aa345 +b1e3ee2c4dd03a60b2991d116c372de18f18fe279f712829b61c904103a2bd66202083925bc816d07884982e52a03212 +a13f0593791dbbd360b4f34af42d5cc275816a8db4b82503fe7c2ff6acc22ae4bd9581a1c8c236f682d5c4c02cc274cc +86ba8238d3ed490abcc3f9ecc541305876315fb71bca8aaf87538012daab019992753bf1e10f8670e33bff0d36db0bf0 +b65fbb89fafb0e2a66fe547a60246d00b98fe2cb65db4922d9cef6668de7b2f4bb6c25970f1e112df06b4d1d953d3f34 +abb2d413e6f9e3c5f582e6020f879104473a829380b96a28123eb2bdd41a7a195f769b6ac70b35ba52a9fee9d6a289c3 +88ec764573e501c9d69098a11ea1ad20cdc171362f76eb215129cfcca43460140741ea06cee65a1f21b708afb6f9d5b0 +a7aaec27246a3337911b0201f4c5b746e45780598004dac15d9d15e5682b4c688158adffdef7179abb654f686e4c6adc +a1128589258f1fbfa33341604c3cb07f2a30c651086f90dce63ae48b4f01782e27c3829de5102f847cde140374567c58 +aaf2b149c1ca9352c94cc201125452b1ed7ca7c361ed022d626899426cb2d4cc915d76c58fa58b3ad4a6284a9ae1bc45 +aaf5c71b18b27cd8fe1a9028027f2293f0753d400481655c0d88b081f150d0292fb9bd3e6acabb343a6afb4afdb103b5 +947c0257d1fb29ecc26c4dc5eab977ebb47d698b48f9357ce8ff2d2ed461c5725228cc354a285d2331a60d20de09ff67 +b73e996fa30f581699052ed06054c474ebdf3ae662c4dc6f889e827b8b6263df67aeff7f2c7f2919df319a99bdfdceb1 +b696355d3f742dd1bf5f6fbb8eee234e74653131278861bf5a76db85768f0988a73084e1ae03c2100644a1fa86a49688 +b0abca296a8898ac5897f61c50402bd96b59a7932de61b6e3c073d880d39fc8e109998c9dba666b774415edddcff1997 +b7abe07643a82a7cb409ee4177616e4f91ec1cf733699bf24dec90da0617fe3b52622edec6e12f54897c4b288278e4f3 +8a3fae76993edbc81d7b47f049279f4dd5c408133436605d934dee0eadde187d03e6483409713db122a2a412cd631647 +82eb8e48becfdf06b2d1b93bf072c35df210cf64ed6086267033ad219bf130c55ee60718f28a0e1cad7bc0a39d940260 +a88f783e32944a82ea1ea4206e52c4bcf9962b4232e3c3b45bd72932ee1082527bf80864ce82497e5a8e40f2a60962d0 +830cf6b1e99430ae93a3f26fbfb92c741c895b017924dcd9e418c3dc4a5b21105850a8dd2536fa052667e508b90738f2 +990dce4c2c6f44bb6870328fba6aa2a26b0b8b2d57bfb24acf398b1edc0f3790665275f650884bd438d5403973469fa2 +a2e5b6232d81c94bcb7fed782e2d00ff70fc86a3abddbe4332cb0544b4e109ae9639a180ae4c1f416752ed668d918420 +b4cdf7c2b3753c8d96d92eb3d5fa984fef5d346a76dc5016552069e3f110356b82e9585b9c2f5313c76ffaecef3d6fd8 +83b23b87f91d8d602bff3a4aa1ead39fcc04b26cf113a9da6d2bd08ba7ea827f10b69a699c16911605b0126a9132140f +8aae7a2d9daa8a2b14f9168fe82933b35587a3e9ebf0f9c37bf1f8aa015f18fb116b7fba85a25c0b5e9f4b91ba1d350b +80d1163675145cc1fab9203d5581e4cd2bed26ad49f077a7927dec88814e0bed7912e6bbe6507613b8e393d5ee3be9be +93ddeb77b6a4c62f69b11cf36646ed089dcaa491590450456a525faf5659d810323b3effa0b908000887c20ac6b12c80 +9406360a2b105c44c45ba440055e40da5c41f64057e6b35a3786526869b853472e615e6beb957b62698a2e8a93608e13 +93bfc435ab9183d11e9ad17dac977a5b7e518db720e79a99072ce7e1b8fcb13a738806f414df5a3caa3e0b8a6ce38625 +8a12402c2509053500e8456d8b77470f1bbb9785dd7995ebbbe32fd7171406c7ce7bd89a96d0f41dbc6194e8f7442f42 +aab901e35bf17e6422722c52a9da8b7062d065169bf446ef0cbf8d68167a8b92dab57320c1470fee1f4fc6100269c6e2 +8cad277d9e2ba086378190d33f1116ba40071d2cb78d41012ec605c23f13009e187d094d785012b9c55038ec96324001 +85511c72e2894e75075436a163418279f660c417e1d7792edce5f95f2a52024d1b5677e2e150bf4339ad064f70420c60 +85549ca8dcbe49d16d4b3e2b8a30495f16c0de35711978ada1e2d88ad28e80872fca3fb02deb951b8bcb01b6555492e4 +8d379ab35194fe5edf98045a088db240a643509ddc2794c9900aa6b50535476daa92fd2b0a3d3d638c2069e535cd783b +b45cfebe529556b110392cb64059f4eb4d88aaf10f1000fdd986f7f140fdd878ce529c3c69dfd2c9d06f7b1e426e38f3 +ac009efd11f0c4cdd07dd4283a8181420a2ba6a4155b32c2fed6b9f913d98e057d0f5f85e6af82efc19eb4e2a97a82df +b2c2cdffa82f614e9cb5769b7c33c7d555e264e604e9b6138e19bcfc49284721180b0781ecbf321d7e60259174da9c3c +95789960f848797abbe1c66ef05d01d920228ca1f698130c7b1e6ca73bfda82cee672d30a9787688620554e8886554ee +98444018fa01b7273d3370eeb01adc8db902d5a69b9afc0aa9eadfeb43c4356863f19078d3c0d74e80f06ecf5a5223f4 +87d20b058050542f497c6645de59b8310f6eeec53acbc084e38b85414c3ea3016da3da690853498bde1c14de1db6f391 +a5c12b3a40e54bee82a315c503c1ce431309a862458030dde02376745ec1d6b9c1dbeea481ae6883425e9dae608e444e +b9daa3bf33f0a2979785067dcece83250e7bf6deb75bb1dbbab4af9e95ddfb3d38c288cbef3f80519a8916a77a43b56c +b682ec3118f71bde6c08f06ea53378ea404f8a1c4c273dd08989f2df39d6634f6463be1d172ac0e06f0fa19ac4a62366 +a4f94fd51ecf9d2065177593970854d3dce745eebb2a6d49c573cbf64a586ae949ddfa60466aaef0c0afb22bd92e0b57 +86cd5609efd570c51adbc606c1c63759c5f4f025fcbefab6bc3045b6ad2423628c68f5931ff56fdda985168ce993cc24 +981192e31e62e45572f933e86cdd5b1d28b1790b255c491c79bd9bb4964359b0e5f94f2ae0e00ef7fe7891b5c3904932 +9898f52b57472ebc7053f7bf7ab6695ce8df6213fc7f2d6f6ea68b5baad86ec1371a29304cae1baadf15083296958d27 +b676c4a8a791ae00a2405a0c88b9544878749a7235d3a5a9f53a3f822e0c5c1b147a7f3f0fc228049dc46e87aa6b6368 +9976e10beff544e5c1645c81a807739eff90449df58ffdd8d1aa45dd50b4c62f9370538b9855a00dd596480f38ebe7a5 +a0e91404894187ec23c16d39d647ada912a2c4febfd050a1ea433c4bfdc1568b4e97a78a89ba643aca3e2782033c3c58 +91a6ea9a80476ed137eb81558ff1d55b8581663cccd41db4fc286876226b6515fd38661557419e1e46b6a3bc9cda3741 +b9e8a1e23c60335a37a16f8085f80178a17d5e055d87ffe8cf63c532af923e5a5a2d76cf078164fb577996683796caa6 +ad8e151d87a37e8df438d0a6a7c02c3f511143efb93fde8aef334d218cb25932baf9e97c2f36c633620a024a5626af3d +978f942f210e8a482015e6fdc35a4c967c67b66e6e2a17a05cc7a0f2163aed227b775d4352b0c3cca6cbf4bd5bafaf75 +b5e2e3d8b2e871c07f5899e108e133f87479959b80cb8a103fbecde00ccdbfbd997540eef33079c5cc14b1c00c009fd1 +88a164b3fefd36857f429ab10002243b053f5d386466dbb9e5135ed3c72dd369a5a25e5e2aaa11f25488535e044e2f12 +a66091c0db4e7cf05a089ec2b9ff74744354d0196968201f5e201699144b52bb13b4e68e12502727163e6db96e3565f2 +8e65aff8e37240461b7374c20bfd1d58b73a525c28994a98f723daed9486130b3189f8efe5c5efcd7f5390cc366038da +8b37c21dd7304c3aa366959ba8c77ea8b22164a67e136808b6f8e48604297f7429a6c6ecf67b1d09b8b7ec083eacd7e0 +b689b1277ad050f53da91a702516a06d7406ff33a4714ea859b3b2b69f8d0aa8f983c7e039b19c0759a3815d841fa409 +b17f7a0a182ed4937f88489e4c4e6163dcf49fd2ea4d9efbba8126c743bea951cd769752acd02e921774dc8ebcfae33b +8b7fab4f90be825ac5d782a438e55c0a86be1c314a5dbc3cc6ed60760a8a94ef296391f1f6363652200cce4c188dae67 +ab8410c4eaa2bb43b0dd271aa2836061bc95cb600b0be331dada76ddb46711ff7a4ad8c466cc1078b9f9131f0dc9d879 +9194bd7b3cc218624459d51c4d6dbc13da5d3de313448f8175650fa4cfab7cc4afcda5427b6676c3c13897dc638b401e +980f61a0f01349acd8fc9fdc88fc2c5813610c07eecb6ab14af0845a980792a60dadf13bb4437b0169ae3eff8f5984ce +b783bee24acea9c99d16434195c6940cf01fc2db135e21f16acae45a509eca3af6b9232a8aa3a86f9715c5f6a85cb1c3 +a3079931c4b90966d1faa948db847741878b5828bc60325f5ebe554dcab4adcc19ee8bce645e48a8f4a9413bb3c6a093 +801f61ac9318f6e033a99071a46ae06ed249394638c19720831fff850226363a4ae8486dd00967746298ee9f1d65462f +b34dbbed4f3bb91f28285c40f64ce60c691737cc2b2d2be5c7d0210611cd58341bb5bda51bb642d3ee2d80882e642a13 +8750af19abfb915e63c81542b13d84526a0c809179bbcc1cd8a52b29f3aba3ae0f7cf6f4f01790bf64ef7db01d8ee887 +a6ea10000eb2dd4efc242ac95bc3b3873cdd882fbeb7c9538c87e3143a263ca3a2e192b2159316a625cfb5fb0b6cdcb3 +aa40ca54bc758a6c64cb932924917581062e088b3ad43976b28f2e11d8a7dea73f1fb50aeaa0e70182bb2dc07d805bb9 +a4779dfd25b5ec9d75dfb54a4bb030364899a5e75c1492403acb19f2adc782c7ac4daeb66d2f5aeb74135afe9f318e3f +b4551e2805d63ca453f4f38b1921ac87ff687e1d70575ad38f3469d6f0608ef76b7b1b98ae1e6b1e7d928773aaab6e3b +99490ee722f96aad2743b08dd37bfeb75a8c59efaee4c9b694eaa05eb8a6bb23861a4480544c7617d04d23fd5e2543b4 +8a7050d964d295fff98ae30d77ce730a055719313457e773fcce94c4d71a9b7cf63db67e54a8aab20fb1335b0130b5d5 +903144e6bbee0a4fec17ff80fef0d2103981140c3d41776cfb184ced17f480a687dd093f6b538584327e6142812e3cd5 +a5b30f7c6939bdc24a84ae784add927fec798b5a5ee3dd156c652df020728dd6d43898be364cf5ee181725fbcffc0964 +b43d97ec2bc66af92d921a5c5c20a03ef2be2bc2c9b345f46d8287409fcbfd88ebc49d4509d64468222cd1d2021bf236 +82dc23c7f5086c9ac6b4566359bfb830d203544b0d8332a210775670f899cd9ff48b94bfeba40040c25664ebdd5cfad8 +9294cd017fea581dabb73dcc8c619904d7e022b664b0a8502c9d30f3807668af279948e7e41030ae296d492225297e95 +8d6c9dc636c8e884f9a4299e5cff06d044ebc94ad783a4b71788347ea4a336d4d048b8a9ecabae789e8fcdc459723dfb +801a80bc49e882ec81b04e37407713f033f7bdac79252dfa3dc8c5bd0229fcbd4019890e402cf843b9378df08f72ab84 +b4313ca32569d973900f6196363c0b280ddfa1b47c88d019e5f399b805b444a777950fc21ae198fc23ece52674b94abf +96f06056fd255fdabf78986e315e7c4fdf5495cf850536b7976baa97a994cc6a99c34609c33a0f2facba5e6f1026dce6 +983ed80220a5545ffd70ef5e6ac10217d82ec9cd8f9a27ee77a5ff4074092308c0e6396fc4e9932a77ddd474e61f8b55 +872a059aa630af73c4abbd076e8b333a973ffc5bdecf5dcc0600b00162184213cb19d4f601795030033beb808d5810ce +b040f318d9d3b8833da854014a44296dbd6762dd17cab13f91987256c54353b7f0800547cb645a7cc231997454209fdd +a8c4731a555308e8ce0b8325eb7a4cbf6113d07e9f41932df04480b72628d313b941c7055f1cc2ac45c7353b56e96ca9 +8c24031440b77637e045a52e5ea3f488926ab0b426148975edf066c40a4581beecc1bfb18fc4cf5f9f96dc6681b4bd28 +b39254b475abf342f301298feaa17a4b3051f30ea23a18acf59e003e2704ac96fe40691f1da387913bdf7aee6389f9a8 +a1dbf938b604ccc6d60881cc71f38df568aa02752aa44d123514154017503f6c1c335ae43e359f1487bc8934073cd9c1 +8d52aa1be9f429ece0580498d8fe9fef46d4a11f49436a82b8927f9503dacc41245907f126594c1cd30701286f8c092c +b826f396486942c0326d16f30a01b00a682c30a75553dc6ac34fd5b3e96b13c33b94738f522eebaffb59ff8c571c76e9 +aa89f51cbf6e6c3e2aa2806187b69ab3361c84e89f393f3ed284fe84db46fc3944aa44f8928e3964f9c1a1ec27048f68 +a254df0efa4203fb92b42a1cd81ca955922e14bf408262c8f7cb7dc703da0ca2c71556bd2d05b22ce9a90ad77309833d +93263c507e4d5f4e5df88e85b3d85c46ea729fb542a718b196333e2d9fb8a2e62dc1347cf146466a54ba12d200ef09d9 +922e3c4a84246d89a07aa3e90f02e04b2cea9bebc0e68b742156f702aed31b28c6dfa7ac936ea2fc2e029adf68361f98 +9a00628eeeda4ccbed3ef7834149aec4c77aac1a14bc2491ba5d1a4a2c5d29afb82ceaa5aac1c5ce1e42cdcaf53e30ba +ab3a88df36d703920f6648a295a70ffa5316c96044f39ff132937bfda768937cb6a479e9ba4a4e66b377f3a9996a88c4 +966b11526ab099d550ab33c6a9667e5cfdedf255da17a80a519d09acd78d2ea24ec18bd1ea7d8d63cf0a408f1c1fe0b3 +b5c21b9817dc32f3df9d9988aa3560e1e840d586d01cd596bc0f850ab416b6013cbf7dbfd05ac981f26014c74bd2d2b2 +9040abef5e2523e7f139c9f744a64b98fea3a57952059ffe4d5ed77fa87068203c090ef4e7f52c88fb82ea8a6fdca33e +a0dcdaeb7d3f5d30d49c004c5f478818c470187f4b0b4856812dcd1b3a86de58a99acb8ceb44c6b80c3060cf967c43a4 +b5f4be9a69e4a6719ea91104820df8623b6d1073e8ee4168de10a7e49c8babea772bcbc6b0908185e98d607e49cd3609 +8634020a5a78650015763c06121c606d2dd7b324aa17387910513dd6480fb797df541fc15b70d269b2794ad190595084 +9504d1d0fb31ff1926c89040c04d51fd1f5cddf9d7ca3d036e7fd17e7a0f767ef33cee1d8bf7e17e2bc40949e7630417 +812c72846ef6d692cf11d8f8c3de8fa78cc287303315114492667b19c702cd24d462020f1276895df26e937c38f361f8 +8c97aa5e9ef2aa9a1435ef9ddfe62e850f0360864ed5fb82bf9fef4ef04d8fb4f827dc078bc911ee275e4501edd6617c +ac5f7af5e23c8e429aaa6b6825129922b59d25b4608f07b65f21388a9ac3aa89096712f320afe6d56e44e1f0d51a4eb9 +a8c84d9a8593a0cb5be1e450960f59878a4e6b70da54a7613dfc25911b7cc9e6d789d39401b0a0d6471ab9dcdc707976 +8c9d5fd89611392c0f085ffa4fa642a181f0b9b23593deb5e10fdd1642722ca75ef34a037e88a8d03f2888fe7461f27c +8c74b05f91fb95c85e7bd41f6d9a1e41e667e68f3d19b325c1f25df1767019919edab89b92af237896cbc4e6d6dc1854 +a3caecb91640821f0b2c4981b23f2069df8d2b98ce026c1538bc096b292f5f956a5d52c1c8d6a8165a1608083ba6494b +8ae8e0c36f8b79a69176ff29855df45d0fcd9e4d1dbaed8899f8fcdece676e418ec034a6c161e2a894f0c834aaecbfd1 +b88d18c67dc3b1b6ed60ee437c441c1ed14ecddebccf43683605716f30058b1aa4ba05ff10cd8171ee97d8f58d70c094 +94f43d84dcdfd9cd19115c7d8e9c1e856828eafbfdec93b876cf0007e317e30b2ad951dbabc186aa6ef90fdee4d91990 +b44e4723f41fc1d5b0057f371e3381ae02566590b3f964b6eb07b2104f66ff78410c407235fa98d04f635694f3baca09 +addd8390173d29ca0811534d389253831fed75fed135398617836b6e70767269eacb1560b39a58f02042ca3b97fe59c4 +80bdbdacc0c358c7ea52aeacdc5f9ceb6928bcf6e7dee7c17d8ae3bf7c2372aa7a0372363888968fc0921aaf4776d5d0 +a486e2b6f04f403f9e609d69dfb3cfb992af56ecad1683271df3e3faa3b86638b81e73b39978fb829ee7133d72901f2d +a19472da57457e10c6a6307895393ddaec8f523760d66937fe26a025817319e234eaf69756ffdf1b84c81733424a96d7 +ad6a195397cbc2d75171f5e82090441eed60bd1ba42c39ef565b8b5a8281b04400678625b1dc46d617f694a7652a8e5d +8f98e721c06cec432e2221f2e1b06bb1469d916a8d88d6973acf68d1e003441d00390dafcead8ecdbf9eae4509baf5aa +91d62a0f9d13c59adfe1376ed6d057eae244d13c6b3d99be49a49e0075cf20f4085cf127774644ac93615be9ac9e5db6 +af45dec199245e2b326a0d79c4899ed44b1c0219db42602a4a6184ace0ff831a3276297af28f92e8b008ba412318e33e +8754bde54e8d2d169e6a7d6f0eae6097bc0461c395192bd00dd6f105677ea56ab384c02553ea5eeac0a65adcb0df77ee +b676afd2f5afc37a314c943d496e31b4885efcbcc2061036e370a74cfde5642bb035622d78d693bfc3136fc036c7edb4 +aab6ffe6cc234397cf1822e02912bc282dfb314e92fb5a9e10d0c34ee9b5856d4b76e166bc2bb6fcdd66aabea35ec4ef +ada6e62f90ee6b852ec4b72b22367acac2896f0df2c105beda27096583ddbedddc710d171330569f111c6e44a5b57ae7 +802139dd15241a6de663d9b810121bdd9cf11f7f8c8ca6de63f4f8e731409e40d1fd3558b4f619ed42ee54929dff1c7e +ad8e70531cec21b4e6f55be1751c2d025bd2d7d8158269b054cfe57fa29252d052ce4478ec7db6ec705789e2118d63b3 +a8e4a4271769480e1b33a28c87a150ecc0b48bfe8a15ae04152197881de4ce4b03453aefe574842424edbbe4173e1a3a +b98c65726296610cef16c5b58da5491acd33bd5c5c5af4d934a9840649ef85730fbce8018dee09ded14e278009ed094a +8e213a7861223287b860f040e5caaa563daa0b681e4e09ec79ad00cc459238e70bbeaf7486bbe182fc12650700034ec5 +a2879f9e1a556cf89b9b5b3bd8646a8cce6b60bcbc8095df44637f66a2da5858eee2dc9091475a8f64bb5aff849389cd +8a17cdb4077b9b0bcf28b93294ac5ae4c8bba8839fce0f1012b53187ac008f9858b02925fbfc421f1123afcdbd8b7753 +86fd9c11528aa43946e4415ff64a3ca6409ee6f807368c68997b18605da65e415ccd85ad913820d450cb386593de666d +8ed55923b963c3d85a91aca11c40ff9c6c7f1e2b9bc199d1a270e5fb16aa62dec0136e97866145ae9d58a493e8b1cbbb +ae32af5b5d418668ae123c639b149e5eed602404e8516da4a61db944b537a3620545e8e3d38cf10cdaea980ab2f80973 +95cb8d9e9d6762d78dde0ad73869ffaca904a7d763a378b8cc11a7933d3e7d1c8aec4271a079b1b00f8887ee5b1ea21f +b5ea20b42a3ca247f00ab5328c05f0cf194973d5f7271c66c41c5055b1ffdca136be179709e0c1de209fbe07b9820bf3 +98682f7cce471c92a8d6d15fee4ddf4d43dd97c3e3811d2913618ecacc6440b737717c07736ae4558c910e11ee98104e +a67da2c7cbba48e929ca4e4b9a6299fe01ef79eff8cc5cd3fdbdc0721a68130e4079f30ae151a573a7dcca8ecf2e684e +a9981c9f9dcbb3b0f6996f664fb2acd7573189f203be37b2b714662aa273551396abfb1f612ccde4e4c8127a050dbe4b +92d55eff8da600f886da9bf68e8eecf482faa4b268f3f286b3b3e5cc91b19604081498d4905b201bb4ec68e32b5591d9 +963e3f1728de9d719c86d390f3eb9c3f99d1928347fab0abf10dbb37d76b59ddb64d4734c977863a6cd03ffece5ca895 +93480e2de83c921056b6d8628ac37cd5ef7555ba43b0308fc13386cb0515d42c12ecd06057137aa71a7931beaf90b9ce +8feae57ff0e6a162cc81c99f45c6187d268fc0bee8c2bffc92142ef76c253d201f0e932943cf2fa312982b281ce1066b +8f8f4bd4200fb87afcd743274480220d77571928000d4197410dbb75439d368df6a06d941a6152206371d2ca9cac99e4 +8ee7f11e79af4478e0a70eb424fe8078237ad99ba6d7e6bf1a8d5e44e40abd22d404bd39b718ad6fdf4c6601f2a47665 +a98acfcec612b574943195b9ba95bebcc9c0b945c9f6b3e8760b2a4635909246a9d73b0b095c27b4ecb3339704e389b7 +b520efd19f65e81dc285031ea3593f8c5dad793e4426beb9196ab46e45346f265fd71e50adb0da657977c60ed5724128 +a3d9d0b7415280ce4dfa2429d47b2b8e37604a5157280a72cc81d541ffe44612dbb3ef7d03693fc42a569169d5842dc3 +8c29e2d0b33801f6d9a9c065a76c5cad1fb0a001506b970307e21765ee97c732a4cbf1d7c1b72d95e0ad340b3b075224 +839e21f292892a6eb596b9b1e9c4bd7c22a6fe71d3d04487c77840028d48392c5cbe73140a4e742338e0c8475cd0c1ad +8bea5c68e7743998619185bb662e958f1b4d3ca81019d84ac43c88911aab3abe4ee9bcc73cb95aa3ae87c0138801bde3 +b8f262d21a94604049e008ce03dc857848168e1efca4522acb0ccc827ffb37f545e1947843a356563a76bc6489605b66 +a7bd0842b0bb38d9943b82aa883f36f4eb8a6e8a7790d4f87faf306608f51d250a19b73984f1156cef5dd2581664614b +a993e649bd953627a88a2539dac3a12ec7f37a4c65b01425d9d34edf7ee10a71aa98f65c9e013107f824faf8aee041a9 +8e07eced75c67cb4d2ec01857f6ac1408482e6b31cb2faa249e8cf99f180575587df530c7782a7539b5221121ef48aa0 +b2f4578f26c05ecb9e2669ca744eb19d4f737321ac7d04fafd18beb7866e0fec9dd063953ae1f077b44b9c6f54db1279 +b6b3788a6c7bcaf467d19daf6ab884d549aa866970c05a9181f544ff190d043192c84fe437a75a30b78b425461cca062 +a270684903c61544b85a7041e81f65e787e1c1e23e57538fa8a69836bed0ca1673861dd29f743a1280f2f38eddd3aa83 +a9c2397c4773dcad2821266dadfd2401d013d9f35de6744f2ec201f3507700adb1e6ec4f5a453be4764da8bf68543f26 +83a3025ed6fd5df9d98be32a74e10a0d9728b560942d33ba028536fb148fc34ae87e92be2df3e420a8dfec08da495982 +90dc70c183a90bab988b4a85b7b921c8070af0e5f220364fe11afa0722990b2c971e1e98eef62d3287fedfd9411f1df7 +82d940937a6c636224d04f8e2536f93dcf20dc97a5f188875ad76c21b804aef9af10839419b61143c1f88a695959a6b4 +8017f9473ce49d498d6f168137e77e62fe553e5a51e75b519cf2cbd1ab9afdafad80fd5e6fd0860e640b0d78ca8ed947 +80573a0ec049fe1f7b3013b2839e145cd87e07c0e43826a29ef8c92516f9a30896c2ffcf3ed77ed22a6cf3101b1789d5 +953349abd2559f9824db07cec857ad54f1a05018f3076425f8dbae37f8d92a46af2c04ab7c8ec0250449541187696e98 +ab7bd2c4f05ee9a9f252c4e16a20993a12c535c3809d124bae24642616521a9768d3f19eceaf8524583f47ae1f527684 +9883b77ee834ee0112ca2f366d2a6fc213e0cf454e061438c2901a5ba35b7378f64da8adf6a476eb1562991ef5b4a5bc +89291811db308637356dbf7ed22cf07bfce33eb977734ee346e8c15a231b35d8b4443574f3fa97a40867b3e23b0bbfa4 +93d753849d7d9588d39e38217500b123a6b628a873876612d9f98b5d611f52c89c573432d2176752b5d1cc2d94899b8b +a45add3c4844db3b7a237295fc85fddc788ac1ec395a0524d2fc90a539571a247146aea4aa10eec30a95e9617c85b98d +90f94578842db7a4de672da1e483858ece5e466c73c12f725a0fc71f42ff880c9447a33fa9096839bee817536f2591e2 +b2c1b6fb031bb30460f157356562b44b4de096a0a112eab4fb3cc500aad38bc770da1fc2e73caf687a0da5e8537049c0 +afb15e15fd930929c0e3c66482068a5afe0c7b7f82e216a76c5eb1113625bfa0b045a52259d472284cfbaf4796c71456 +ad222a9a3d907713418c151b8793d5e37634354322068f8206b9d0da1a3f53b0004193713d23ec35990639a1b6c2e075 +b44a128dce97e8c4b178cdbca0a5c1b3f6e164490fac0fd68dbfe0aafa89920bb4ea420a8527e06c80dd19c2f135e3ef +8596e993ef18b8d94e9c42a90cb7060affc586b8e9b526820d25124285de5590134e2e86592e9dc4dd45ccf5d578fa60 +b71bb0ad138141ed506b2253e84110d2db97cc2d24a3fd0d096b0022d9f38f87aa74e2f505074632d64e90bcc491aa30 +84841eafd357309de47b92ca5ec163dec094a2e5271bc65898c31932e0160bee165e4decb23af339cfe09c83e1cc5441 +8a2915ee39a6fd4a240b98533d7690ef1773ce578ed1fb05ed414ebe36f7ef289fa46f41768df57190438c356331e329 +90bb337165386f1990cbd8ed2e8321ef21bc18125b015b4da0c37e5fcc446b26005379ee4fad8ce9348ceb4ab49e82e2 +b707b50ea2ab05c6d183671587f25fe29eef23fe569d731459a1ac111a0b83a2cd65b88242876b34aeead3b05a15d745 +ae1f159f79b7996315c4f9acce7e21a6ed59d4ef76331196fc86911fda3035edd5c11d568b105175a36c948d0263b382 +922bc525bace05e5dff6b5cabde5469ddd2c1c601f7131abc04ecefdd35095e6ac015b1aec3c3b25c5dee8d139baf60d +a7b060405b2740f82db64683187b1bb89e5f40c8438663c7cbc8ef2513929fe5f92625667a7f2f599a72a96b1fc8f08a +b9dfe94a08651db5efefbb813269bce80d814e3089b80c0654491e438d820bf521f8a4a4477909344ba88f7683eebb43 +841817a9729465743576950b6e8eea32ebf39cca99ace86c4792f9f35926e2d6830c52854a3b2eaeb61694e6845008bd +934128034bde8fc7b93b952aa56e0ed28b36cfa04cfa1f0d5b38266dd40beedff5e0bab86e4717b0fb56c56be2eae26b +aee9d64caf28596308782cd8f3cf819506daf3378f86157ff775e618596411adf94efd0e9542787ca942066f02cbd332 +85871184db314411a49575fee088c52ed5dba4e916ee001ec24d90898a0154d9790a06aa8a707ca7a8b986c0293b8d89 +8d3d87edcc0187a099c97b581a598d357a41ac152303bb27c849eb78e72e15cb97cf9a0468fc36f245c3e152c76bb7dd +900475d165dec18b99eb7b5f9e9ad1d2d4f632e55fdcc4c5ecd7775fed462990e6aaafe9c669f40508f9b15f00bda31f +a25b5954edd57e7811a0d18532043d975c7b44b80f65cd630935d7b16ada05f30fe2b7be7ae8a2f54c25957faf3f1950 +a089019afa3a7a15f7e7874e73b6773c0a824e6d3379b4c928e173321fb165ad979a6be004d394c28d19d410b2655d3e +b28f46797dee0c538bd3de815df641a0ef718ad3e52b2764aec380d6905b38b50ad6f60d0f68e096ca39960ba7734355 +b0ac155d3d05851b04104e6b459f1a68e9e155437c92421a7c0e4dd511ef89cf71dfa3cc920769492ee283a65ebf029e +813c69a810745580d43d5b5480f0ba81000fbef0071e6b655c7346bef5ed774e9214a7816d40eb1774a5bd033767a046 +b176345ca75c64f10ec33daa0dcf1f282b66a862fcd3d8d66c913f9a02db4c9d283dadc02eff13aaab94bc932a42234e +92560f67e5b995db4a489bb86ee78b4aee0800143b3535ad557a53e9e08716bd0202d9f5714722c2a5e8310046e3f5b3 +8adb427bad9cc15fc6c457a96a6750dda8c46d859c5f69bf0e7ab8fc0964430b33967fd47cf0675b6ba1757f91255e6e +b120f723b80389a025b2daa891b140b3d7b8d520ae2a6a313f6e3d365a217af73292dcb249dca1f414ec05e865e3cdc7 +a61a5d261a8dfe5996c42ea0a5ae703a2adcfda80e86837074d868eee16f87d38da19596c48b55dbd7a7cbec1a9b4996 +99dc921eacc6bb867c5825ad4c83bc4af9dd78a18b3d0e1a60ad493e3805b8fb9b7922b577da1adb3d805edfc128d51d +85455fa165a07282aaab4a5bfb88027f47b9532e4af8195c048515f88b0db7e80f42e7a385fd4944faaa7f2a6544ad17 +96dff2d1c8a879d443fe576d46bcceaf5f4551d2e8aad9c1a30883637c91090de99ad5eec228eb5febf93911502d3cbb +a87eb7f439377fb26c6bfe779701f4aea78dd7980b452a386afec62905e75217a1996c5234853432a62ef8bab21c31c3 +b598278293823e9ccb638232a799211173b906444376337fdf044d0227d28fcc4c5867e6ecb3200e59ca0b139e71cac9 +aa6fe147edc95027654d68140f428ec53cede3552c5f49c09d18bc6f6ae8c739a63042eb7291d14d717a4e1f0778abcb +ae8ee18913d328b2fba71efe65526d3ee9c81beda53cf776baec4019ea30212010758cbb5dc85ed6620ce04b189f01f2 +ae9fb686777e88dffdd42805fe4114aa0da1b350d92a27ff3f8a817fb25af1fcfc9a06155affe0273bf13caad16a5351 +95d372ba3a2ee38371538f34aae91b4844488e273f70c02f1992370f89fc2343eff95692d52ce9f21206abbee4959958 +b15260376f0a34ca2827ff53acd7eaaef94c9acc2f244b36500423069cb1cdaa57ac8dd74adb5b53d0fd4265fcbb28ea +b0ffce6a8059537ef6affdbbc300547ef86e00109289239b0c6930456c562b4ed97f2e523963af17736dd71b46c44ac7 +b5499a1277d34f9892f7579731ff53f423f2ffffa9ea43a6e929df8c525e301396249a2324818a6a03daa0e71fcd47b3 +98dbfb8e97a377a25605a7665d4d53e66146204d8953afda661ae506858c5cd77ff7f21f5f10232e06dbc37378638948 +84177e27e6da0e900c51f17077f5991e0e61bff00ca62c1623e627c5aea1b743f86eef6d55b13219a1947515150bade6 +b50407bb5c61b057ab8935df94fd43ca04870015705b4f30ceac85c1035db0eb8293babc3d40e513b6fb6792ecbc27a9 +988699a16917514e37f41ab5c24f4835ed8a2ca85d99972646fcc47c7e2a83c2816011144a8968a119657c4cda78d517 +920c43fdcb738239ad542cb6504ab34498bce892311c781971d7db4dec70e288676de4d8697024b108cfa8757fa74035 +aaa106329aac882e8d46b523f126a86d3cee2d888035ce65c0be4eaae3e92fd862f6ac2da458a835539cccafaba9e626 +96e4c1562d14b7556f3d3e8a1b34ea4addc5a8170e1df541dc344728bcb74cd1630eb7ba4c70e9c68fd23c5c5d5a729b +a616ac5016d4e68e03074273cd3df9693ee0ce3458e8758b117a5c1bc6306dd2c7fad96b1bb37219c57ac62c78ad7a3e +8db7d9b20abfb1445babd484ae9e38ff9153ac8492230d7591e14e3fca7388a5ca6ef7d92ed445c8943cf5263e4a6ad7 +88464134221aa7134878eb10928f31c8bd752ab68c27c9061c1de3f145c85731a4b76acdc7e939b399b6e497f9e6c136 +a5f7c794f70b7c191c835dded21d442b6514bab5e4d19b56f630b6a2f1a84a1d69102d7a0dcca256aab5882d3f30f3ca +b96b6f98b6817b5fa6b1b1044e2411bdf08bf3ffaa9f38915d59e1d2b9bed8b3d645eee322ee611102ce308be19dbc15 +92c26ade2e57257f498ac4ff0672d60b7ea26dad3eb39ed9a265162ccd205c36b882dba3689758c675f29e20836b62d9 +8379a0299e75774930577071d258e89e471951642b98e5e664c148af584d80df4caa4bd370174dae258848c306f44be5 +a0e53beda02bd82bf3d24bd1b65b656238128e734b6c7a65e3e45d3658d934f909c86ca4c3f2d19e0ac3c7aae58b342e +8ca5ceaeaf139188afd48f9bf034d8baf77bbf9669791c7e56ebf783394d7fcdf2a25fa4bdfcddfde649aa0dc67ccccd +a8060e6448844e9db4e9fb4da1c04bcf88fda4542def5d223f62c161490cf1408a85b7c484341929c0f9ce2a1d63e84b +af6e1a5ecf50b754bb9eb2723096c9e9a8e82c29e9dcaa8856ab70074430534c5395534e1c0ed9ce98f4b84d4082fa67 +81c8dbbef98f1b561e531683d5ae0f9b27b7f45dc6b2f6d61119ca0d559bf4ceb676d320afc5aba1811eeef7547a59d8 +85b46cd64d605c7090a2faf1a2aadf22403b3692b3de1d83e38b2de0108d90ac56be35b0dca92c7a41c4b179a3567268 +8dd3cc3062ddbe17fd962c2452c2968c73739608f007ad81fa1788931c0e0dda65032f344a12249d743852eb1a6d52a9 +8630f1707aea9c90937b915f1f3d9d7ba6bda6d7fdef7a40877a40c1ee52471fd888f84c2b2c30b125451b2834f90d3b +b4a747e0bd4e1e0357861184dacec6714b2b7e4ee52fa227724369334cf54861d2f61724a4666dae249aa967d8e3972f +a72de682e6f9490b808d58f34a0d67f25db393c6941f9342a375de9ca560e4c5825c83797d7df6ed812b71a25e582fff +8d5ea7d5c01f1f41fffe282a334262cc4c31b5dcf31f42cc31d6c8e37c9bd2f1620a45519dab71e108fe21211c275b6c +8ccdc7e3642c2894acbf9367f3e99c85963cea46dc5473d175339a2391be57dd8815feacadec766e13645971213b9eb8 +858e9b5fc8c13b651ff8eb92324bdda281db4cf39f7e7bd0472908b3e50b761fa06687f3d46f4047643029dc3e0ceeaa +ae20d36c70cd754128c07cbc18dcb8d58b17d7e83416e84964b71ccff9701f63d93b2b44ec3fddc13bbe42ebdd66221e +860dbf7013da7709e24b491de198cb2fa2ffd49a392a7714ad2ab69a656ca23f6eafa90d6fdc2aa04a70f2c056af2703 +8f809e5119429840cb464ed0a1428762ba5e177a16c92581679d7a63f59e510fdc651c6cc84d11e3f663834fcafeafdd +8d8a8dce82c3c8ea7d1cb771865c618d1e3da2348e5d216c4cbbd0ac541107e19b8f8c826220ca631d6f0a329215a8d6 +86e3115c895ae965b819e9161511540445e887815502562930cedc040b162ecb1e8bdc1b6705f74d52bf3e927bc6b057 +b9833b81a14115865ca48c9c6a3855f985228e04cbc285f59bf163dca5e966d69579ea4dba530b1e53f20bd4dccdc919 +a71f5801838a6dbb162aa6f0be7beea56fadac1a4bcd8113a0a74ab14fc470a03775908c76822d64eb52a79b35530c05 +a77ab73ae94b6d3378884f57eee400eff4a2969aa26e76281f577a61257347de704794761ea1465dd22a6cc6304fbc4a +acd1c5df3c487c04cf27f002e81f2348a0119349b3691012526a7b0d3bf911cdd3accbc9883112ed2ba852145e57fe68 +8a28515a48832ac9eaf8a3fb3ad0829c46c944b4cb28acbcdbca1d0d4c3c623a36cda53a29291b8f2e0ea8ee056b1dee +846bafca11a7f45b674237359b2966b7bf5161916a18cf69f3ec42c855792d967d3bf3f3799b72d008766206bb7a1aa3 +b24b341675b1db9a72c3405bbe4a95ccdfd18fa96f876ec946ccb5108f73e8816019998218a036b005ef9a458e75aeb3 +b99c267b4a09193f3448bc8c323e91ef5b97e23aeff227033fe5f00e19bab5583f6e5fcb472ec84f12b13a54d5c0e286 +a088aa478dbe45973b04ecafbcbd7ee85c9a77f594046545cdb83697a0c2b01b22b1af0b97dd75d387bb889e17f17aa7 +a0c6b0cdff2d69964134a014e36c3709d9e63f6463c5cd7b01b6f0be673731b202d577539d89dd57a888326da1df95af +b4e6dc4ef11b2b41794ece70a8968e56705199d183366759568b6fa845d2cae127486e926b5b27ae9118bb21d1682c1d +a007804353f174098f02540a57e96227232444d5ae0a24232c244647148b6c049848cbd2b50d0a25af3ca9164bfff8ee +873fb034cc39c9cee553ece908fbf315f62efbc412b9afdde6a1889326b7f6f813e050b0601ba9921688e958cb75942e +b5676c90f0106c40d8683299e59d564f505ec990230cb076caef3ae33f2021e6aa5c9b27bb8fead05fc076df034c28f5 +b5a67fc4c5539ad1ddf946a063110f824f7f08d2e4d30762c9d437748c96c9147a88efc22260573803ab545c18b108f2 +817ff2b748a949973a91b69b0ec38efbd945aeb26a176d19f0fb76e261c7526c759e6f5516f9ed34de6eb1ac7838c9cb +99b76bda3526a5d841e059010fdb14eb2fa035a7d10463373a062a98c3c1a123e2da0848421dd7546d776438fd05e304 +aa0d363270f90d56bbee7ea577b0c358532bda36d9247af6c57d000044a97ba41e35bb0db438f4c94551c6350e4e0674 +acdae205d05f54b9544be96c9032350511895ccf413dbbc56d1f03053185df22a6d5b7ffcc3fbe96c3e2ce898ccfa73e +b091c220a1de18d384f50dd071dca4648ca4e708162c52a60e2cedc0188e77c54639f75bce9a468a64b2549119c07ded +878676133e5c700b1d4844564fa92a9930badb5293d882aa25ee6721a9f2cfab02088c31d62cf1342ae3edaea99a1ea0 +9756d0793e6aba3b4dff48100bb49a5ec08ec733f966cb438379b91caf52fc2a5930830ec3f49aa15a02c82c1914dc7a +9722f760184d3b2d67cb2cea7fa41b1ff920a63446006bd98c6347c03d224d2d8328fa20ccd057690093d284b9a80360 +b5a68489de4f253715a67f0879437bfe8f4dfc4e655ca344848980e6153b1d728acde028bb66fd626fa72eedd46ff683 +a8cfc900b34835d9fd3add08044636f69614eff9ae929eac616c39bd760fd275ee89bf24b0f275dd77a66e54fd6b94e5 +89967479bebf70b2893cad993bf7236a9efe4042d4408022fdbb47788fabedcec27d3bba99db778fcde41e43887e45af +889235938fcec60275c2cf0f19d73a44d03877d817b60bb26f4cbce09db0afae86d42d6847b21f07b650af9b9381fa82 +b7fc321fa94557d8fbdd9fff55ab5c8788764614c1300d5ef1024290b2dbb9216bce15cb125da541f47b411a2e7e3c2d +b11b0c4dc9477176b3cda6b17858dbd8c35a933ed31364801093f310af082cb5a61700f36851e94835c5d4625bf89e32 +9874e54d2939ee0600f4194f183877c30da26d7515e9e268fea8d24a675dd2945d1565d9016b62b1baab875ac892f4d2 +90df3a77280d6f1fa25a986309bba9d5b89c3cf13656c933069bc78e6c314058716b62eacfa7ab4aff43518b8b815698 +962b08299a287d77f28d3609f39fd31bc0069f7d478de17539e61fcc517045050644b0307c917208b300ce5d32affcca +b30eedca41afb6f083442aaa00f2e4d5dc0fda58e66aaf0f44e93d4af5c4bf8ea22afec888cacbf3fae26d88e8d344cc +847747a22fab3fe3c8cd67f3f1d54440f0b34ce7b513225dc8eb4fa789d7d9f3577631c0890a3d251e782a78418fecfa +8d1ef3cb5836e4039b34ee4e1b4820128eb1e8540e350309e4b8fea80f3ae803d1f25f4b9c115482b324adf7c8178bc7 +8f8a2b0b0f24f09920b58c76f7d99ec2eb2e780b5a66f2f30a9ed267dcaea0ec63b472282076c7bf8548211376c72f6e +831ee6dc8889bbf4d345eaeb2f425959c112d2190764abbbe33bc44e1d9698af87ff5a54d01fac00cfee5878dee7c0f6 +a7eb2479ac80d0ee23f2648fd46c5e819ad3a1f4752b613607ae712961b300e37f98704880ac0a75f700f87d67853c7a +aa4d1b9cec62db549833000d51e83b930db21af1d37c250fdc15d97bc98de7a5af60dbf7268c8ec9c194d5d5ccda3c1d +87396fd7e78c4bcf270369c23bc533b7fb363ca50d67262937dab40c7f15bd8448a8ba42e93cf35fb8b22af76740d5e1 +a958b2a9ffccbca13c0c408f41afcfc14d3c7a4d30ea496ce786927399baaf3514ff70970ef4b2a72740105b8a304509 +a5963a9dd3fe5507e3453b3b8ed4b593a4d2ced75293aee21bfed7280283348d9e08bf8244c1fce459aa2470211d41ea +8b06ddc3359827558b2bb57caf78b3e5a319504f8047735fcc8ec0becf099c0104a60d4d86773e7b841eb5b6b3c0cc03 +9437e7278283f6d4d1a53d976c3c2c85c5fe9b5aec7e29d54a5423e425b4be15400ed314f72e22e7c44ee4bacf0e681c +b56067ee26a485ed532c16ec622bb09135a36c29b0451949aa36fee0b0954d4bf012e30d7e3fc56e9f153616b19349bc +a5c72f7f5d9f5b35e789830a064a59c10175093a0ce17654da7048827d0b9709b443a947346b0e5d96b5ea89b8d7c575 +a8318d01182d4c9af2847a29a6b947feef5795fc12e487a30001cc1ec482b48450c77af4837edfa1aedf69f0642c7e5e +82ea421c091552d3dafa7da161420cb5601b819e861dd2ba1a788c3d1b5e8fa75cc3f2b0db125dde8742eb45b335efa2 +8679fd1c7771ea3b12006d4a972f4f2892e61f108107d4586f58ee7f2533d95d89b9695d369cdace665f19c6bc3bc85e +b5ab3e8adee4c950fce4d33a0e2f85d3d886e60a6e2f4454b57bc68725f0cf246372d863167482cce1ea10a7c67c3af2 +a85696927075ec188979180326c689016a0dc7a2f14ae02ea27c39ef91418cd44177d3fca5752cf6b298fd75fa012e26 +a44f87b7232f102cd092f86c952a88afb635484a984da90a41a57a3d883c9469064bf105b9026024090486b6c6baa939 +866ac91a437db945bbfdc11fcee583f3669fa0a78a7cecf50fbfa6ed1026d63ad6125deba8291452bf0c04f2a50e5981 +b780d5a1e278fd4eef6139982e093ceafea16cb71d930768dea07c9689369ff589d0c7f47d5821d75fe93b28c5f41575 +b025d0046e643506e66642c2c6a5397a8117bbfe086cee4175ff8b7120e4f1e6794e1e3f6ec11390993cca26d207ae43 +a04a22b6e28c959ab265c7f48cde42bb6a00832c6beb2595b5df2879080a9424890960417d7d7ceb013d697d0ebf7267 +81de9c656ac27f54d60d0252e33aff4e9e9e9c3363a50740baf15a2b9061f730a51ae1704e8c4a626153cf66d47f19b1 +a15fab90599df889df11fa60c752948b68fba54005491180dafb66c5775547976d0eef33945e55d4818653e0818c6f92 +b06f9be44ddb103a72fa4ebc242c8ee1975fe9bf9ef7124afeda9967ff3db644dbf31440151b824869406851a90984a2 +99abdfe6806ae5efa2d11577da17bd874d847c5f810460148bc045bcf38c4fd564917eacb6ed61bb9164ed58055cd684 +ac53231077f83f0ae5f25e52b70bb6105d561c0ba178040c11c3df8450c508ed5df34f067fdaacf716f90b4926f36df5 +99e3f509af44fc8d4ebc693d3682db45fd282971659f142c1b9c61592573a008fc00502c6af296c59c2e3e43ed31ec7a +98f2f5819670aff9a344e1c401f9faf5db83f5c0953d3244cfa760762560e1c3a3c7692bb7107ea6eaf5247ac6fd7cc8 +b5b9f90391cec935db8d2b142571650fcbb6f6eb65b89c9329e84b10bfa1c656026674d70280ade4ba87eeaf9333714d +b0696b77ca8a0cdbe86cad12f358880926906fb50e14f55b1afc1e08478ae6376215cbb79bc9035de2808c7cd2b13b85 +a51d746833062a65fd458a48a390631d5d59e98e2230b80d8f852cfc57d77f05eefcfd3c395ade1e86d4a39c2141365c +812d67654319f4ef3c9e4a2d4f027a4cb7768f1ea3f5fdde8d1b79187a4b874ff9a5c70f15b7efa079c2dc69d1b9b1fe +968978b653c6416bf810f6c2ffa3d1abbefbd06f66b6686e9a4fdce3f869e0ab1e43cce14dc83786596761c100ae17e1 +98e1e6ab562ca7743783b802faeb0a24f1341abfb9655f106920aef08964a3c0e8083e1acda7ae28fed7cdd5478decb6 +a91c0b982a0a7085a103600edf99e9d0bee4c4e7db6d9f8f376c215c7d42476218462a3765f2928e12c3dd49d688e4fd +8a43395b3124fab9e2438635bf88952e8e3084dad7ecb3a9927f9af0e0887bce4707084043671fc98ad03621e40a149e +b0b37626143d4a8c6f5693d5f1fe871525b4dd946c4239cde032b91f60a4d7a930d7ba28959737550d71c4a870a3a3be +b01c74acae1715c19df08d5f4a10e0c19d1356264eb17938d97127bf57e09ced05ba30d0fc1a9f32d6cff8b0d5f91c9a +b4c2328eb8a5a673406faed8f0aebb8540d2791646e37ce46e0e382506570ca276eb6f8e166dbbf9e0a84064873473b9 +85cb9f769a185e3538e4a4beda9a008694e1bf8dfeea9dc07c5c40a9ceb1d31fcb13cacfaa52849ba1894b5027cb8c30 +8742f91cddc9a115ddc73982f980f750d82d3760f2d46ee4490d5b17c6c3bb57c7d4c7b8d6311b7b41e59464c009b6a5 +948ef86d17128a061e1bdd3ea7fcc7348e3ec87ec35dc20a58dd757d5d18037fe5e052bb359e27ab4c2320d9a52a6a0b +a70f6a214097c271e0d2d95e30fce72d38c30a2f186271fdff0e38e005aff5baed53739b8c4f9501aa7f529c5cb2da59 +892a7574cf6704ad75b346c95ae6f2668904f1218c35b89b07a0c2dbf3c62173c348f6fd9473926eef56a37c0f635c04 +837e85a41f39b4ded1420aa8fc3be46a7adb99305e0928c6d7643b7c44434b72984cea08eb68f5f803661df0db78c87d +94e495329f2aab3eeb68f347961d1006e69d990095877a4dcc376546233adf29a14bf6b16a0c39aa477e15368e87014c +851860a8fdf76a97048396553262637dade27f1f63f926997e74c7c72b14b10293eae7824e8dedffad1aead57c124f79 +90481017a250972055ab1cf45ff17d2469517f10f18c9d4ef79a9bdc97a49093289bbacfefa8a1e491bbb75388b34ac0 +983db15f7463df28091c691608ca9c51095530fa6b1b7b5b099c612e673d29e16787cc9ae1c64370ba6560582ce623c0 +a477dab41014c778a1b78a7ce5936b7b842124509424e3bfc02cc58878c841c45f9e04ccc58b4f2ff8231488fff0b627 +868ebba1c85d1f2a3bf34c0ab18721ea725378b24f6b6785637ee4019e65d4850e051c8408fe94a995cc918c7b193089 +93cbf4238a37ccd4c8654f01a96af809a7d5b81b9e1eab04be2f861d9d2470996fb67367e5bf9dcd602dc11a3e4cf185 +83113f4e696030cca9fdc2efc96ba179cf26887c677f76cde13820940ad6891cb106bb5b436d6b0f8867f2fd03933f7d +90c709f4e3359a6d215d03f45ad5cf8067aedd4aab03512dd62229696485a41dcd64e2acce327fda390e0352152fce13 +9945cfced107a36f3cf028ba04c653360afc5013858b9a12fac48802efcbc198c9baf3a7f9b23dfdd5036e88bc7274c8 +832ae60192b47fc735a8ddeaf68314b16256c90ab68099f58e43073e249c6939895c544a02fa34e40805bc6b5db33461 +8b12c335818b643c1d22cbc2869606cf64e7ae54a7713617fc4dd3b2f052ebd6b920ca59ba2e9c7aa8cf71bb4f40f9e8 +a2033eb7a373931c65d66989644aa0892ac3778b9a811b2f413d8bf534e282c339717979f9aa742162abb3468c195f87 +aba2b4c37dea36bed6d39323e5f628ab607699c66767f9bf24ef5df1bfcad00c2664123c0d8d5bd782f1e14a06f4c769 +b71963777535b4d407286d08f6f55da8f50418486392a0018ee10f9ae007a377b8b8336f33386b0eb01c45695c3ed2da +88dc87826941340913b564a4f9b74985a311371c8e7b47881235d81c081f1682bef313c2f86561a038757fb7d6a1a8dc +869e13e3fcf91396750150f9dc9307460494c1d365f57893fd06fb8acf87ac7dddc24e4320d9cad0414119013ea739b8 +92194e292303d32b91ae9cecb8d6367c8799c2d928b2e2846dab1b901371a4e522fc4089aad8f4ee676f0614ff8b19d7 +aa589a3e512cb4f8589bc61e826a06d9f9cb9fdfd57cf5c8a5a63841435b0548e30a424ca3d9ef52bf82cc83c6cb1134 +81802e0194bc351b9a5e7a0a47911d3a0a331b280cf1936c6cf86b839d3a4ab64e800a3fe80ea6c72c3751356005a38b +88e5e9e3c802314ddd21cb86f2014948b7618502a70321c1caf72401654e361aac6990a674239afa1f46698545614c93 +abac1e0f85d5c3ff6d54ed94930c81716d0ac92be49e3d393bed858833f4796c2b80bf7c943e7110de7b2d148463bfbf +b7eb416004febd574aef281745464f93ef835fd65b77d460b6ad5d5a85a24b536b4dec800cfe80ae98489e54447e8bb6 +b3fd8ed1c30e7c15b0bc0baf0d9d1ecad266bafb281cd4e37c55edc76c202fb1e4ea315a91a2848f40f481793ae35058 +86ef674ddf4b7d303c68bbfb53db00b925ccbf11d7d775ca09e458f4ecd868ca828103e8e7cd9d99672a193e81b83923 +95ef414e9f7e93f0aaaeb63cd84eb37fc059eb8b6eced2f01b24835b043b1afb3458069c45218da790c44de7246860c9 +93ec8f84c20b7752bfc84bb88c11d5f76456136377272b9ac95d46c34fce6dcfc54c0e4f45186dd8df6e2f924f7726ab +95df5f3f677c03a238a76582d7cb22ed998b9f89aecf701475467616335c18e435283764fb733fb7099810fec35932ae +8cda640695c6bc1497d19b9edc5ff4ea94c1c135d86f573d744358758f6066c1458901f9367190dcd24432ae41684cf0 +b19aedf5569435ff62019d71baa5e0a970c6d95fe4758081604f16b8e6120e6b557209cdea0ccd2efec6ff9e902d6ce6 +b3041f21f07d52e6bd723068df610aa894dfdde88094897593e50c5694c23025e412ef87a9d16cadd1adbb1c6e89ced4 +a7f8d6ab0a7beb4f8d1cfef6960ebdaa364239eca949b535607dee5caeff8e5dfc2a9cfb880cc4466780c696cff2c3a6 +99a565b4796e2b990bfcb234772d93c5ffdbe10453b5aa94662272009a606ba6ea30cc0c3c26aa22982c1e90738418a5 +90c54b55ff19157c1e679d8d4f7f0687a70a27d88f123179a973c62565adfcc9347cfe31f54539038cf2f34556c86870 +8612f34bcd018d742202d77d7ce26cf9bc4e0d78e50ddf75250b9944583b2c6648f992b635ea13fdaae119764e7c28d5 +a04fb38e5529bf9c76ec2b5e3a1ef3c6f9effb6246c7f67301cfed707356ba1bf774f2867c77a5805933f0c8ad0ec644 +b4800e7b503da0164885d253135c3b989690794d145182572181995e6fa1989f3d0324993e871bbd5f48fadd869d8a18 +9981cd4f28ae7b7dadf454fb3aec29746dc2e0ca3bd371b2a57cd2135a7d93559e02132528ccd2d305b639d7ac51613d +a3ceec012dd1fbad3ef9f9f1d6fe7618e13d4d59e3f50540d2a57010d651092979c75442ec8b38a1ab678505e30b710d +8b97b8654d067fb4319a6e4ee439fb8de0f22fd9db5569ba0935a02235cb4edd40a4740836c303ec2394c59a0b96308b +b3d1bf4410fec669a269622c3ce63282c9ac864620d7b46c9dfcec52d8e79b90c4c90a69c32763136a7f2d148493524e +93174eba1e03f879e44921084aa0ee3562e48c2be49085de96ed7621c768ff52324d14c8cc81f17d7ed50c38ffb2c964 +aa2194cd0fb7aec3dac9a1bd8ea08be785926ed6812538be6d3c54218ea4b563646af1f5c5f95cb914f37edfae55137d +93f2c0dd59364f6061d3da189e04d6c64389a3563b062e8f969a982cd68cc55b4f38b21546c8a67c8df466ff4f61f9c5 +aa7dd497cc949c10209c7010ba4ce8a1efd3cd806a849971e3e01716ea06a62e9d5e122ad1d2b8e5a535fae0a01a7761 +ad402424b2a32bca775a66aa087580d7a81f0867f293f1c35580b9e87ccc5a2bab00c29a50fd0d7bd711085ae2248965 +96237843d8e29ac77fc6ebf4acc12946ad11697de8e5f152fe5776f2475b790226a7d156ac48968dd68b89512dc55943 +a45c25cdbb9fc327cc49a1666988af9ab4c5f79cea751437d576793a01c3eeea4c962c05c0947852fe0e4c63e1c84771 +93dcf834a614a6f5484cc4ba059e733ab5dcc54253229df65ff5ad57b447353ebbc930736a4c96322e264e65736948dc +b9a94f82a82c0c5a26f2c1d5381afec3645e8ee04c947dc3b7ad59a73018db1e9965ab3642f2bbf60f32c430b074fb22 +94eab29b3524ccbe0c4b928e5fa5dd8f684074b332fcf301c634d11083653ffee4f7e92ddbcb87ed038024954ad1747b +b8dca5f679931d6abef0674bad0639aefad64c2b80572d646aaab17adf5ca1ab2ebeecd5a526cadc230bec92ed933fc2 +944d394958e539251b475c4304f103a09f62448b7d8a8eaef2f58e7de4f6e2e657d58d5b38e8513474115f323f6ec601 +8a5ae1f13d433962d05df79d049b28e63fe72688fc3e6660aa28e0876a860c3dbc5fc889d79f5c4dec4b3a34cdf89277 +afa5278724998eced338bb5932ecf1043d2be5dd93f4d231d05d2ea05b4455f2ffdc0eadcb335dcace96dd8b2b4926fb +b91153a2f4647ae82fc4ee7396d2ca23270ec7f8884ce9eead7e9376270678edd42dd3d4d6c003dfc2dde9fd88cc6e7c +adc932f1c679bf7889cb1ff4a2d2897d7973483fa283979a0ea3640c80ed106ea0934c1961dd42d74b22504be49851f2 +a82e90761fae684d1415cee0649bb031bcb325ae0b28f128ab8e3650bccedd302a70de1a341ca8decfdda76f3349cad0 +8ae353188b4b98835f4ef0333cccb9e29e1ac3ec11d554bc96f5880c101cb3c84b8eefe72f2287b0812735339fe66cfa +b8b41135bb1a1ffb64afbd83e2189e755f2c350e1273cf47c38ae9b8c4800d831436a69458b8ef9fa8b95a148d8ec9fd +96f75a04d8752fa93dc1eaf85ad333cff4eeec902a345576139e16de3a88eeb71b6726224349bb9844065cc454d959e9 +ab82b05e3923ad4c26f5727c60dc0d23063c03f5a4fd8077da66aa87042cad1bd99586d4ab35aa5e4ce6f4da6fecf3c1 +a50c83db91c26ef7bf1720d8815b41bd056b49fd99710943679a162ccf46097a7a24585750ece886e38eb4fdb866fa37 +a719f667914a84f62350dcc6f4f30b9ab428eac6837b70318c3ac491c1e69d48af5e1656c021818f377d911fe947c113 +a148807aafddfa0a5624c7cb9e42468219e4bdb9994ec36bc19b6e6d7c4a54d3a0763d13ca80624af48bbd96d73afca5 +aa012f205daf22a03e9fb13a63783dda7666f788a237232598d02a4d4becec7a699ab493f78d722ce68519262924c708 +97fc15fab5952c5a2d698fd6f7ad48aff1c8aa589f7d3b14285fea5e858c471cf72f09a892e814104fa2b27eb9771e73 +8da8840236812667c4c51c8fc8ab96d20dae8e2025290b9cde0147570a03384370b0fcbe20339c6aff09cca5d63e726f +b477d85359a8e423fed73409f61417a806cb89c9a401967622aba32bf85b569e82bca1b3394c79e180114a0d60b97316 +b3d6ee2ed1e4c5cf8ba2c3a4f329832e41c7fdcbcda8a3fcbe8f60967fdb1717665610b7c1ac65582534d269d762aa09 +a0b3b30b1b830b8331ee19f96b4a4321a6b93a3395b95d3a895682c65ec6ea64774b878b93514eaf353f2e4be28617b8 +a2b88e9617f4d30ef4e686d1932ad43cd555fadcb5102e51bea19e6fca649284ccf4debb37b5cb2090ef386fa5bf5327 +8a4446f7e8463ea977a68d6217a9046ad4356d6fc1c18d46c5d2ab681ea977b8faff136d65abea6bbf8936369cb33117 +91e7464bc56e03f436228104939ddd50caace5a38f68817bb2991e193b57adf6835152bbf3dbcdebf0382ac9823f60c9 +961a441e6cdf8106c4f45e5b47190d35644faec701c9cfc41ced40cfdd1fa83752fd56c1ac49131a47f1970a8f825904 +94b7b165cc71c2ae82976b8f03c035fb70e90028992b853aa902c0467b384c7bcf01d56166bec5def4453e4d0c907e52 +a5d32cffabbf547f900026b34ef46f08075b7a244565f615370d2f04edf50b094c95088a4a139ce07caf55bcd99afa07 +b4e06e73660745f75ab2f34d9f6d2675b58f80f911ab6dd4c5a6ce1095f9a2b50d86f6ff9a05394190bdf96af0827920 +ad3fd8f83c0103b29d41319209dffca201d2b98094362da08da3fd6ff0ba96796b49d6bed525c9adb96c2954858e7f48 +b0c27430695f0fd20ae31e1ec621da090094f2203e17411db9384695ffcf5c7c6badf461ba49ba70164aacebd6f278ee +b9bc6e972fc3b532fd2b1eeafc4bceb77604885f32132af6a9a842fa2440df452f49ec0cd9d86da1180e8deb0723b260 +9729e22d6104b0174c136a854920f542b384d375040adcebe36acc253bdb55845eb43e34dc5a7cc27d22c417973c24d0 +a8b420b36d48786c9231d454468a6e855dd7f71dcfd095efc9855ee70dbece0f06ad277f7829c5813fc30524c3e40308 +8757dff5499668c93fc5d9cea0a8db61817b8ed407200d623030b5849a913d12f8371b667cfde8d8082026eda7407e8c +b859ad747ca5af661fbd03a1a282df6e84c224ecea645bc2d4ba5e35fa06cbf047387319fca0cbc76b712398c0798968 +8e3173c27875f1460297af0fa736c945dc842ec3e476a973d3d5f790bf183ad3ffe96ac13868c5101d8e299890791864 +a9d725e2b92c878be42b5eecc2c3081c63c7231ccc7e2dee17ca6a4caaeae22788fab1f1465fcbd7fc236613fc2bae4c +86f6c4f04a354cb2470ef91914816fd740f8d5795ce7ff981f55a2634695fde5951bbae7a4bbc4c63747040f8644170a +851773cb26f320f0c3f252d95ea7e058ffcc795dd0dc35e459aa1b6b448238909230d809e82022e64b7fca5d40b8324c +8962641e0306220d9892fe2d452caa286301a3c465185757be7bce2d9b2c9beb3040280099606cc86773e43941fd3439 +8beb6e08c440b0de5fb85251d39d9e72db4e556a2dfe3dae59efd8b359d08492064cebd8d8993254b43bde8bd67d969a +a7e047894466ffe3dec4ab8d5462f2b1d8ac0df006b1d2dd26caf499ea857d93a811cf42233f9e948c9cb903beec004c +92eedd95557a91691a5e2835170390ce2401e223da43b78615a804c49566f9d31cbb7f10c8a8390c4bdcf691544fdba9 +a5e5b5d8fa65824e958bbae98d146b4b332f97ed50e0bc2c58851dc2c174ab71bcbb1ae015cd2955c26b368487dd862f +853a494eafb308175629d581ed04bed71bbc3af9ca4c0dc483d03d27c993a2bbd88cea47c2085a6928d166fe6938fb77 +83f06b88d29afbfbe8f61811690322ac4fdd6abb9a23612162e7a2dd6bcbb5f14cee298ebebc1a382484f7346dc51e60 +8c9cf05735ea5a0e563490bdc7ed29a4426643711c651e35c8551ca6f855c8458ae8f0933a022d0bb9a952edfed411f6 +b906b48d807748a26cc2a8848455a76ce502261afe31f61777b71917bdf7de2fece419db636439478c7582058f626c29 +97efe1fa7c9b25d8bea79d74b6cdcf88f63f1e865f54b58512a2e60428630b0b40b8b6af1b5f71df47520507548c3cad +8ef5ca6e753818906bb3fc71405928d8e4108854ef0ef01c1009071b353bc2852e771fcb619d5fea45590e8f61003d7f +8e4d901661e2913740d70ba4d0745df5e8c9c0a260149d9362beadc7e669630ba909ff0e8a6cc85c54d6b7435d0d351e +b7c6ba3bebbd9592967954e3a480ee8df1d9f5965f04e7d78a5415b645128deae7ddaf6ed507c8877bfca91ce078e529 +840bedb0ad4e25acf6cd25dee4f98fea495b2312dc5cb7a8388c5ab00b2acb9cd25da08e9fbead145a3107972b1ccd5d +a8d4578dbafdb27f3911af59962d89e75dea74db55346720357790da677312c203107d9c7911535aa563446fde7d4c47 +86d3b77f231bfa09251b7fd2ce09c27ac520ec35d783e912476f9a4863f83d269eb175790d6e735da9260293d707f8ee +b34909f1cc033232652da0c34051a769dc76adb1aee00674a59dc1b860f6e610974c3b4bb69a69ccc73e01f042431242 +90799854d0cf34e1d91ff8e101bc7c5007423d34d2f3bd9adea2ecac57e83f3a65a506bb93d4caea49b29f6d18149957 +8ef94cde29b037e19a1ce7bf4418ad3c95cd9457412796ea385750c19a6690f13a3bb5bb6a9ee81e7a40face1e0a8bca +97053d21ae8d75972fb37f6fe516c38c32ab162fb56b9f510f954858f4e3ef6ac8c3a9557ed3f41b7b6aef05fe97f931 +90a9f9f0f40991f3bddc58b92d40382147db22cce50d092d4a05aad251b46b94e71ec9f7107a180243288059fcc5ce29 +a14265b1344ac2921b0f890d13bcfc432e4f648ce403e261fce4d3bb32ffee9e2794c02830346054f998e82784c77040 +91928402ae121e56a3e64cd6f390127e6e92fbfb1967ec6efa4f52f3e8058f1f41a0f4fe96b5bcc11641c1139e790b2b +921c8c92b6d40da6c5a7b592acc74fc0f577d93767b9aa4a1cd302a72dbf503a1ea5b2c29fa0d0359bff3b8f252246d1 +93ae0ebe0e8e133fd80cf67a499047e30ec4c4660ccec9d49098717ef57721a030f423e00c5e74af4ff4acf014a10497 +82c865e21905aebfe0496af1c6ac7e342b5f446a9edb4f7da0f2fb0340abfd8e6fc545da874459d9aabe6bce0dd9bfcb +aee3961d8d2687c0f134b9c28b920bdc4021d925fbe14323c84224a9fe161248789249fb85436a5891d0bbff42c2a3e9 +91aee420b98b6949482b8ff4be996b97245b4e8f583a6e085226539074f42aa89818395efd1a6699735a569bfe19d623 +a48eec22c192e495b01722d0016a54acc45ff837e2a95c4294ce81d5a4e43e0053a6f0ead8a4fb3ddd35faf6607275b0 +a26e15937c11faa30ffa64817f035e294cab0e839f73d29de8a244ad039be4e221eb47ea08d9a4658b0152fc3caf6110 +b84450f948aa7c8682fccb9cae84d8e3558adf2d0ca5fb81eb200415291158720f8f3470542ab5b88c6873ad08e7fa9a +a8e8ec27d0608d020169a85d6ecdb40eb402f006a3b97afe32cc01987721b3a68a92ec693aeb4d357e189e05fadf699e +ac87cd535ef5699312cc26f86adb71baa0be42e858bd5a2d94ac05737dac63430691e29b9a30d2559ad581a172519b2c +a4481e67b524f8cddf2046625efd3d75efee6aab87ddd2c1b22835647e918157e5e924ac760db2195c86d326f3db1615 +891f29ded231486ee826840c8895cb325f7e84a5a6d2eac246cb3573612cde274720233b1978318a57ed337a046330a6 +906b6e750e6178289012769807d2598925d7e51c260c14497d8af978b1695990e3352e6e809a752f376597a68083870c +b7a056898ee1e46f7f29702fb39232f678ec173eccd170303b3b0a30c8d8cf1a5321384e3513e3b03bb742c238deaa54 +8f2f035fd96c3a336354c89ec9b8222803bf42e95fb2412c28d4e75eec99c1d4d402501ccae17357b757db8bdb0bfeab +81228625ffcedf977fba9cfa13f6edead3985e2651d5974789c394a69401cd7face9e20ae6694be4c0d4bab5e99c61a8 +885a83eae25e61439ad809567a2ab148583402e01cfdd77b0e37ab4038935425c64b4e0886949bf06438c35e80aa13f4 +8926387f48752f6933899c48e038cf14e7941ec6a58bcc0a436614b396296a17aa53e6873803dd3041dae470bd493fcb +95d0d3fa061f4d856eca78a569aa132db14cede7646f97e2aceb6da0c8ea53195d3b7a566fe5ec8c41b95ecdd89a1c6b +a3c817f4062ed6aa94064ea695d76c1825f3bf77b310fe1db28b8bedc9aaacbf1019dbd128adfd53042fb943d863a2b7 +af1208417aa584052da309169854149ede38a3ad63c76cad6e43afb6f1a7b854edf8310a0b00088c039259cedf0f859b +8b713fc3196bad35dbf364089049ada5477e540d78d76a5f0a9df98f7ba4a0e65dd0644509c149f9b07887298bf74b04 +89c09c43c5b733c4a417cd9ebc0795cc3348b72778d31828a9171427779a82ef023c1a4fcfcdc919ae25056f9c826fde +a0759c850ed320c8c874435e90ace6edfb8e7b3f2a09d942b8ad8339c508044ee2ee26c70f1b626ec49a77971433b6a8 +b85cbc58d4fd52286e714ac4eaaa0b2743a1de06fa03ddf8f6668ec6f1d204acccce93b10620272afb8c0b49bc4b0a43 +814e0a87384e159892a8d23036985fa3f489c53bce192e107bd2d64f57b1bf5ea0acc1ef46c7a42bbc5cd0924d92b4a0 +aa6821da96ad89d7881b878e141076522f104ea9a5bbdd1fce9f641898f7d6232c518a87a0f666871d7e3165c26081e4 +a9041d714bfc067b5427252186fa3557bad598fc0067dc8521aa9bc1ae298f6e96113db5ac9f6bade9a85d5a950c9755 +b8669340f3064692625e1bf682d34fbe69a61689e3aa6d6a3e822c781d406b0300dba9c3f7b8152a8c2513f1310d4291 +a78c53316ce768a1dc5968030bf4fc885f4029b1ddb6a5d84a61c85af686c73727f62823891edfcb6ccf4545de366cff +ad1d3aa29ea28292ddd438c865e2b5d93f32cdf009e6d5f5dc726de996583925727e6348bf1c28c22dec0bd86aaf867f +ae1447a2062e9e28af5f38aecc60fe150cd10c2edeaf2110034aa144f6235ed7fbce432a58805d4fe1f6b12652d6e1cd +a32146634332d3303934550705353c6d4fae5fa5985105bba35041e74cd71e2aad67b45da171221f6ed80f36bf6dffa3 +a232e8286184196ea77427b53d8b52c44d758ecc42d22556529db3136379b4989dec61cff610cc6cf6700a450a847a94 +8a72c7255125a736da52dff5f77e44c3de29f88fc05f5ff9227c69df296930caaa11446595e6bea3bd946baac5ef957c +9688a981a9457678067f629f8efa6b522e7318b529f88d37ef56c5bf8f1c34fb9bb3a918ab73caab82bf5abb0c03518b +88286f3eabd71115fc3b17a6bf6981340a81cf7e5f96b0a1a016d4ec8c18fb486d46c70919123d0c189a6f5d6ff29a1e +b535e701b40d793c02ac0d625ca91620d3f4a512aa9741f71389e58381008b2f93d597586d06213c4e103d67d0ddf6c5 +80d0c9dd941e8d8d3700cc51a434a5aaa3308cf8ebfd14128ccfd258f826b27cc3cf5c3ad7851340393abb1eeab3a157 +87049225fa2380d93f18d3d90cb0697a56b373b66d7f24ab209966aed8b55a2790194d5885399db29dd5b1f189eda64f +a52df158ce8670e0290551e8878d63dd33b4759d6f50e448e63fc7fe6ea99dddb6f180be5fc0fc3918ce54c05f80b356 +8b2a728b39c465fb0f60b0c486e5dc8d5845ccec03d3dd93b393cedeeb3fe1b44518359f1ed55fc770a8f74bfeb9923d +91fc05419dba718fa4a910dcf256ebea356bbea00522d8d5ec3e7ba4271a26035aac15e8d9f707969df1d655d92dac55 +97c8779ae80c24c1f82d5a714762d6ee81069224e39515e41d8a71c9310dc5d1c55cc92bc5c6a4bd391ae4c321d1d4d2 +b5e5aedba378c4484e3a7a4ed41b75b0844f674261c2501497de6f91f7274b5a4c1be0e055f2e0c0cab843d891169fbf +8a26212f27211b295beea500abc8e9d430a8500d3a350cc62f895d39e8b4668aa638c17633804ba353010000165637ae +864a95118e5d394e00e99efebd505df0125525c9ebe165764c453b80ad3edc730feebde3d93850745dfd88a27bb8f20b +a092e0b78290e826cc1ae56afffdd08f7c10954f549a3ea6666f3db1b6cdaeb7df53db28dd2a92446342930fe60a27ce +a1720224c0626a081b6c637b2a6d37da85d9a82241e5efef3bc15699b02a69f6304e43d8ff3144d60c16e00225d6b39e +a7b3d098cebea9cf32e19c5195608182b6afe9d4af6b9df532c047eb7a941a971279b2ae6a4b80f2f9d9313a6d788ce3 +a3d2451e6788944802c5077a778d7b7299dbb9d1612676bb6baae78f39976e0fd879493cc4a4d737b8174b472a456850 +930121b73da844571b1411d56760e80923a4ee09917b3e9cff4d3dcb0bc27026ff2c4e2c44e7aca7d3f8383f129c7f9b +b4b0119d163ee00a2b74bdf188a5cdcf054daaa48c483b94bbb4d09ff615afb4a91347db6363bc7535e2af9054ec2214 +a5846decee706780201095a8cdd48fbf3d3a2eac8d089a818e5e22c29457494bbfb4399323b067f3d2be2197c33dbd98 +96ba600df10ee7af5a9df29c0ca31dbed275d647faf9c66c7342de927ceb25b5bdd852dd7aae0228b27897f90fdd5d62 +b6ac51ddc98edd9fb9f54ef84bf372a041d58dfdf0dfdbdc4b08ddc1a7ba93ddbb1413dda3c1545a3fd7386c6b85975c +b35f3efd91a0723e0d486188ea9675a3462106470455118392d7610470b623caca2fa33829721c05fbeb0fabcf570bfc +87f49e85df5f8055714a8ce7adf37f6a278e64e76ed74c60abe3edfc3611ef5b0426d4c6da45e5f3b74d30be1dc6f539 +8ff8bb06902a71b1e9177a77367318b2e3e0a88f5d74d6907ca9943f4f9f1ceb5f297132c2a025259d17a67e880d1bad +85eb6de6c70fe5c53ab0ab27aa0fec439f136c979c557d317337cafa6e6c5cb3169679c9169567dec5f6c72b3c057d83 +ac18715ed1080771d760cb7066c6328faf65d9b30517903f8a5cad8d66d5c6381156b521107d7cd75ebb8c30e250706c +b95b9eae4703727e4ac9ddf2ae675906487bb78905a5f9cba74a4cbfd118d96b7afb6ef3ed5edf14fd963b830d71338c +a3b47b52fda16b62b11c8aa4daa56b0b669c4d5c56a3059b7d063284d8a91f6fff9ccccab23d6ceb9650483b2d353039 +96a95b3f327df94c85e92f2e406f1649ac621533c256b062738f3c3ee137059a735a3e6072247acf57b1b0d8c219bd7f +b19b33cc04570be94eae8e943d5bb17bb0c96e9de4ca84f9f41b37320a1a03d397d53747dc13275fef1b356de557214f +a1faa3dcb931dd91507f3f12a17c43f6627fa2bc5c71fbdd27548e091eaaaba262477949cd51290e81196bffb954a492 +b060a16079dca1d28a1fb33cbc26f368630ee042d980ce305230005d5b9ab533a7a695281ab76e9214458303932d8bbc +b303783196a858fe45d67e0520c30576da605fd69964449c20009fbd5099cf1de52a32d326d7c3b864de07440195ef40 +aa550a4c20d1003d137ffd8fbdc1196d09ad53cfa0e202302093a80fa3bbc4c9aff83f34f2151785cc1ce5f30255693b +a7f8585f45566a351058e10c6f1ff4a7ba24811f1482a47202f581525615ca770da93f2f58878788b45b92cb446ef4ec +8206f63a9a5b59bd68e64a843e68fcdf706f4c13bbfcdfa9928298e5b9251006ae0bbd80c715aa3c9957d2c0148b5059 +ac9490abe1241319658f1c2c645cfa01296f5d4106020c7894b7ba4a65cdd52f6c5401bd3b3cf1c9863e088cd8c9a16f +85dd6d9c80a1b58c24c4d2cb7590d33d2454f381f58e820979948e5831972360cde67bbd56e1860077ef5192fcacb904 +8b0285944c676fe2519cb68da0973275fa29c0718d838d363ce46651b068d29f867cf9fe579ff8da0bb8b37d202bb23c +95147275da658d43a758b203b9ca1f1c1478853e9bf77b5218593142e2bd9c0bf46d2206ab64cef99295de6e9a268edc +b8efa187fdd3e1f46c15cd596e9567690c10e253b5beaa5be8074b6ea4e6d3d06e0f2b05323453239e419ae1e7128521 +8340464f52c92e31806fd3e8e65f56e27194d1f6daa4a0f0b3831e8102aba16f88bb5a621633ddb7dd0342e1d2d12343 +8615d87dcab85a78dc052f05a01e751176b756b5dc9985014347454ce5752f459dd6464e1c5aff36cb6c51b783fa2692 +80c6e35c0d3defbe4d3968792724a23f0b8830dd2fac58663583a49339ea20f1812cc4140e3ee867c7e716177319bbbe +a7aa63dbfc201dde8f29bb6e23d7aa5020dd35bd18a0cc93c8a10c35d695913fe25b9e8cf9b5fd1899e9657b22bc8863 +97c2a4ba80c4caba2e729a603d2faa0120915e3fe64cbb065f7ff33de5f877f1ec9461cf455e88ec9e9ded9393939dba +a54bd1419f0e2d2d87757870f37c476c7e3a13502f1ada82fd7394fd29f8a00c4986473d753034d0954a2550badbac0b +8d3e2bf900d0d2b9b46e6e2f37620f0cc90526dbbcfaad4e4a37ed53f39fdd23bd3a6f21aa7e800eaec937d9710dd6e3 +a88d2b1c7802b2dc216c2b6532406c091bfb12f29121b9a82c1154470e250188413ddd3e79f7e009ea987a4c45b332e5 +8c552c2101dfdc3f99c2da436115452e4d364eefe029b12946f05673c5ce1cfb48d39a579625849236dc6c8e7277dd30 +8415c252d52a26a6400c3189c928a98559bf24162ecf3eef1d10e439269c31d854b0b4f6ec7a2430e3f11b5d77de78d6 +8b38905bad93a8d42339dbdb5e510003c51fcaf05e04f88fd7083753353bc1c4c00a5dd4a67431cd4456d0669c7040e2 +b1d0ed8862250d0f0d9ef9dcf0cd16d84313d1a795dc0c08e0b150dadf9ce73d32d735e04632b289cafa69a6ee75dc89 +9434e18a5fb631b10edb02057f2d1fe16000ee55ada3c26a079c9fc3943e29d6de99e52829fe7b333e962270c712e51e +b1b9f3914007e6fca8ad3e7e848a1108988cb2318da36df24767d804e95d1272943fda948451135cc1b5052a3953b081 +8c02947a76d7b6c0a700a83dfb971dc105bfe996e18c521445f036310914b349ab28e57571e36ae08d13a46fb01c2f43 +893472fbc225f973a0ac6a0a0130b9cfb7ab6869dff80df71a62b1f6beb4afd069bbf35b4f327165bc31dff39e4fcaa4 +a7c176c0903175f3540d62f9afee994d5d9bf37081e094644b22f017e94c515afefde7bb07f638342abef7de657f8848 +860186c2b1d3b1e657729bc804275fb5f5ee89eaa60848fcabd3871289665ea9f0efc8a95792d884972bcfa2de96223b +865b38aea6386d0ac8f501a7d934e23d01dc50105324e354d4c4fa3cb1d4c29c26f4566df7b1a728e10cfaa9d24552e6 +b4eea5548de6969dada658df604b5d9c49002e2258352838003e0fdf7b299d81fb025807a7f37cf5b547cebd7f2c1f93 +8982de11ba68d63a649a3b296d4d56c71e3c3eec016db250d733ab7c3b9a620c09c5a5d0b64fd30d3bc03037ca4b17c9 +84d8b8a10d67eda4716673167c360fc9b95717cf36ef1d5bc6f2ef5b9d2624f0e76c2a704d016adf03e775ea8e28d83a +834d03ebd51aff4d777714783e750b84c16cb6627f8311bd8ff17c3b97fc4a5bba57d6c8f6d74f195d3030bcb5f07612 +aaf49e0def0c4d5f2c1e9c17b51e931d2f754b19e80070954980b6c160178349f6d3c8d4808801d362e77f41a0008918 +8ef4115edec841854e89f2bbd11498dac7396bca35dda554290d3db1c459ffc17be671f4a46d29fa78cbd6064cc2da20 +9641dc8a64f4acd38e343a3062787c48c312f1382f7e310ccea3e95e066ab6dc980f6ed90a633236a435e68bf6b3c625 +8a84cfc2cbeb18a11dd6c2a0aebb3f6fd58a33bb4b26101e826add03748595022e816afac79a4e7c20b3805252839dca +9770782d729017659844421e1639ffcda66a2044df9e19769b90292df87dcb146b20c6b9141bb2302029d84a5310665d +98c7ec9696454868ac52799d1c098c15ec4e08b34884dda186ebfe87d32840b81fd3282295df141c91137faf4cc02da8 +a3f6eb921247617292162dfc8eec5b830ddc294a0fb92f5b4828a541091ffdaff34c392c1d7168259d6204405d90ec72 +b185f77a468f07a54222d968a95635234e74fc942485604909308a9028ed2753b15902b9134749f381f7cd6b89cc8c3d +867608a682d53bd691dbc92eeb460d1c300b362ca49c11a280f6768ccec217f1145f9d59fe50d994f715ce89d38a74e1 +afaad630ad8827cd71aade80edf3d7aeb65a344878db12fa848759e6233f6fceca563aa437e506ea9e0f1e47b126d45b +a12afbc84e3441594aecf85d089423dd3bb8bb33a1a384ddf7cc14caa72284caaa56aa179c15e3140fd56bb532491a67 +98757b0b5e5837ddc156a4a01ce78f33bb1fce51e0c1254ee9b6d3942268d0feb50b93edbf6aa88f9ea7b3c0309830d8 +89573f4a4ae752e9f964e42bec77d28a41840c28e4bcdf86a98a131d0b85367b885077823a6f916972de6ac110821bd2 +a17f2745052de5de9c059307308fc49f56cb5230e7a41cb7e14a61c9efa742ee14c41023ce90c7f2261adc71e31045f8 +914b07c53a41c0d480083f41a61c10429ea42dafea9a0db93862d2269ff69c41db8b110b4768687b88089b5e095523cf +b380cc3e0d26370976fe891d24ea4eeb1b6be8cfce01f47fd68838a27190e644fd57b049d3aa0a9589370de20e276944 +906385fdfad60feec79eb1c303e750c659ceb22d9c16a95faaae093daadd53e7aa039a45d57e20951d6e1ca0dc899ef2 +b5211ceee31b194dba60b616bfd91536e71b9213a3aaaf5aaf9b2f4cbdeb05191861d78b97eec58e3c81abe4f0488c04 +97878e9e38c2f69d697800e7a2f132fc4babaacf471c79c26a757f771606e55fe696ece68a3163a0ffeb2f72274cf214 +959431c1f54c46500c05aaa9a2bc4230531dad97ae768fa92bb85436c0ecc6374cf20fb0ef82d122db116820a943b401 +b69e5a1c6798f30d33e42cb8d124f025d2c77c993c4c7107a539aacddf44d8d4d2239e802ece32e60ee4dbfdce201bdb +a8b09e5e9f802ad273b2efa02bcbc3d4a65ac68510510b9400a08d75b47b31c6f61ffdb3704abf535a3d6d9362fc6244 +a41ace7f1efa930564544af9aa7d42a9f50f8ba834badcaf64b0801aaed0f1616b295284e74ca00c29a1e10c3de68996 +a8f2aa0bbbc19420a7c7cec3e8d4229129b4eb08fff814d959300cd7a017ddb6548c9a6efebad567d5a6fde679a6ac6a +9683da74490a2161252d671d0bc16eb07110f7af171a1080dc4d9e4684854336a44c022efe3074eb29958ae8a1a14ace +8ef44d78d10795050c161b36afa9ab2f2f004ccf50fdeef42fe9cdc72ebb15a09389ca72a00001cd6d9b1d7b3bb766c3 +adca54f3b14fb18298098970b0267301b7312afb75894deea1b2afa3e85b7a3b4efac9971ab54c5cbecba2da9f18507e +ac5d4528f06fdccfc1370d5c3d03ed982fed0861a93a3f6453aa64e99360b124926d1892faaf72d89459e663721dfa99 +98aa1c801bd615b8cba728fa993021e181e0ad717ba01c0290e7355694155407083eb53cb70819c4775da39d33224db7 +8b3aea4c7c2bfe1020de3261ec085d79c7bf8a7903b825d2c70ebbb84af197bcc54e3653c5373a2045c3021526b63b66 +a29f3de4cb3d99afff1daf7d431b38a33a9804fedc41626618928ed059df6f6fe9f298a046b594ffee951ed4d4e1400f +803fd346be540c5242667c18ee41b26bc812456ab13ff117196ed69b90ee608c8cb6554396b64066a546ec87a71ed6a9 +a9c18d81ffd029c0339c72c499bb51685392253b996b6eabd8b76f05c6191ed8444a1397d63b9923743661a319517f7e +a048d5c390d08f07161faac71c5994baf152c883b205f3bb10d3501709d6516ae54d491b486303a11b751857a31f0052 +9156fb4803e40e28d8d57d928481a8de4373687288da44fe88c5676a8ae013ed1fcc09d56a31140bf74e7f767253810e +98e289c725b18e0085afdfaf2acbc674dae7b0a2ecc2537a7d0b87e20eb785404ab05973a787f0495d2adb3e5565c09b +8a7237b249325bd67cdc1f9fb278710069033c304afbf270b7ea24dbc10c8eabe559a484d3edc733c77b4384932deb41 +9056f2e5b02e5c2e04a69fa1323bbf1859d143761268d18e74632e43800a2a9c76fd681e924a19bc141de0e128d3e462 +b9f2bf9e4e7263014296a82b9ecbb05d3f1efa4b2e675e3b38d3eace59da06a89c859256e1b77847886d6aa15f98f649 +83b22949cca19030289bbf7cd2a0d8b84e1d468e78bc85271a6753241b89122627632723bc293cf904a5eb2b5dc6c3ae +a919aaf35dd0116168d2ee845122026416bec9633df113fbd913d8db5996221e234f98470d029a8ff182825b59fda20a +91726901f49d32b41afa15219073842278f60dcee223640903d871e318a1c2b541136b7b38a7b2ab7d31e4242fc29674 +942b77666545bc9a858d36cfe857ab1a787c9528f4a0b87918a06bf510793264dcafd12ae6bd3ee300179dab7f40aed0 +80adc1f2f9c47a96d416e44fcba41628abc0fae1f88f6a26aea4648419ab726f7fcc2187c7d5145e3d8f5a75c03937f4 +8041e0f66ba9dcee01e336dd4d16ae5e4e1618512fc147cc8230003aa2940848162dc2187d4130bf550dc1f3559849d4 +999e8adc51bab54386af1c5e8822986ad1b7ecaf1f8a4c2baa5bb2fe9d10710e49545c5a8bd89ed0e61a3d73a908e5ef +89272ffd39b6e9f99fafdd58bd9dc00f66f26a1d36b38a1ac6215e3546d966739eecda7fc236335479207cef95cce484 +b8e0b7532af13f15dc04a0eb4ea8abd67e58f1b1c6ad2e70c0ffa04a5c18ec2018b5d7f4be2f9f86db5e0b3986f639d9 +b96bd11b0f6ead4abd5fe1e4c6e995da7583b901afd01cc05e87d04663fb997997d6d39dd9fb067c62cb1b1cbb67516f +94ab08914088b973e8dbd5685decb95f3bf9e7e4700d50a05dbf5aaac9aea4be2c10c83096c02252e9238ceea1351d05 +a188de419b062af21275d976494c131ba18d2b2ead8bdbfa38a777832448e64d4d9725c6a1d530ffb6513f18d5b68d9d +8f73c8c118fa25c76a4ec5611351953c491452743056a819c8c82ba4737a37d88da0b55f837e7239a5f46d2c05a1bbba +894a44769e0be1c26648b0d89c4c9f46dbdeb3a71b90c493093bee372bb9f2d3f319850fd886d51f4f58db0de5641742 +87d239923b0db024a8d9b0281111d47b0761d81c50652268b074efa3ea70d793e30f874a91ce33a4acecd0cf38c01951 +b1b48b75a97f9fc2dc9530dc69f6268829dd0ddd574516e7eb1b9f5c3a90058889a7bcf3d378738e6d4b02f5fbfa44db +83e3ee9526ffcb60c6e75b75550fc017912ec0daf96d0a0d5f58c1b229cce90c684ac7c3e17fb998def8e7e2e155d750 +b9b7bba579e474b0abdc7775ff5f84c9f117c6ca17788cf5a5f01b2c35a14aa39036031c8d799fec2cfb371d9f7471fd +90d7faf4891fbc368a32f575dfb69f13e37161ab4f63a7139be103285a49490c2851a907f8d36e09e7d1a190dddbc6cd +968c8b9affe18fc34a4e21f0d8c5518341c566099e6b45b8721c9912bab3693c9cc343406fe90279692a1eef2a3f7311 +8735baaf4704207550f77df73fb701d9a63329993a8cb355ccc0d80daf950145f37e9b4b22be2aba29898e974f9fd552 +90f52b2dccf525b9191d836b205ffe966d9a94f6c5800f8f51f51f6c822619e5abdf1257ee523597858032d2e21014ec +831209f8f5257bb3eb452d3ee643d5f063299f8e4bfea91b47fc27453ac49fd0ba3cf9d493c24f2ca10d3c06d7c51cd6 +a5a4db4571f69b0f60fb3e63af37c3c2f99b2add4fc0e5baf1a22de24f456e6146c8dc66a2ecaafeb71dce970083cd68 +b63da69108fad437e48bd5c4fc6f7a06c4274afc904b77e3993db4575d3275fce6cffa1246de1346c10a617074b57c07 +a449448d4156b6b701b1fa6e0fe334d7d5dd758432a0f91d785b4d45fb8a78e29d42631bc22aaa4ea26f8669e531fed7 +aabe43de1350b6831ef03b0eef52c49ffb0ccd6189cce6f87f97c57a510ac0440806700ce2902e2e0b7a57b851405845 +91015f144fe12d5d0b0808c61fa03efe0249058e1829bb18770242f5fb3811e4c8b57ff9cb43deccfc70552e4993892f +8e9c570811ce44133ce3e0a208053acb2493ef18aade57c319276ad532578a60d939ed0bde92f98b0e6a8d8aabd60111 +8b21839b5dc1c9a38515c1076b45cedec245d1c185c0faac1d3d317f71f1bfebba57c2559bcdb413d9d7f0a2b07f3563 +90413bbd162be1b711e9355d83769e6aac52fdfa74802d628ff009325aa174c68f5329ddd552ef93e8fdcb9b03b34af3 +8b6b02e3f9dd1031ebd3df9a30432a3c86e64306062ef00a6d1243620d0cb66dc76f8d0d412eceff877ff8768c2696ce +9894b41d9fc715f8f6addace65451f41dc5ce7b983dd8cb33757b4d7259bef12f144e0077d0b662aa847d5a45f33c563 +a353a9740f6188d73aa4175a6c5f97898a05ed7aae9d2a365f15b91dfa7c28b921fdef0a32d90b6fb82718b33d3ddb8d +984eab8faed87c403c9979f2d2340fb090cc26d00cb4092aeb187c3f4ee1df3f57cb8363f7764073188790b16dfc464b +a5c5ae0ba435fb7f3ddd5ad962358da326239ff236fc3b51bd22e88296236b109951cee1b98f444302badc58d1b5bfbe +880be1006b0156f2788813432f450f613d235f41aba52a6000d2ad310408ad73d86b79f6081aef1e8c51010d404ba670 +937da751aae68f865c7a33fa38d718f20e2a1c65cb18c8e08f8441f0cdc77662789d2793794dd0a427cad30cd0b33f42 +9496fde66c834ff86f205897db12bbf9a9bb78d9ba8b5fb539cd0a2c927cc6b4120c017b0a652750b45edbe5f650e5dd +97a6f409ffeb593e149307a14bc47befb632412d70565c5f13d6b7d032acd2e3ed0f7b6af701b387f11d69ee4a8094d7 +97ed94934263dc0260f4f7513745ed3483cdddb9adb85dc33193c3a8b4d52affaf1ded23b59c34651afbffe80d40dc36 +b2b26378d44f916bcf999db218b9892e06de8075f205c7dafd6d37a252185c2d1b58e2e809c717963d25627e31f068e4 +b8f9fa1fb45fb19a45223f7be06c37d3a3501dd227c3e15999d1c34b605f888123026590697d0ae24d6c421df8112520 +997aa71e3b2e8c780f6855e94453c682bee1356b5ce804619ef14834475511105b1e4d01470fe4e2215dc72182d9909c +ac2cb2a7cf55aaf990cfada0218453853047e813d3f51f5a623d09f4714da79de6592671358a5edf938a67f905b6cb5b +8d8340d0c3081cd30d34f3ff6191e1ff6ad7994b4ebac19e5936f1157ca84e1813228b7605ee226366d6bab1e2bf62a2 +9693b17669086003cb46c75fed26ea83914a54901a145e18c799a777db1df9c9ca6b2ea3ee91e7b0ab848dc89cf77f19 +a6b6b2a6cd8c4922d78c8ba379373b375d66ac6ea04b830a23d5a496cf714a9439d81c865da92d52600aa4e2e43afcf1 +89cb665020abc3f5e11a03c7ba5ec9d890fa9ed2630f1443a8e45a28c32786ed980b5343ffffaea60eeff5b313bc0d66 +b37b989106594221bc6cf33a1a83c3e65ecdef279e90333a9e105b8139dc28384bb2277edd4b77c9e59d15e6afe074c5 +98ce5aee5918d18b2326b30c1ba41669cce20bc7a1d1b585363305fbdea66055164a7ac398ca0f0e670291a3061022eb +b57f472d5f34beb4cf430d7c0f8ac5bd1c0621a284633ed36e6f7804bc2b7847f54b469c7ea163a436510d9e3b32f97e +ae673a6579dbf0504c8fd0c8fc0252d2f7ae8da615a06f4d215c2f8a8f516201f24e5cc42967630c252905e5dbbd6377 +97c1501835a31091a5a83f0546e01c85ee847a0ca52fb3cc0653f6a826e13d25ddc623a5dea139108f7270a1fd7043ea +9376ee667f3834f6c0da4324fdcca5c04712e0649877ee19da79a2d23be24640c38758fce562470ce2134ca34148ffe3 +818af89c40379a10074cfaba6d5968ecf667f1a68a7edaa18e8977ccb34e0829f237c5634fbd079e7f22928b277f1096 +b8e0af0be0a252b28df25d4a509f31878bcddf702af0e5553393c3dfd4a1f1247ad8dc2668bc8dedc9b41f6ad8e71b15 +811667ffb60bc4316e44bd04573503f5b4dc44d1ec824393a699c950e5fa085b146537ddd6a08a3fede7700396a0df7d +ad834cbf850b2f61ce799c4a0f8ab0c57039d4e1113933c50b0c00175171aadee84894d1376cf325bfd434c3deb44315 +a8b7dfcdb40373ba4d55e751ccfb9070554434df9e359fc165284ee3dc35db6fb6055657ecf5a9e9b7b8e2e1abea4375 +b56a5b9fd41c9d3f65532aa58bf71a38fcf07782e1ae0084dc537862fa02e6d66658b19d6f71c39cd5dbfac418da1837 +a935af5ed224b9533b41a7e79f872f6851591da9e9d906050ccd1b2c772a1d6d010c5fc7160c4f8cd7d3aa14c3bcdc26 +a81e580fc98692567b28323fc746f70c3139d989fb6aabf3529504d42d0620f05327e3385c2bd5faea010d60dd5c8bdf +a8b352054cdcde8ddb24989329a249b71498a5593a13edad1e913c795dcad3d24789abca9c7ed1d57efcc9e3156da479 +b0de8a2bd7f93284b2bc700e442f52ada16a22ad8d86329591547411c23fff0333b2ab0c9edf82bf7903ebf69916eed1 +843e9781b653d1a427f3534b2e86add49d308ca247546f9fcf565f9e08df921e4d969e1b8ed83f3f849e98c0f63e39be +84a4098c5dca9f73e827d44025473096101affd7193c40a0307e3215e850e753e9a08e6e74a442d57626ff26df77faac +b463eaaa2f3315b511c22a97fad353014d840a6a95fe0d457d0677e63e571407d7f5268f8775381a5e7adc3b4163eb88 +ad0417edaa16cfddc288eef4173aa7057ca4f81e815541ac588ef5f24b98d56fed6845deb6ae1a9740a28bb1cd8780a7 +9271963b8fb2288a96e07eac13c0543ec41abdc6d978bd7c44ae08251ea49994412b542c77c8208cd71fd8e7852d4a70 +8b68b6db9044d8bafc155d69e0daba95cd59d6afebb085791e999afed4f33a2479c633d31d534ff767b8cd433d591a23 +a6a06a0e433e385437d9996ce823abda9848754aa9cdd25ec8701af35c9ec15df999825669bbc2e17cedb597a96e8eeb +94d414bff8b6b8597634b77a77d1060db8e1af0d0ddfb737a9bf1c66c8430e93a425510af2464bce4a7b29bc66cf325b +b6514049562af1c6fb7d0e8df6987b020f0b7a6e721f4862e36b1ba0e19af19414ede04b346be22d348b50875803d1bf +a42c7fb34f2fbee8aaccd1d86672d0acdf4e6bb083ff0456512d7e1e43be041cc0924322fcd986e6e1bce5d5ecce6f92 +867cbdd169a52440ae0a75d33a28c7d00aa92b4b65aaac5e62aa53a8fc367c08ab8828cc8fa18b6e7d1f908d158e3382 +a6fe0b768fff3e4a6153e59a7b7508eb2ee8165eaf5274d41ac2812bd4563c4ca2b132f0e27ea2f1c98759cc3589b61c +b3eb1dba43d10b9e17ffec8def053fc96f9883bacb49330a089a0ca5b9ab0182e8b5111ad4aa55c1ce1b6f4afa5c70a3 +a1531351098bdfcda566ff4d811301c0305626c77f954a38420c490e7c684f517eb1a4e4bd2c3904a10bac889cba314a +92278d106ad2f27eacdb86bdb1faa0a07a93765bb79dcff191873c52253af83480114b2299ffe5324f9c31d0abbdbbd1 +8900ba95a90c447fb6fa1f528af3d7a378aec25feb0620516b6b97e54b328fc31af42e46a8ad5e6e3029d83a6f2bbe5f +86053d481179c1ac910d5e7b9a5de82794b442f20e854583512ce1f9c3f09e71d1bf97d6700fe776debfe1527ab97a82 +a32a60de492fc4340336416bccbd2591b5e414fca0aead82281212e24490acc01747537b3da783684e27aeb987245cc8 +9820fe8e0338f21797143f368177e3669a1f3894b40ae9fa3b353125f7c8e85cc424dcf89878f2c7667f65db3b1e4165 +934d64711b4348ac5e1395cc6a3215e5643b540f591380d254165486b0ec2a1d0d21c7d2c6310f9e0eed3d08ecf4b57c +b9fd32d589432eddcb66dc30ad78981360915854cc44b2afeb826b5d48a08e377dc91be66f5bf1e783d1a8bb320f7ccb +98c972cf01efff4fc2e485b47572e2d8dde22461d127ef401b71a111b0603203971e3cde40912643affd7341cd27e57a +8db6c1620760063edabd376f4399b6e1355462e04f5c81cdcb3989fdc00f9a466bc85ed899e886c89c149adad69edbad +ad7b7fda0aa6e2aa66a27235ac5cc680aa04b85dce329fc4be84f75c9c961120a3d9e446aa44539aaac8ea203eecb4eb +8ccb01eaf41d816ce69ebd57754859e263530915e775c4e7d9dac37b2457a9099b9ae9b4c6cb09eb5ff246e3c9320c59 +b895b83b5f7ca46e02697dbaa6157df6c7571864c83e504a8c77d965bc2ba97bf9353a71c56a020df64498bd40e30b21 +8018c07a81c522fbc25f2cb14f2321c61b98bd8962ed8eb7d5823dbe5d1958a5ec2fb5622fd0868e991bcb6cae016ea1 +95b16364e94d01b3664812264d7185032722a4afc23bdd33bc16ae87ee61816c741657c37138d9312cebfb5fcfbb3b2d +94a709209990a8b09bfb4b9581ab471aae3a29526eae861108b28edb84aab6d28f1d7a25dddd8150b70af34bee4ca2e4 +ae06c80839c5a13269b984ff4d8a5938c6f4d8d647b1b1daa8cf7f6145340b76a286cd615ec251a65501e6290162da50 +875cbd0694eeb90d3567da9dc7f570d97b02bd9cf17bfa011efdd48f1d580608a3213bff4006603b8b4079fa66bded10 +b27f88c455f025e1cd902097d6a224d76bdf9c9195adee30bef4a0b0411fff980787285896e1943a62271d0aca531446 +8024880cde783cdb2b863e3dd856be92bacc5b2a1347e96e039fe34279ce528560d2df7d4d1624a4595dbafb40529697 +8883d02c2a5c0e026d941c785128d4ac6f7a9de625ea735b7d6ff27a5ba10fa4d6370d450d99a855d919f40d64f86afc +a1beb985c45fdc30ac536f1c385b40b6113ef6fabc2f76d255490fe529468847a776efa674ba8fed72180f07d3f701f1 +ab83bd9b007561695210e3276fde72e507456ba277ad4c348a2aec7a6e9ebdc2277cb4bd0bca73bd79bd2240a1fc4456 +8db27f516153812149854fd6bb1250e843a3ae1c9637df818b08bd016a769d0497ab6087fe3b2fd4080882713607bf46 +b3891dde4e00d60386aeff161b4a0fbc30bb31ee7918ce5fc0b49aac3238a000ced192c9c4c08d90de3a0ba973d7cfd6 +90a2049a15c02e59024a7a1cb0adea97501c60b1c7442fbbe560054c3d69264e69627ac57b7d9be01bef498bb2a60198 +87df67a4bd72444b5faa4f3b067204c4927c869dd3b29ad192d859589a9b2c1d6d35ed68310081e140add254a9463092 +8f80986a8dc8a0d6408ebbcb4f234e76413c11cb0d66067f9436bb232373100f20a4fded60f08dec3525315abfaa8523 +b061e10beb12ba3683688a4ae3a91600d14878ef78a308d01b93e4918efc666450e3f7b0e56283468e218934231df98c +86b9e55f3783d62e381659d3e06699d788b88aab1ff99848db328a83c97d223f602201bf2127c5ecf419752fed0a224d +858d878e29925c87243e010020007f96fa33264e89c8693af12857b362aee3fac2244057e159651c476ebe1dfbd67bcb +8fd47cdef87d7a569ffce806d2c2dad100692d6c53e5f5dfc6e274f897dccadcee30fc6c6e61373961bbc1f3ecbfa698 +892f2822daf3df3a759bef03168c1cb07408df62e024747a788e94d2da325f880bb9c6e136c7f6643f45b021c6ccb654 +8714e37ac24f5a198f219e7c88a92172fc3db129e044e914663ac708d8101851e7c53fce79d32d0e6da74f2ccd1d30ff +ae95e1dbba8b9e2c8dfbe1c202e9ccfd04fa396470035a699b902fbd86d5e6a31732a7c8cae00b9a4f6e51c8d560c7c3 +b0cd058e77498e860fa20c5f8d9bd09bb249add1badf84ba8d1bd49e704b9b4bcd67a5c3d211840a2c8fefab3fea639b +b78e468d3a7da0dd481f333ae56534e2ef97587be2e259a458e25aa37952aed1cc5f835640f812d8052f5bada8f57b12 +835de7965c6b26e7ad1b92eb6f0261d1f376fa12d61eb618d9b342b597c9c117a5a8f6a36269aeea88072b4641e6b5bf +b4d0eb99136b3643468c9c48a20fad62785a60fbdd3c054efac4bd1fa7979b4c9ca6c2c0b18069c0912bea2f19832790 +a00c47315dc0700a850966836a95f3cebfde04dd094bde0742dee77b89a05b5ad655921f86fafd1e902938ff34d4c58d +ab13fa0afaa92229a71ee91efae6d1b15f14b6eacefffb7401d41d0d6db24e24a8dbe8ee19b4680ecb69d2a0cb4e84e7 +aa56c0fb18401210062dbc653df8e3732aa8921a1280e9737e99b26a0100a13a9cba8ad0317a69bba16193362ee0f030 +8b410324a6406b345df0fa25f541ac20b7313fa55832752f70cf4c79f43b0bd3d5b4cdc447e6ba7bca08d0edffa8e29c +893362241ae412d9e5df46506407595c58ffbd7fb1fdaf0694c3432470599291238997abe118bf7737e56a4f5c9dc292 +921618194a756be81cb49d6357cb392b32cc62d96c8ffb7e16d9659a0f226a0436bd378da7b835054dbe0de2c6372ef2 +94a2904f10994928ff5367b777e1430047736fbece33442cf452018bfdeae62e84cd75cf80f8468285e347d504c94111 +b4b81545b767f380bfe10e0fea9c3cc62ca8db40b43c83ffb245259378731298e3eb6c3bdc3a16932f88f5d8a86edc4d +936203c2453ff01c6fc635e4d54320d69e60047d805daae3b75633c2259108497b778f011e5a057249f11b2b888ea76c +b90bf6378d29339443c3f2008b1e2b5f0345f86e393027f14a295e583bf6e6c2b10f54b6dcc42079ff0d356c405b03bb +916913f550d327de2d8d6c7723dcef2e3869efaf95fd963d95c8980b97748c61ad8e2e629cead8577266d93fe39203bd +a033c6f3d5ecbabeb83eb363e54e5faa7ed2d7f4fb771b161762c4f003eac4e1afb236806b784baf2222cad54e2d3cd9 +ab289d4a5771147e6c29ff9ac2bf65d70081ea6c6af2d9b728c3c144574a31b5fd8632af57c18c389aa2cd994938bb0b +9488da2019ff13e290eeac132b491df58b5b7b23c2898ff1a67bffd7e9c9464c39bc8177a57950fd28589e3d9ff9c6c4 +a5abe42b2e0891851440fb2aa6c1d8a86b571bce8b80c8e9e2692e5cb6d45a1b2f055c9fc4c74a7cd292871604129ea9 +90bfef698e83c2ba4dc9304aa01edd274169a978b7154bca518daef394f55857d0d1922ebef3d91fc5ecb3b895d9e0ec +92328f1372b6406ec80786041b6d57018b8507e3881a08727aadfecfdfcfb0824394cbb1150117ac5da5d71b89e895ae +9719751c5f7a65ae2bed8aff7b4b8c34539ff011b259b7ff54f63f9d987b3fbdce5c99534ed561aadaf07bb6e939e208 +a151816774aa9379fccec21cf212429a1c68cf91b055cbb9d931f461a8d5616c693331a11ac5c6fcfbd17d84ee0b44e4 +a72977b1285618a45943ad00f33f37102e2885eccd2f76785254eeca495068fb1d8d49865343e9e8313c6c2c3b2024da +a6f5ad2e023a1585d90625c9f7094f0e8851c79f0eede8ec582ee8e063407cc5b8298e5fdc4c786e4fbbcecaf33e787e +82901e008febcea0c0a14ae21d985a397630e18ee6e346f4a449f23be228e8f338df567d30211a11180b94fbc5204bec +b9b57fdb8d14d1be87a25f89553b3966eb7869e0519ffdf4cc4d51f4cec90d68f7b81cdc0450e04207276e9c63ace721 +a06eabcf43585a001448f3dc30411f3d5b74fd0a695c81eda9981842ba2bb0081d3f5a8360aa18b6d43ef13ea78b293d +926fe48a7e8f07559b7237beff9504476dd97b5b4d67acd01a3633358a6ba4c7abed5c87683a11209aa2ee759888e00e +a716cd3a84a963e2a5a46145b6ef4ebce705de52bf2945c374152a1e41c228a9c4eae0b6d1e222c1eea8b9c13c002177 +8a9b5985df6fb32cdb06ba1591a977545444478f2fe985ed1b10de61c630f0a4693c2185d63f0dc0256b208072c43b17 +a8eab26ae0ebcdf96a59fad1dc2d5e83b94abb2ea1774b607023f9d9e0fe065853b1e2242e794f989a80a47f550c0bd9 +84adbf38164cd04f3d770a7f4b8eae7a5d25b4a803fb63c02b95b71b33e454319c44e07a760d22bf5f58e7e372d09a16 +90f443a3ba1b9129a0bee400b5b29d42e50bb2aa56b0022bbfc3c6f8d69db40299871ec7c1b68421cc89e1af6b13a39a +81c5a94b379eb98c494a8d0067c748ba47e87a2ada0105202ed7651eb4e5111a0cd8569b06ae68d392c4fd74a37833d2 +8f92324b14a1549ee0b186073a26691088e41556d33b54258fc6e0b000e9624156db4e97861a0ec22960e6c47ca8a1dd +8b021cd0fffe055068cc460aec3cc455952e2ac32be5fa060e0d1b6cf30ed15381618f801249e893b1b9f10dd82077b0 +b3e9f0dcb3d6f0b138f589fa54dfb01f849890ab97016372d004aac55103f363a64bc0e606ddf75430f1534a30fc522d +8fdfe64af891db89b25daa859864d479cb7599486bd6f36e593f8f2f839f942261ffc3eed5001a93fde44cbcdc24c583 +a9e4554373c5073e135874e2bacbee69c65308eb0785532fec6a37834e8d0b437b77a2f11cc63c87d7183b82cd9b6bc9 +b4c47daca723ad7193ac5098cad4dcab654186ec5ea5c0fd014a3ac39726be954565a901694ba211820c011fa1c59e18 +8835427e86cdceb4c11cbea331ed724e4e78af15e3bab5be54f6b926bf66b5d99bcc40dbc456d86342c9fa83a033c2d5 +8ea84590a400cedba047c2661378921a42f5ca0421da58c1bcb37bc686a2aed98afab3fa5e6ba3a51029390ef3cdf4d4 +b48551170fc479d69fffb00fae4fba301e92e37cae08f596db6f6489c3b7020edc074f9e8d7465b84e9dcef1b6b3aecc +a6f318b1eaab00836a330710e88bfe400395b3081485f6a212e3cba9463f6fe7864ba4f71e57a411ecdf2bcb4d189f96 +848d5137a39999141a79f4bdf91150796ba36352d8525821bf3bd6e070b352792d79147341b8254dd60fa8c36e9e2618 +a8526f8904b1eac4ae2a25534aa91e8031e9aac7b8f58d8f49897e920c36c0232f4a30aa6eed305deb0f7793c115b267 +b8b6a727c44c37a8388383e959d195d1d0e51a657d4ba360633d219d43c5df645383e2406c25f1d418e72b862c3a6e9b +92e64adf65b42c978f36dd03ab22ba983bfbb61944efccdb45b337ceb486beda99818bf20d32a545503c4572bb0a4983 +9653bb83df66260a0bd059cd4244ef7c661b089e403d26ba777d2090783ff31f963f5d3a9c125b1ad1a1d19134f3fc8d +a74e72355e71ae5eb36dc75191643500ca3e67f18833ee981010e7e7e60a68e1b01b05901eff05014b9ef29aa4829f45 +8b2139a5da14524cf6acc593144db23db424b95b8c7041d8f6c7a14a6725dda1cd09c42bb3ae26a5a3650affaa742800 +a60ddff4300ca44a7c7a00a1f98441ad1438e07c30275bc46551cee1b681926d2c825cc8f90399ee5f36bb9fbd07d3dd +a04e5e9958867a5acc15fdea0d88951cfebd37c657102f6ba1dcdaa5e46cf1c823ad0d98718e88e436f260b770599102 +95e977abeb70d46fe8d7584204770f14c856a77680607304ce58077550152733758e7a8b98b11b378540542b1175fecd +8c9ec93ed35a25ce00d61609e92d567459a45e39922ccd1c64ab512e292787125bd4164c00af4cf89fd3cf9deddcd8bb +819819ad0338250d9c89aceda9e217df12ac54e940c77fb8420575caa3fa78930689d0377ba88f16d38179a807135dc6 +8baafb379d4150ac382b14a64788d819146480d7a1dccd3deef6889686ded375900f5df069843ef14d754ad3d7540401 +ab827236996bb79b447714c6993af941c5ae66248df4d9a6f3650d44b853badb5c0cb67804210e07a7b9d66ca43092f6 +927656c3eac8d2eb575e3daeb77f9605771170c325bee6aeade10c083d42bd8dcbf3bcc3d929ea437001c7cf9a95e2da +af22b212d5ee44fd4197966b9690487c38a119cd6536cfb8c181f38a94610dd9e057f95774047a446504dd96dd11e326 +a44bd94b9e01e3ba36340f2ac2201ecb477495d4f1fb6726a6b439302deabb5a35d237c6a6aeb7e3b0a65649f8656716 +af367aeeae3bba14fbdb05bcc1a521000dd9d37f5c34ae56fb306d3dfda201d0329a8b6e89d98e15825cb3c6bfdb1194 +abcc4fbdea43e50ded9e2fb01464f4e87fb136e960141e8d39214f92794cfab5634f22cd40b18d8c0e501f2307aad23e +920786cbd674348b9853689915dfcab02cce2a4596d117962bce36aadddf4bdd143891e22f2c8015517039a64e8aede3 +8cde63b9bd57cb3ef743f1f3e8250669eed739e5fbd68c500a3cc0c12f93862a69aebcdbc69dd8f476c2eb307f572a53 +b967e65a5f1cd8d5d570f5e87e7e186fba51b9504f8e466392a76d8a971fb91fd9b7565bcc1647f50d7d15e48b93bc95 +8d5a87b25fedf5edd57d870304bfd9081dc78c3e3e3b38b997260a92edac7feccdaf24feb51822d2edc223b70bb4ed5f +b6cd5d340a57f8ec73723c4f3ecd6601620dc8137a3e75a5d3c578bc79a9cae86b379950c644dee2ff99dad780d025c1 +b6f0a8e754b7f52a85a2a2e6512cfd017f7fb0418d19bb318308951c4e242d3c65bbcb9748da9cbc91a738f9ca577332 +a89dcf7d410bccec385400dd96b1cc6af89026a431d0f531aa992cbd7bc8bfd7c5f360bcb665bda1d72efa17bb982551 +97788e7522427a46c4b6258d15623ef7a565712812fa80d001e1de8dc1791392702f3fa3cce5a8cd1c5755625a0ad10a +b5338fb5e137ff625b27c5148298f27ce8f493e2527c5d0facaa49f29cae34580d0d6c3c1074a2e46cd8db3f56004ea9 +8962f006d7b1095dd0dd132ffe7e87e328510c95ad893cf3b2ab21c177c5cf2c27f47d8856f87e9762c547be009d25c0 +87fee9ce9c26aa476e67e0791a809e0a06a8a98facf3faea730d438d3e516cdf75d645fa75c906e4e44ab9237a22c016 +b75ab972e1a1214bab0b38cc3e973d44bb233acda5b4291f5e110b6fb78fdcab93dc63f01168debd898e165f615be1f7 +b5a0fb52bca279d3853761a94b206acaf313df33ae6303d9b71edae90b66fc507adbc60fb11e758888736c81d5d80c0a +849b8f0005010e684701cd3a4e59e8c89e5fec59af6d2de5b6332cde03b865ea84f07f0b80ec3404380b0e148fbd2c24 +96e2b0b6fe78408f9208f809f5c40398100b2dac202c8c5c33c2189560dea868270a598c419871a5a2b67783354f6014 +b234b81f996142d0df2c719760bf996544820a03195a6dc0ff6a72543692f5a369bf63d1f0b477ef2fe7b3234e41f685 +b85e39bcf40da1a12a535740176f4de749a93824079deb5fdaa004f3282fdefaf5275e3418c88c419bd42a3dd2ed2b3b +a27279304b89a18a4e2b443246f2368fb8b15f46a34533179b6bd2ef683f6e98e222b7a32880b39b8fac1afa90133803 +8923c22cf15c9c1964213d725b337ece9ea854775a06f75f232c4859c7142a3942f418354e33066298aedfba3cb27e62 +b109f714311fb9bc431ef57911e2cad6a3949455b9f23255cd7edea35be629e07f845fe53e2b12a32305ee2f4f264f27 +b51e82ae5c7d48050e405897d0053e9ea4b2714d002e88f78c9a307cd50b9c6b3ee7cb86f86527be9d964b01895fab20 +90db256931c7f98bcf3bffff4d496739185e7a20f329ee7bffd4e0850a37739948ec745285703967f4ca50ec370cf68b +a0485ac0445d88dafac56bfba2563b020cfc370f54c1606c89d12cfd8a4d1336d2ba50306e476155a6f5b0e0a1f2d092 +a00754c3462e74bda928da855bbf90f9077db395e32f03cce9b2955546d900b72330d247b7d607b65e130f5b0d883de0 +8547d56727c3ad8b5c8ce622ed9ad86fe8cd78e6e4848c9845914b5063b17330bd10b46d8d3f18f83ca09ecb28d1afb2 +95b937b2a979bce0e159ac75c7d5d659be8599c92305e73e942aab414793364a3ec28c7c1c8491a5750ba84a29828d8d +b011e150f0294e45a0f4c69409999d0c2e602449dbd67ab95e8258466687cd733a0329083a31b03722f4e2580ddc95e9 +924651a733ad5e5d9adadad3ea6a6babb8e455c8d5f2cb5bdc83fa422e7752592190ccedaa827b866861e73506a6968e +a4d5180122f8e31503ae027e54da50f72f5cfb910a6f7309bd882b5cd666f454672591f1f20e461e182a47d03b47052a +ab19ae659c4f73ea3d21895269dbec583c7029955a36469124ebe295027010faab56c4a475973497f28e9a77c03b8fd0 +ae7ea1a803d0f439e91494f8f35fc1167dae23834c0c699ffe65d3da8b09f8df5a53195a99ca7b8558242279e69578fa +b9d63cf0e30f9800101b43b980bcd2f229758e74b21ad5354866b4e684791c08a184330dc316228a0d67fe0210f2bc4d +8c41629744391ddb96dcbbf9cd99b13d36e57d65962e0aeb92ebccf1c4cc769626feb3ec0363def08eceb102b3dd4ad6 +b2848ff24faf9e667a8c19d050a93896e9e75b86595f7b762c7c74ccdfb9db126ae094961fee7f5d1192776c1ac1a524 +af013bc29206743ce934d5887b8d0fb3667c89bda465d2321835a3618513fba6a459dd7566268220ffce7e0c97e22b2c +8bb799e36db1132da8e8b028ea8487dd3266b4628c56dfae4ea275f3c47c78e3d7445ab8d0aaee4cbf42148b3a148175 +ae2b81fd47c038b5195a52ab8431f0d3cab4cf24c4237252d955aad2156adc16dda9d3270157e0bfe5a44022e5c051ef +8e0129213b1698d2ec6df132356805a8633ba79e672e586dfef664ffccca71834253ba14f296da962651fcba2c002622 +a1ae30b500ae77cd9bbb803d737b4a5991cc780618ac22b5cc179efd8fe10afb8c135457f2e7b86ded485ea12eae70e5 +8a39723077b7c0df6e3bf6548afa3910c214ee275951fbe5155a39473be98099626ea14d844630a6fa90292b9594665d +a628386c79b61aa7314b01d9814aeec20c2a66e3deda322a39957e7135c2e52b1da486d1b9cd61c87afb22c1d10f6462 +97867f469b01249820aadd9a54e12d4fdadd4555f2d530450e1f8f6d2dae57360578e2c2c8ba41e3b5950df596537a98 +97f192d0457c217affa5a24267dd16cb4c01de8fefde9df4884e1906d2f22e73382dcee6c7d910bf6430bb03f4a4f1e1 +86d5b5739de8442dc74d0d8dc78e49210fe11bf8c6ff0f0faecbc47b64812d6b28c8afddf6d9c0212f1988451d6ccb1c +8ff3312ce9693cd4a9f4b8e75bd805f65b0790ee43fd9e075fe4cebc87185bdf161335049819f22530f54fed2779a5b9 +8dc41d85548bee5d51941d55752a500bde3c5a8f3b362da4eec307a963968e26605048a111c9166d448b8dddf6f53892 +996bdfd004b534151e309ac925fa5ee7801c9da4f6b4c43e156d1158b134535a2a3956e1255e0dd72ac2af6bddaebcaf +aead652704b788bf4983c8f725c644c327a6e9f6683215f5c826c09f82fd2e40631791f51d14e6aded91fdc018d45501 +991ffab58a82b98ed8fc7b00c3faca153589fe09cebf6a137ad506387a1ca4dba475b0e4a1b9bdad829f1422facaec39 +9652e6c4ae084221d6bad855ec0bc11b5f855c6efba67f644e0902ab790a98861cecc6ce047c68273c3aa7eeb2f4c7d9 +b88b816507aaeea6dc92b861eabdc96988b74d7883f20a4b30ba249158acaff3c50d261742fc9ad2e9eba888a8d59065 +acd028a51e16c07a10d2073b9d03070457ac5f1246365295a1359d015c460b92b4861125fabe6f114de8197045df408d +806d3cd9d02d41c49179fe7dac5b05dcfc9a205a283135d4f008d0771c58e6f963d7ad0f6798606edda718eb5c7ff3ed +b9b71f1657a6b206fc40159a941e127f252a7b324dea864ecd804f48c0ed86da9778a925fb65491204a92bc2a26fef32 +80ed67bd0e74350c875abedc0e07fd42ce7cb926f0f3fb1949c6ac73f2300b5a14a5c6f6ff8aed99d5ea5029bb8e7ae6 +9875f67a7a473714e4dd75ee0c763ddf88101532d9680724b3848fef69e218b04a96b90f88e0f4409aa40b9a21507ecc +b4a2bb1b421e5243e5e7576a0672dc19f9f70315a03f6411c19f76616ffbb70fc5dc0e57fd4ab85e24ea2261b7ce38ab +879723002ce43e6c75ba2246f51436efe3376242beff987d025c3c4476495af32d52a54fad5d9ec329a442b93bcff1ce +a4121efbefd9c3eb143619afa52a916f199c75024908047763b29466cdfc837c2fcc894aca63044c33c41c777e529b5b +895f637b497a9766714a3d9e3c275a1f0c9ddab105bf4c8b7e663f36cd79492022415bb4938c1a4849bda73106ace77c +b119acb8b161ce4384a924645a248a656a831af526cd337d97e08405415b9dd22060849c76b88a4785eb5e7214961759 +802e712f4c0a17009c4be6c1e5ba2ca3b82adcb68793ec81f4489b7985babd8a3873d544de63d5e5de0cb4dc5048c030 +ab111051e4651b910c68ecfdc33f2d99e7bf4182df68cedbdbbcac219a543e04d93ecb2763fe32b40c095c7ca193c331 +855c73ef6afc6bcaab4c1e6388519fd5cbb682f91995bebd558167715db454f38012291beccea8186a3fb7045c685b67 +a29d02ec6d9baf84c19dfd0eb378307703bfafc0744b73335550f3cd1b647275e70215f02d1f4ab82a5df4d4e12dd938 +91510a45b8a50cac982d2db8faf8318352418c3f1c59bc6bc95eab0089d5d3a3a215533c415380e50b7928b9d388ff89 +8286e7a2751ca4e23ea7a15851ad96d2cadf5b47f39f43165dde40d38ddb33f63a07bc00600c22e41d68a66fd8a0fa51 +a413d4e619b63799dd0f42ac57e99628d338b676d52aec2bb0d1bb39155ad9344b50cdfe1fe643ff041f1bc9e2cec833 +85524e5bb43ae58784d7e0966a664717289e541c8fcaff651541718d79a718f040a70aa8daf735f6635dabfc85c00663 +97f0d48a4028ff4266faf1c6997b6ad27404daa50ca4420c00b90f0b3e2d82ef8134d0a04108a74955e61e8dfeac082c +8df6145c6cc39034c2f7331d488b8a411931c8faa25d99c5432831292637fd983d4f6b1a6f55522b4a42a462d63c6845 +98c2060f67a916991b391e67fcf23e5f305112807fe95bdddb8ce6c4084126557e4c5f003afb32e30bc6808b30d4b526 +8964246b3c2b8f7312f0a99647c38ef41daf70d2b99b112412356e680185da6810ab8ee0855ad7409d334173bcc4438f +b56c2c416a7069c14bdb3f2e208c5a6ad5aac1cbe5b1faf99dc89c7141d0259d1c6250be9d9195500c4a41182ad2ec3d +b7864583a4cae3b1083dcdcff7f123d24a69920a57d6594d0b7219e31bf0e236682442b6499a1f6795cfeb4f5f236695 +a064f94139bf1b70d476bde97099631b1284aa6b4d87f16bfc65c075e58b2f1b3c2d057605259f806e545674a1169881 +80d1bc4acf14c0f487cd57c5d6157b7f38917e93cb660f1c25e474fcdcac3c3dfda50f6bcccfd6676bae25c4b6b5014e +8ad9a4976c4e3e282843518149fcf5d454240740f4b91466f6310b7216d23d70b9b47c42870293252f29f092f330967a +914197593d2d99d784c704cad7ecd3f0b9f55dce03fc928d13e1a1034566c4de754f1c2a5ade047b0956415fe40399ec +8d77f5e29c572ec3c0ca39cbae2072ba4102403265b3d8c347a00386da9c0b8688d6e3280c96037c300d57b3545f3773 +abfdf79d935fd4f06a04938d6580a8cbf9735f0d498f49677f26e73d3b34b7075d525afcb4f14ef1632cb375bef7dd55 +a97a8c446e3edc86efac7bda5e2e5d0158c909552a3bf86151df20ece63b8d18b608f477286fb1c7f05605ab7e6a7c2c +8618d946c7fd62486551c35486fa466bdfcdc63c941e4cff5a01fbbe566b7ea9dc763cbe73e2acae063060b619a212a9 +8d03ee468070936004b06acf64b868963f721f37faa09887f8a82c155ad5c5732572a6855b531db58af03b1afe034a18 +8d3247f75966ea63935ef6049f7c889c1651374adb446f49499fc9191dbcde7ea33cbc1f1e2d3d1756b6e69870404643 +afc853c3a3facb4ba0267512b8242327cd88007cef3bf549184ee891b5ddc8c27267bae7700758ad5bc32753ebf55dae +80df863eaea289de5a2101f2288046fdbfaa64f2cf1d6419a0e0eb8c93e3880d3a3fdf4940f7524ea1514eef77fb514e +8434b5888c2b51d12d57da6fb7392fff29393c2e3bfee8e3f9d395e23ddc016f10ebe3e3182d9584fddbd93a6effcefc +b78cbb4c9e80e3808c8f006dc3148a59a9cace55bcbb20dd27597557f931e5df7eb3efd18d880fe63466636701a8925e +acb140e44098414ae513b6ef38480e4f6180c6d5f9d1ca40ae7fbadb8b046829f79c97fe2cc663cbccd5ccf3994180c6 +936cb8dc959e1fc574f6bb31f28b756499532ebb79b2c97ff58b720d1cd50dc24b1c17d3beb853ba76cb8334106ce807 +adda2116d9fab2c214ec10c0b75f7f1d75e0dd01e9c3e295a0a126af0ea2c66373d977f0aefdda2e569c0a25f4921d0e +89a5cefb80c92dcad7653b1545f11701d6312aef392986835d048f39d5bc062cabc8a9501c5439c2b922efc5f04954d0 +b9acb52747ce7f759b9cdc781f54938968c7eeacb27c1a080474e59394a55ae1d5734caf22d80289d3392aab76441e89 +8564f72ce60f15a4225f1a223d757ebd19300e341fd9c1fe5a8ece8776c69c601938fa2d5c21b0935bd2bb593293272b +a5567d7b277c4ebf80e09c7e200c20d6cb27acbaa118c66ef71cbccb33ee3ddce0e0f57b77277ae1db9c66ed6e2d8f30 +b82e9c2d8df1cdd3b2417bf316d53e9f3cb58473c4cb5383f521ef53e0af961ef916e4f6557a6d8b4655ec01415231cd +aa816dfd2814c8a25bd2cbaf66303ee49784df471bac4b3188074ea30816f00f425234454d40d8ad8035aa925d74da36 +9919f384df20faaa2d226b521cab207dd2b62420d25ebbda28c9b2ca76a2a52203b2ad7844c1a25f5c75f005c5a83149 +b24a6aa35c2d0f87e36598b36224c64427cd69642b6f9c1bd478a62c70f8ee69f85028648f6603b4f04fb21355f2afb1 +892e044bdb1276b455eac2204be105e1821f987c2570494b1f32aa09506caba7ed343cd09b1bc126fed5e0fda3d0eaad +af0e01a3ad954dc048de18bc46bb1c4971db2467e839698e4dd05cd1adcb9261013fe9fd0cafb946c0b586f6aad86d4e +ac152f0a9ace425378daf02510eb7923ff1ed2c0f8d1deb918e4efb63655de1ba58c96438e9aa23abdf2431dc771370d +ad8c7419c097709347e2394195924e09617b47ac5c7a84aeb9deab8975f22155de0f70cf20d8a976551b14e3a2683a2b +808f14f67ae801536fb70a5898ab86e50ad35340cffd0648daed2f2c4564c9ad538034b2a179a6a8bfa27e9d93b4cbe0 +80a74ab7ce4769db93cfa695a166db95f0a9c47885ff826ad5d93310f36d6b18b5351c67c858b9837b925e85a1995b63 +95b88c3cdd64401c345828f4e4754b1a88b4875a14c08a668b90acd499b3b858842669ecd73a46c5d9f1de32ec1a0120 +8ddbd770b7b18a5917eb43926fa05004e819f1d1ead05b915269e4a86b53e0633a90559007e59f6705a3769e2126ac56 +ab6db5fc220754f19948bef98844e6e38dd623565d1695e1198040c228ac4fd863c1f168cac1d036bbfb718d9d8dd036 +97bef628e977c069e60c395a17740e0e1bc1828f5607ae7f30ce5a0c95f02b53af2ad062700a75212e462aa22c3c5465 +b68d465e04fd17ca98501e61eccb0ce30401855e98046e0c1debba71c2153d6a7a704aa36a6f12454696e78e87181cdc +a79cfdd048f4181e005bd0fbac0a8424495474956b58ce858d2b700fb0f931c406282bd33bfa25c8991bc528d12a69c1 +843f55fa0a6a0969daf2b48080738f30b269b2e7ec123a799e5b203c0b3b4b956dc95d095bc6550b0013918cdff8a225 +b683cdf2823036827e5b454bfe04af9bec1850d25a7a7a44aee7696b6ff0468b7ed6885a41dde2b8f3ecc4aec880c3d2 +8b500796e82acdc89778e0c0f230f744fb05f762000fee877bcf57e8fb703d212dbc2374887bdc2e7b7a273d83a85798 +ac35a8ee87bafecb1a87f15abc7ccf4109aab4ac91d357821e417f9b1474d196c38cc41cd13667f68d1ffab5e79a6e92 +b6e517739390cfed5b395d33b14bce7cd7aaece57fe79a7eb3cbf150dc10765c3ea9fef7976a21a2243687e6eea38ef6 +b53901eeee26692273365b789f2a60afc9b5f0df229c6d21b07016cf4c0e7985beec748aeca52262f68084393ab038e1 +ac4804f33d8ba2b4854ca3537bd8bf2dda72d4e94ff7ecaaf9bd3b7f098343d74d765471ef80072ae34f860b052cbfb1 +8c6a30a93f1dde18039bbdd1ef294552bf79856e20bce863e4b8dd72d906be3ff22468ff3610e06b5a7d1745dde7ead9 +88f0607fa3b7cefe20a02115572b16fc3222be86bb19e592c86c48afbe7e0dd523492b0c29a3bceb9a20f5538bc3134c +a660b801bbddad725975ddf9a8f606f76ecef831f954be224d6178c368e1c72d346f00c4a4c95c289b62d36f2af323cf +a75b9a6aea9542b698938dcd6cc2f6fe0c43e29f64b2f54aeb05d35fac73d41aa7fd750af4fa9333644aab8db90775b9 +83e1b7129d963d1cd076c3baa5fe422148e939273db173e4d59d1858a7d841eacac7fe817d15ab8f8a493bf46c2045e6 +9060a2e9c24de11f9c70e039b5ffe9e6d32f1ae39f3dda263610df2265d917679e689898e4a8bd84ad34613dca5e3761 +b42fc8b863a2af15e04d1fe6693c09b46007c0b8298973fb4762b45b4590ad7fe0aa758918b2fe5ed1ed0359754fd955 +83e6de7860fb256ecf7b47506a5e557d0fb0aefe57fb513c7dee2bd9604712d08ca26adca7ba9a54b712372a7c585a26 +90586e9cbbf71475ecd3e7b5753b286804dcce61e165502a82b960099e79272de8b7494b8877b54ae838eb5d0f71af2f +b2e4b0d21208f73b7b75e08df80cde20c4578e117d37092a490af82354e2afd3a7dbab46fa2d12fcb731cdaece69c2ba +a010961239bb8809fc7fb4aa08fa30d33a130f9f417ee9ea60f587dcc5ef4e1b7abcdcbf8e848ecdcb7972ef6af46e78 +8f511fd58d1e3403a5eefdc0a4ba6b8af848c7efddbf9575ee84449facde05ae9a24aa41a5725416467f6fbd11369c52 +b24ebbd2d4482eb618cea1ac4fbfd9ed8c46c0988a27259300a7ce5ce1bb256aeca0357828cbbc4cf0dfafbf586040e1 +b3ea29e9cca55250e9b7b9bd854edae40f0f0cc65fe478cd468795d1288cc20d7b34ced33bd1356f1f54a4291faa877d +8a8b20f222d9e65bbde33638033972e7d44c6a310b92a9d9c5273b324c4ad1a94f2a10cbce8300c34dbd9beb618c877d +b2436a9a647dc3f12c550e4ddc5b010e6f9cb3f3504742d377384b625fc38f5b71710a49fb73ffaf95b9856047c98201 +a13f8b77c70621e421be94c7412454adc1937b9e09845c2853ef72cdbe500e5c1bf08e3c8b8d6b8eff4bce5b8dec9213 +b25de8780c80d779e6c2e3c4e839a5a107d55b9cccc3ad7c575f9fe37ef44b35db4c1b58f6114a5f2f9ca11e1eb9c5fa +96ba6ad4358c7a645e5edb07d23836cbd35c47d9a66937d09486570e68da3c8f72a578bd2e14188d3acc17e563a652d7 +a7f55989814051fda73f83b5f1a3d5385cd31dc34baf94b37c208b3eaca008ff696fd7f41e2ecffc2dd586de905bf613 +882d0c7c81e58eb9560349f35c35e4498dcde7af7be8d7974b79d262304c26ab67ffa5ed287bb193d5f0ab46b4096015 +a607158f0c1fd0377a8ee5e9715ac230abf97406c19b233d22f5911ebe716967cc10425546dc44e40c38bd6c2b4bca2e +87e8cde50e5d852d3f073a43d652f7186bac7354612517cfaecd4a1b942f06fef6f14546279c0dc0262e2997b835b2a4 +a1c93acc6db9d5ee426fb4a0b846bb7a7b8d5915bec777a9fe6907246b0beafb8938941c8c79ed6082155f75dbc1e332 +b1e4f61457b86f76cd93eafd7536f72baf239ce5a62bd5a8085a34e90576b1e118e25002d2de49b01d6e9a245ee7d3a2 +a0435fe9a4bd1031ec5973a103ec9396b2ce9fd982f6d9ed780fa80ac06a6e47a0a6eb2daf52df1dc9292db622ee9fa3 +b66d8e8a1717e4bfa42083b6ef4490e090a73168b2912f2111743e089027be0a4945a229ecf5d0b5eec11b23f0e11303 +8eb764f26904eea4f4169be6e75beaa6a39e4eb524625a15a78befe3d8e3cc82692d9b135590c20ed460d6e4ba630ef7 +b7e4aea6bb09829e53fe83e53f49a7a331a6d7bf76e0073d758577e6d6fbe63dab642b23657355cad48896ad8715119c +8f94207982373a99ffa282673f192aa98d0c4461fb77c31dc4549628bd9687a249f1b3c66b1840929341e42516c5c64a +a9c673cb247b13e17fa5e616f0399b7f5c7ad043e143e44ae68855a840870ab3d2aad737ebcf74c2cc9688d17ef3a794 +b02635104dd28c02068985256975c0af783899eb996e37d021d9a35238deeea9e836760db21869be7b6c82aa687ded29 +b33bc0966389710812b5f6698afa3e9c84839a1b85492ba11e6ded26695260abf66be6fb355d12d3a8524966f0f89e0f +a79c0dd09506951c33da3cbc23843fd02d641fc24c640a205e6e8150240372847312b9381fb03c5d301fe4dbee8d0da2 +b74de6f3a2c502b5b658ebe8a9b7edd78afd036f5a2736aa06502863b6865d131b9e3542e72a86fa2e1d2db4927661ed +99e365def1452ff9fb4b9eccd36ff4154d128469ba5bd73e83ae457ab53977cf6fc04a5d05bdcde357ab539e34bd9fe0 +b4f2bfb95abb47c67870aa6ca38ac8f3ae1b1a2bed064b1be7ff90865ea12e4930fcf66429c7ecd1183fae4a01539386 +ae4bde87f36b912e92398bf72e11d5389e93b2de1b277d7ed4b6fb5a9ab9f71a959ec3bcb734c11079440fe42b86fafd +b826459e568efdeeb66688482b67ef5020787275123fd3192f979b6175e3b0ed59e17cb734a0a052bf13f0afc7bd237c +a99dd735f4a7c85cb23dcc7f4835f9ab32026886909aaa95876b98029c37dc4d621726c872d3a9e50403443c958f4029 +99083545034768010988bf8a9f34486c2cd9da27a1d10db3ab86eb69a1dd9c8ee723e7da4ef2aced63c1dbd53ccc52cb +8ac3209349f0142546c714ef7e9d1b094aab5469b8f080c0a37cb0362da5349e108760f272fbba770aa468e48d9a34c4 +af5f48ed74b21e3f2c1430192adb4b804dc873cd7e8f07130c556c30e7b78df0ef5a14b205368848fa9185e5a68dee0d +b8b741b65d68df89443523ba74203226f1e0d13bab073d183662d124e83e76cd318b2bfff09879c04d81b577ac895638 +914abe4282d11176d4f2f08c6f15e6c2d0cde1ab4de00bbe888015c205f51929d97296a0a8d3ca5641f085a29ea89505 +83ec306b2a9a6780efafe799df90b1aebdbff7d47921a136ea8a5648b9708a97231245a1082fea38e47ecafbbe000528 +95d6b58d70b388dfcee4eda0c9805362ccfb60a87603add565b175b2c14ed92999dfdb0d3724ee3e5d30535f282641e9 +97eeb4de607c8306e1d4e494f0d5db126d53fd04983ab5674ec5996b971899e734fa4011f2c889da21154ea1e76dbd2f +84ff21977fbd873ea06bec444d4ec9ff0e3902edc29dfa25f3bed269b3709e3116e99dc06cc3e77f53c53b736bf8fc29 +8ecf483874a040a4a1c293af145094fedf203a5eb37c3e165857e108cce3e1210e0bfc0f26f4ae5e2194024929ba034d +97d9b92b2ef34609d69402167f81bce225ed3a95718a3b403f702b93e96a121a8f7f072d0ff47e8b25164e204d1576bf +ab87c39cca1803b4e84b32e40ff30289e3cbbcfbe16a70f9e025643824752359be1f10c3e5398df402b6fec64d5a3537 +af84ca57e6944332884b5c84750afe0d5950015e127acec161853d55d48fd864c7da8d59cc5aba4ceceac650b813fcc0 +b1d23d98edbe7089ce0a8432e0eb3b427c350fb4bb39eb2aca3c2bef68c432078cb9b4b2c4966255e00e734fa616638b +8e2b5252e0ea96d40835ebfb5693af49946509975682d68651396d6bb1463f09e75fd0afa04ccea49893b5b9c3e77e40 +8db25e762f1d4a89a9a1cbc61c01698e775906bc88a921b2905735457a35df9ab84bae12e1b1b8dafadd50212f1acda1 +b5f7cd163a801770a4034e2b837e00191b0ac63a2b91032ae9a99ec182d748798df48a14644935fabdbac9a43a26749a +998e7232e5906843d6272d4e04f3f00ca41a57e6dcc393c68b5b5899e6d3f23001913a24383ed00955d5ec823dbd3844 +ab2110a5174ae55ebb0a788f753597bd060ee8d6beafc5f7ce25046ea036dba939d67104bba91103d7838b50e36703d1 +a211972a4f6a0303bec6c86f5c23c0d25ab4df0ba25876cbaad66ae010b5a00aa0c5daded85e4326261a17a563508a25 +a49f53496a4041a01e07f2c2cf1e84e2ee726917bb103fd267451b9b7bb1331c0afde85a79a55409bfde27328b2a4745 +934e915c67c7fc47adeabdde49f63f04644fe234672003be2aa0a2454dc8d9288f94293478936a450f2e3f249d395b5b +b6e69e9d6808ff7f60a01b7aea6781495d7a20f5b547852d3f0af727a7434209d3015a9dd04cbe3e272918e32e345508 +b348d3462092b5c6fead7e515e09611438db8d69650876dd3b56226e303252bbeb9e9f3b888fb911445b0c87132a1d0e +8d6510334a905efe5a32001e167f1ba06f9bc4af7ffbf11b7f7bf3c0076b5cca373d8c47e98c1ba8755bb22632bfe0e7 +a2d5200f20985dcd473d119ee97e1c0fafafa0f191185bfed9cac429cef8198d17665dac4f70342eea66e6e4a7370d58 +8dd7eb6b1841b3f33425a158d33a172b79b2dc8a01378e4174e67a1a4c8f4b887f02c7c3a8f354ed9eac718155bcdf37 +b16ca19388642f71afcd9f7007b490d82f83210ac1a989da9d4bf4c419de07af8c048cd301ec7e01b9d06abda7c169d5 +93cb2d847d1a88de8c1c9d5b3c83efd0b7afb3682942bd2c8ab5ef35b33dc31a097a3e181daab8630d4e840b677216dc +a8b648c769e77a7b41c0c689fe2fba9bc585067e004bcb1732cb7b1618e97b317781c36c23a00680fc780b58c301a789 +918c321100d57712866bdae84edf7e42df30a32853af257e0cb4da028842a43b49e775f3cecb85cd817269c728de7319 +a7b0f6ce42e00c519e69b2c78fd9b75a2e7103e5892d3c1afd70c9b5b9e706180a4bf73dbb2d3eed52bfd521103ec5b3 +90041994af3322b010891356afd8115340bd7fd7ba328716fbc4fe458236c8cad8c7564ae473d6091ec3a54bdab524c0 +acb1ac83809573846231f9be2dc5f3e986cc36dd9574a620b1cced45bad0b11ea957ce8c6cbf964a0af916781c574f05 +ac54677dc002698fc4d454c7beb862ad085d0514f92576f3485a44c0cb47afb9db2c085058918a3508f9b3de0137d97c +8dea56e1bfa150e442f8484b2952b116781d08cfa3072d08657cc09b0217276efc4ab6f5fd726bfd826f6976ced8da29 +a2b09e25baf01d4364b5205fa0c4dea84ef8fe03709113b034f88a0f0a502a81bf92c1d4641e2ac9f3a6f4203d3645ee +b95fe37aa351b4292691a9c2e547224c37ec2751a31ecce59810cb2ae0993da6fbe5efe0ab82f164462fa3764b6eb20f +a3498947e91a3a540e86940be664fc82f1e83ff41a0d95eb84b925e820602a41b7393c8b458bd4ebbe574a754586787a +aa2516d3620c832e5728fefdb1af0be30c871cbad4b166a7a4565af676e73bddc2f2f51acc603b3a022056daad2b330e +a9251b56467fb55f64c70729e2ec77a59d7eac79cc0b4b25ee405ac02aea46bf1cbc858bc773934a6d9bea57cb528185 +ae8c0a4ca7ba6bdca8764bac98df0581f00358db904e57867e6ffdf15542e55f7bad2dedac152ef88038b466ed901934 +b0881e27e52cc6a57c4f3f278dffc7f63a9174b68bc867c16d8a151d9cc4d0aeb703d1074d1927faa9ffb43e10912c9a +b67138465d6654ded486d18e682f11a238d6a65d90f23d6b13eb6a1b7471efbac9ada6345dfb13e5432196d2a256829a +944c69a6f1126edd38f6eef60b8a5bd17147ab511e44e8e0a442e87244d8f35236ee0b8d3dac0631f8598f16486a5f74 +995679dbe03dec775da26708cb9200dabcad983825f1ba601eb9395f9da350ca71e8af61dbff4c668fd0eebac7e4e356 +89de362f02dc14de6995d43cdea3c854a0986c605ba5eb5dacf24e3a85983229bc99a2fcf50aba3df59f0fb20daffe29 +84607f0e2d078df22d0866285614f5d78cf7697c94a7d1b5e02b770101ceecbfd53806b377b124a7320d9fed65000b97 +93e3faab60050dac76ab44a29bcd521813e76ec8e4ae22712d77bb489bb49f98f9087acfd6a77016a09a42ddedab2d73 +b7d64a7a35f21747b8e6a874be31ba770c0d13cbd41448411994e8cebb59591295a26bacbf74ee91e248a5b111aacca0 +8dcad429a2b0d66b9eb8c1c3924d7a72979727db6a535526a3518bed2a9532d12aad1c5a778824ca4cb98e3e513f85f8 +980882895faa347bd2fd1dda7b8ee7ed49e69843afe646f677b371eecc7a10e0f4e40bb55f28995a40080df471876816 +89e8e7fb51df79971e2f7bf65783614abbb0d7f3f1b4a15d3f0d160deafa7ed1c446d9a5ae1a77160d4dd94ceed8af13 +93fda8d350392e9c4d4ffe6534f7e7be53f32483d9319093e8436fbb8166a3c01085dc858373e65c7f4d014e0dc2bab7 +897521a87b7ebf7152de5260c0875e3c7df1c53e734c672569219ee6f9bd196c5ecef159b6a1d3b7cd95e91b9b8803ff +b59affa408a0f7bd7930fa3b88750fd043ce672c10a3adeba95a12f23f0dda1793f761a86f7409ce1e6fd3b3b7195381 +b4422ccc12f4fe99c530cda610053af9ffe635b633d52492fd81271d1f6f91b87171d572d5bd0e46ff63e221fb2fc4a5 +a4542cdf3346ee0867c08d630c2aefc57442f1c05c0eba52d223bfdca5e9d0bb80775cff6ce2e28aa2730231fd7b1bb1 +a7d297bb09118b914d286e5d1e87bdf13f7d174b988e38fb5427902e8e8c674072f36b19055a1070abcf357f8668f35b +9213b0ae24b7cb43ae95e25c09fead8bdbac55141694137d67eb5eab5e90a348a13d4d4d2cbc6436fc4f4f9f7334ced2 +8aed71a0d116d832a372b42a0bb92a1980f3edf8189bdbaed7cde89fc0418b3ab21a04f5c6e1d3b8edf73f1f62bd6b15 +a6c47d77d714c285c84c6b9458cbec5e3b191c0502dffd10ce049cf1ea27ddf868ef0cff13a2377289fa6c932b8e4f28 +92f45622ec02483f2c1e07075a6695416d3768c8984856f284f40734346d56cb5b3322f20c2c9f0ef8e58ddc294a309a +af6450d02b79ac9fc79f35655b58fd3619cd5d38c5317564b453f5f2d79d7a030bf767e399fe01b658a72fbd2cac2356 +a3c01fed5240eb8a61ffa8ff4a120dbcebb53b8e19845949c77fb4f9b2c3dd52c7001df6219ad2f76c785a4ee0f64a2a +af3136bfe8f774187bdf87555a1ac505322a956229a285d28bab1c88d4f4d12245af8dff35914a62e90e49f3dce6acb0 +b20e21d28444fc96737958cd951858fda324b924b4d3d08932540fd4b87150f053db6985b96903906ce83dde0578cbb2 +b7978101071268d1f485134b4dfd1e35f89b82c7d99ae91f58b6745f5e0273b7e06f3b23009033ecc3e41b2e9e85219b +9104b7d75245b784187175912cc0ad869e12f1983b98e052710fb33663224362bffd69ceed43e7d4ad7f998c0a699eb7 +a7624cd71b92699ce3fde0e747976ee04ee820032ac45dd27d769edf3b3379a4b8db358e50c9d057c63b5a9b13d76bcd +9354a76f294005de8c59db10e638ae6e8c6d6b86a699d8da93143da8478d36116211c788d8285d8e01ea6647dfcaa1aa +b85935c04cae14af9848db5339ab6420122c041075ec1549314e3c9c5a610d9b794ea3617c50ca7af6b4aec8b06bc7dd +ad6835a62311c84b30ce90e86c91c0f31c4a44bf0a1db65bf331b7cf530cca0488efaac009ab9ed14c1d487da9e88feb +80339f0245cc37a42bd14cd58d2a8d50c554364d3a8485d0520ea6d2c83db3597bf51a858b10c838bfc8b6bc35619638 +b370420ac1a011f6d8f930511b788708ccf2fe23ca7b775b65faa5f5a15c112a4667ed6496ae452baf2204e9ce0dbf09 +8ceab3dadca807a1c8de58ac5788313419c37bc89603692c7a4d96e2311b7fe9e813cc691a7e25a242828cdf98f8bbcd +ac1526ebc6bd4ac92ee1b239f915e494d0279fbd065e4cab1f1b8a1663f67daa89560f6c99bbc3e63fa845520316d2e6 +8240ab0bc36a29d43ec3059c7e6355ff39567e135f93b243145d3ada97fd1c970743819e0d58bd5171967daec144e7a1 +a99743192a6f1967511b2d3038cc73edacb7e85f84b2926d8880d932d2fa12f5215592311a7548494b68a87ec70c93eb +8ffffc31c235997e59ab33c2f79f468399eb52b776fd7968f37a73e41949111957434f2c0a27645ab34c741eb627cd1f +8949d955309415d6d2cf6ee682ccd0427565142c1bfe43b17c38de05cd7185c48549a35b67665a0380f51aef10b62a8e +9614f727a9dac8ecd22b5b81b6e14d34f516db23a1a7d81771ddaa11f516ed04d4e78b78fda5dc9c276a55372f44c4d4 +aa85d3ef157407bd8aa74032f66bc375fddaff90c612470b5ff5d93659f8c3523b2d1b6937b3cc4201c2aa339621180e +86f8fe8bf4c262dc6a04620a848e3844f5e39a2e1700c960f20ee66d4a559a90141ef4e5091d0f32acb1e915af1e0472 +b3af2eb785b00588371beb3b49536b7919a3f2175d4817de5dcbf7fcc20c512852ef0f313327fd0589b10173f77b92e0 +8388703c512eea59190351f3bd2cce83ff8bcb3c5aefc114cccf9e9b3f78200d8034c3ebe60448aaf6c912f0ff8f0cc4 +95d0dbbbf08ec1ed3975fe7dd542be0a05156a2b3db5092825d918a849411ee536ed958201f74a5513e9743674d6658d +8d1a48802f1a2db247e633ddf61d3ef7a2c062c48dda59bf858916e04f56651a7d51e367d6535964ebf3ae6d2b21b421 +971436871bfe868f25247145a55802945409b3150008535b372c949760d7949dd2fdb40d9b96ae7473bc8f6e9b83ecdb +8ca431728ac0f156763090828a7b6d860bf591e5b9dd3bb3b7f3ba0ca74191f9710ee55efd32db7d18eab5b479cee8a4 +81e28f1a506e84c2b9aba1df720cb50e0b597b2c22f98acc34e710c934cc6f97dcaf33d589e845c2c1f6d8716d05ccac +8f43b11d3f00c41d16c9bc9bc0c44227c056bd77de4f1ca9a799418c5601e744f99066bef47da2d9088ae88eb259327c +8d330aa52744c08ef98cc5599eec8b9b4dd18aa01b803f1d1ca0e29b74f1aa2886ed0224390fc377af25852851fbee03 +a06f5b203b67134c685039ec2bdbcc787353e2575ce73a415db24a517c0c31b59d1de89f12b97cbef0219fb6a1e90a20 +9269a5f49bbb8fec1a387b5d105df88a027de615d5ca6afae20fe89b11746f8d23880db78dac238c955fc8bb3de18046 +af5074b3bc0656421c314547b45b5abd3045ca1b17f5e34ba39d8c1f7928a55d4ca5ea9c2ab59a55909b25255233e04e +8e7ee5d733c8e08f3fb7d85f0628de3de6835121672c65374905dc6d19e02fa2df14c13d5e9835dacd609a4df09abd26 +a9b9aaf83d31e879dfb8e73a0708801b4dbdb5d7c8654b27d2c0f5797ebcacc8d00a82143e2060f0917c9d41f1a03de6 +904872aa1c093cb00e1c8e369a3bdae6931c5b1ed705dd3bffba243dc4f42df3e7d7cf70303d513b34d2245743d765cf +8a4d6b3b1d6afe67383c66693f70b397e510be28e3d97dbc8ec543d699b6cbb0e72eb90a7f65e83cf9f7ef50fb18b128 +a914de13916e6a0dc0e0fefecb3a443cca80d83276513b70c22c6e566a2d41acbd33a0e2836ee09abeffd3a4894e437e +b9c408f5f05934b0aefab301ba22f8254c5ebbf5405b6aa788f76e4b328c150b395f441e3566015a0deb3eca89afe9ff +8d32aa2c81b2a8b89f347c2e0b6567b2117ddbb778fda8a3f19004b7f5aa9dd814b9b3ad35f9223715d2447b2d12f159 +8230e8b9c84cada1bf14ea6aa9ecdadd978d893cf5962fee6c7167ed21239210ea491987f2c8f2e8cfea8c140704ca28 +a5d7b6285fea51c6f21d0976a7c3a97baa3d733a201bfaac0994db6c65611d91c5fc0ebc2a7724ee02b371e575573649 +a54f00a9530f6930069f5e3a8b8b1d52ee1def0aad1763e3c609ec07f25410969b43d5943a94c235ed5eb207b33a402e +a8dc6e96399b81397734c61c3a8154e55a670fa25fa5854b3c66734cbb4ec0d8f6ba650ee3c71da3773ffc9e37abf8bd +8841fbfae1af4d400d49f74495f864804f043416c09c64705251d021b3ab7881f134a00b0241e61010617d04979d747d +95acea7ff4861cc969c1d8cc8775c5eae014ad6e2e0e2d0a911dd916c34ae69f53eef779cc24ff1eac18c2b478d3ba2b +a5dce74abcfb8c68031b47364bd9baf71a91db01e45514ab6216f5eb582ef8fe9b06aaa02f17be8b93392d9b19ab9c06 +89e111169e4ae2f4016c07c574a3bdacd8d2f359561fbbdaa3474de9bc24ef8936784dfe6fe0e29a13cac85a3e622b61 +a4c511af6bdf3892939aab651828259e4ef6ebecfdd503ecc14e61001575b313a89e209cb55a77ec19a64d29ada066ef +923c62156fbf3a44926ffb5dc71f7cef602dbe941a98c61f019a27a18a50c16b6135b6099fe04a2e1dc88a6cad989fb7 +afb9191c541b61afa0ef14652e563cc5a557842ce2afea13e21507dde0ebbe6da5233af949c998c00865c79bb3d45ec8 +8a1f0ad65cb2b225931f41dc53547d756111ecbf5bc57c5ee2cc1ffd61b126d0389d311ffe26cf06eaead95af09c5ca3 +9040b20b5ac2e1a9d30abf7a4eea1ec2db8f3077cb2cfc8736b37222d8d3937f5d9f421167086dc5551e9f0bd2522d07 +b6d888b8c6bd448dccaf99c3f690d47f802e134709ce102fb6f6fc68156943c0762be6f386338163e01eed2d1dd5f734 +b94f0e27bbcda793e4a272603b3dcc739d3bf3207798df7319f8dc9d37cbd850e3724bdd30498c929debad971950223c +9769827767be9d7bacba1b687289e0794c6fe630d33c9b607da1f6a65e3f34cb8bd65327d9287c8c5f3c8b5f6d3d133e +aaac72c993aa2356c9a6a030950441de42b2d746bace29865382f0ef54835bc96958b2f00237d805ee6a69ca82117c1b +a2b1f027d80c1b0e79bfc7dd252e095b436fba23a97a1b2b16cdd39fd39a49e06a1ca9a1345c4dbb3d601ffa99f42bdc +b3fa0ad1478ca571e8aa230921f95d81aed7eca00275a51b33aadabd5cb9c530030691d1242a6ff24e2d4cfd72a47203 +a43ed4368e78daad51b9bf1a685b1e1bfe05bed7340d4a00df718133f686690c99198b60031513328fc353c6825a5f2f +965e145711ecf998b01a18843cbb8db6b91ff46f668229281d4ca52236c4d40804ebc54276e9c168d2a2bfc299bcf397 +ae18e6efc6f54c1d9230210ac859c2f19180f31d2e37a94da2983a4264dbb58ad328ab3cbc6884ce4637c8c2390f7fc1 +83a9200486d4d85f5671643b6daf3d0290b2e41520fb7ea7030e7e342d7789023da6a293a3984308b27eb55f879ad99d +b925fb6ca83479355a44abbcdf182bfac8a3c7cce6cfc7962be277ce34460eb837c561257569be3cb28023208dea80dd +9583dd991b62ae4bd5f379ccd3cec72cfae1c08137ddfbacc659a9641e7d5a82083de60005f74fc807bd2acd218d0789 +ae73bc32e9ff5926e1e06c07a3963080881b976c9875777f8e4cf96af91bf41bdbed4bd77e91253b8ec3c15b4a6d3977 +b2a3ea90aa398717ba7d8c46743e4c487b63c5abb140555d8d20e5115df2f70d3c84a2cb9a5e0536b2d93d24f271b38d +91d119d3bf1d34cd839eb69c6de998b78482ab66bc93fa97e31fb9592f36cdfcd673f52366f8c8e8877e313b92d4a2ad +a1907e20120902cf68912cc3046f8806cabbd7673e80218814cb088e080dd93b5dccba395b13e0025f5755c183276c3a +b2e2011df72504065ec4c12cbc2137b95cfcd1355509671feb7b00dbf7f8d500476a49754cb7fb9219cb5cba7c8afe01 +a48589fb7a74a3dfd782cb3503e6294a81dbb6adb412887569f9408e9079371edbd9822388e0b7ec8d3297ba270f53ef +a203909bfe196ac65ed3e6800d577b6ca5c8fe1d40f7f925a43852951e38883f2ffd250a9e16fab3ed3dc1249650247b +997ac293722a8b98f7e819f8e6c2d4c5bd1103b82d489d8b8aabeb905e95450b9b75bd61442cf68cc957212ec1c55617 +9895a3de62395c33509b153b7820bd94fd2b011f0cac135fcf916482f1eda272ecc79f83a61837e99c3a3c4ab2c5c2a2 +98c2ece4d49a64ec8e06407a0585081003bcef88af35210e22eab91169f8f0c044d611494b755e5bd915804b1d857747 +8bc6dd083b36d076ddf0e0bb1bb87cfd059283ddabb3886f02eb7e27f1f0539b2819527b56b5c13436523c4603ac1d12 +85ab8b7a696333c82dd5e179e12b2e127e67d911de609ff9a03cab95cbeedb1f364aa1f2b5e59353e4ba0d177f996151 +a9478e214afa68c395aa2c7daf8ba1627feb71ad6d8bc7339734cdcdd5a42838e032736c28e6251c808d5a4875ef0d06 +8c53f62cf06a35321c8af3871ee4459768d0745ebf48942b9f464206309f42fc7b2c50f196ae1e43b664f0e2e718a23a +8ba80662f6642d8866e832ec8082a4204ebc993fc304c4b794666856de0407620131a18dc053597bb40a3de0bf8aca22 +8c8fac6b911785d1561a985580c03fb2ebc613ae33e486a92638aa7d4493374118d9a6d9d99121e29c68c3d67ee4e3f3 +90f2c793eee07ad90157040b30558bb3b0164e8ddf856389d6742cf5bd1c712e4c6a8e5678da70a8e9e242ec7864117e +954abed8f6d58896b7f6438c9780236c1c83b02d60a29fa7361559e619e5bc9d67b3646ee39ffafe2b3019bb3357fb50 +b79874f757a33085e1e751544de8fe3afbea92e0234f9c00254c2b36115a16ee46f085f22aa66e0c9177e5106f51b03b +aa148b287cf4f60c64f774282b421aae075f0eaa93a45aab4927750f47e2ef0b811d1846bbb15eeb2f293c80a7612e83 +a588d8825e7b0168d45499dcff6faf0dfe1ba4f090fdc7c06d50344960c0121f10ad109b0b9d13b06ef22de5a04eef87 +8f61ec93d14ebfa9c31731f9ef0fb8907505fedc79378e9a3f65c27bed4d74b41e129c97672ce5f567d897befbceec8c +a008218633f1da10efd01c155f7ed739faec902da6dc48e9f19ccbc8d32bb318d71806285cf2003de2c907bbdd4f8b22 +88ad82c66f7085632d7e348d69da84200c53594553acf5432b50dd1e87f410c802dfea91be3cf804e3117ce13103f23e +8498dba17de0318af227a3f9ed86df37a5c33f9a538be9823f8dce4efc3579e8296cb3b7200cee7c5e0bfd9da23a4b69 +b3c0342231dffe4c9bc7d9265597bc8cc4a82e2980ac6d1407108db5b00349dc91d5116fab51cf2802d58f05f653861d +b3f2730455f9bf5a058598bc60f47740117ba51f6a767e1134516a4e42338b513f377027acf8825da5c4d047a62984fd +816360914fbc9d8b865157bfab07aeb7b90bb5a7c5cd64847b1c3184a52266cd3f8f8f3ef99309ba2edc4622304bacc0 +8fd21b2315b44a52d60b39ebc45970a47b9495f42b88217ae057bebcd3ea0e2476c0c3d13de7f72016ae12ae966a008d +b62014485bc217a0fe892ef1aef0e59604ad5a868face7a93f77a70ba3d7413443fbe7a44552a784d8eae1acb1d1c52b +a905822507e431b35f56724f6c8d2e93b0607ed7a4533073a99cce2b7c1c35367382447073a53036dfdb0d04978ccf2a +81672e39c2b31845142963351de3d9cd04c67c806fdfe77467867463dbbd8a9b0e2400ccc55016e57cbedb02d83a0544 +90919c970ec668de8ec48a2a73bb75cb94f0f8380c79a7909fd8084df61ecd631476ddd474b27103c6817c8f3f260db9 +8fbe37dfb04bf1d3029f8070fd988fc5e4b585e61eab6a8b66caf0ffef979d3ed6a662cd99468ce98ec802e985da5fad +950939aabb90b57a3d667f9820880eb0c4fee5c27fe211ce8ecd34663c21b5543c810b3676111d079ac98644c75ee0ae +b06201ec3c3cfdaf864a66af128effee8ec42d25f1e173c1edf9207979fa52c871757000c591d71a9b6cde40f5001a06 +a79054e8febd0450c96ac7a5fd6bf419c4b17a5926f3bc23a8616f0cfbc2849d97470174cd1baa7c739b12615334b6b7 +81c7391b2a1844ed26a84f054b5f03865b442b7a8d614cd44805b5705fe6a356ac182b66a3c8d415132e389efac5f6b2 +825af1563d0fe53925ec9ac0df65d8211b333474e59359bf1bde8861eecd03f2ac74534d34b7e61031227c2fa7a74e1e +b60dd9bf036f1825295cd2014ef1f6d520cf729b4d6cee0b42cb871b60ae539b27c83aa3f96ee3d490ec27ce7e915115 +89ca43d5b7f3622b42df7887572297a7f52d5204d85e2e1ac6e5d7aa7f8aaea5e3a07280477d910db025d17cd2e7373b +b93a2bc9b1b597f0e514fde76ce5bfb6e61eee39cbf1971ea6db38c3ecb055e7913ec8cd07fb0b0ffae3ca345883101c +8d45546bc30266b20c6c59fc4339eb633155aa58f115a8f976d13789eaae20a95b064fedead247c46665cc13ba856663 +aa8eacfe00e8a4d9815de3f7619d9c420629ada6489933ca66a571bf6c044d08b391e0d9eec7d1cbebe8def1e7523f1e +b32fefc59a0d0319ccb1946b351ed70445d78d9fbb536fa710d3162b9659f10288f12d82b32ecc026d55f16cbad55441 +99c7c45c34044c056b24e8f57123ba5e2c2c039e9f038a66899362840cffe021733e078866a8708504cdc35816cb335d +80def162c134540d5ec071b25ccc3eef4efe158be453af41a310b7916c49ec0ce06bb43dfee96b6d77339e11587de448 +b5f2fa4f68f6a26bcb70d8eab62ad73509c08ee7aa622a14b3d16973ffff508ce6f1aff9ced77b8dcfef7319245cf2de +b4d0436019e779c789464716e1741c189e8945dab7f3072720bd9aa89882fa5b085a1755c48da21541f3cd70a41b0a71 +931e798ef672e1472f4f84c727a101e70d77b3a9f0c0803a5220958d6bbeb8aeeb56c769ab472a3d6451249a13a3f56e +918c10a84de268aa8f1ba24b38fe55ff907be07b1e86b4a4adbf305c0d705c1cf5f65ce99e03e11676cedc89f1a4f331 +8e55a8413b823715ccd92daee357cedd797e69a0e78b6fcdacb7318646b9903dfe05e5501f47b3c52e74055b9eb619a4 +8b329bb63e6c985d7d072dff4680b3f8b1217ed20543277386bd30ec25240d9dc378837dcd5cf4fd9548658635f4c537 +8c2be5386052b22986b33dbc63c5afacb6d0095495564ba4aa28fc8c880a3c78242fb083248d788ed928deb1e30a82c2 +83a2b7bdfcbd25d6b059f27218e009ecb5ecc4da68ead885e00216411d8222062ca42f21c4d9cfa19c31522080af677b +9620334d2633e85646b2e2fc48dc6c3f09c64ef1706ed78a3bb6ce1f6b274a727364df71e97531dfdcb392f70f27f536 +b6c84970ec04545121ec3b79376f4e45053c97e8bf2b11922cc2490a429c38735466097ecb81cc9d9692c74d2fb8abc8 +8e55d707dcf265c5ae29a32c27ce66f200fddb724faa5bbf145ef42280ef645fa2f0cc3cfe2db8599b26c83b91e077df +b910b96b763966402bbebd68a32c15a225ec21e1357fa298478c5981a4310e556103fef0c73bd8903e11c4ed2c065647 +a8fd933a0e9fe8c459809bd93b8ce153e2af55df94b61a1490736b19c89469954da8b72dbd072d798fc06fc3d7a3d60a +811b279c113828e114fd82c2070caa7eb089a46c8cabf865f9c77354a77ebebe0c4c6400dda0e66dd017cfc44d76851d +8ed03e91c331afb3ad6e42767e1b3e8d3a35fb831805ff1b5fd3e91878e04027ff5af1165a3ac295f1578faf2c83b581 +95bf53683d64a0621bf1ca6ee17446783f6c535b7a54d6ea57723487a215759a54f886597a55dfdd560424e368ab2759 +a9bea378768fb1d7ba365a16531c51fc1975f1c73caf2a0891da28509805fa84e2a8db7c6ccfbc620e9002317abf174c +b8308250891015deaf851c4e5a4cf4704d104f94064418488d7e3076d49f36240dcf6fdcf83f45fe8a1d97fb02e3db59 +adcda6b63da21f4074f142f8e7f3a2274f624c733e3a4001054a1809711529c61356aa087f73aed877a58ccb41d38d12 +b80e7869239ae26d1da2e6683f064d1dc93cf4a2b66e9439b3ad9b25324e969bf98014760d29e6b8de7ff152ef498d0f +8e9bf968911df3bb5e3a7655e9d8143e91ee87f14464d7ba9c86e1e31b03ab31b91eda121281b79cd974d9ed2657e33e +9007277e8335a43e6bc3c2f5f98c0ba7024a679b7156aeefe964f1a962e5ac82154ac39d1ffbad85a8f2440f3c1e354b +9422b9d670e997b7c919a429499f38e863c69c6a4d2bb28d85e36ae0895c620f68b71e39eba785e3d39a45be91507757 +926094e01132938000d82dd9a571fef5ef104cd25b4015a25e3442af0329e585aaad5472f0e7a69899ba2d6f734b40aa +95552d8057f7e32c24d69e4d6c51c98403f198a20c5be8826254d19cab2f84d5758e2220cea7e38b7c8a7a23178fd564 +8abcf8dcc8488bcc9ab23c51b9e7a0d91dfc7bebe88b7ed370ee68eceba643e939c5eae66a4aa5fe85120751780e351c +a91bf8198f029e6a4cf6f0cc39b629e9aeff1c77b8739e1d5c73d8c1d3fb5c8f6f23e27b435bf10b5b4ec1cf6a7249ed +b932d87ee3a4b81341511f90fe5aa36c571e8b914f25abcc33dd40ca67a3f6444fe9362c1434744e4af18d6e045c54a3 +a8e960c2be9b1d805d387b3ebe2134d421a65f1fd4c1b4cccdce78f9926f139eea78e3afb449b3d6dd19b5d16ace48fe +a7e2f57cce509fe66707eaba9b4c042c1be93fd6034a9b51d1d30c45c4363eac79d54663d525c9873ab0eec0b1cc4ed3 +aa162a31c2078f4b080199debf24494a8dfdfb9d8fc85b198a861b12a629c73128c55a883e4c2de3dfed6e0e1b83eeab +b5a4d075433eaf4115717a84b4dc37f843d44bba0bf820c92ecdedd5afb61be60f7708c8a151a678d9d5c0ae531bffb7 +b56ab96f7a463c0079e05dc766f3a6a31cae5c5044947734ebe0a26e01367c6763cc8de6c2ee2f3b8218f05bef217474 +b60792ac506b901065a8bc0180a86e028fe34b62ceae1ad640c759538ebf3a2ad9c8c927d662deed6f489ff3ff7813c4 +8c8c2cdf075504d12d441a58542e1f8e4bdf92b3ee4775e836b2734c5ec1e3df919b931386417d04489a1dca806c87d2 +8ed78e91e5c4a68894cefc2f7fa71f02e5e12d40f1bb74332139bc7be4d92c24e07d5ece0e82150ed474aa1337af4c18 +87119c22ff8aa31150bde537d863cad661cc5159b12f084cc319224c533f0deb28526ed8568d00a1441e7d8bb4f05673 +83a60ba5a9cccf22cebadf7318b706c9f29abd25db0e2fc1c802965351b53cbf316df72ee3e9b2d3ae7f3c4494cfdff1 +b73b6a9fdd3e7463fbdaabc9a885b7c82201ad867d1bced1c2484300a01cbbb3f1e21afa95d4c7cbb6cb983416b63b90 +b1d89ad16981ff9217708090d4017662d8838f21f3a3296cffe14590b533905fa06a20e40dd497bd291fa4dfd1bfc511 +8abde560083e071a402e3c7bf31930f537f67d2a7bbc734a7480b1b760aa712ebd1cbcb65b00e11e384e980222fe14a9 +89c731d8f31afea8bdc9c32527bdca257f2a840764d40f6e49403b8e75ae51017d505ea4fff91bf28b6f3a1bc65b8bbc +80e9ac8e077e86ad050ee73dfce268a69564ff1b8419e9c236d981fe7a5f0c2bc756e8603ec604b3b9e36da8fe10a49c +b4f1eea0f304898b1323c6382732e6f40e556bfc68af9ce73f6d54e92f5f23cc4f78eb3f43d578d81e7627fb40f092b3 +a0e3a8d1348f8f153e08ac4839232d75d1d6e81b5de184ec4724f8213baf98d3fe739a96f6b39d79a053b628c3a09981 +a6915ba0b52ffe4a381bbb8ff3791d9d3b848bf89b3bacbb2a7d2e5ae21f1353cdc304b3cb6e82416f7e604035c27d7e +b2c4c9cdfdd2fc9a340ba3ade9423344b9f429e8c7e20a8abbf26400376e312f3ae35d1c456be99dfb5c02fc8a36cbfa +9657d57ca0641825a0aa5687f3f87659d893f33aee819bafa5b1ca1db554811c1c844f971e278606e3a2f096defdc67c +a4ad24d0a557704ada24d8e27a15604bca28679e260b2c69ccc8e6cae5499866724b700605a90df7dfb35130756939b9 +b18d9ea6682f73a1f99a9a4fc98c38fcda02c1a18e8c5fc080cf935a2ac877dc5223fca273dcde190b906178d0fd05bc +8ea5fefad0799c885f50ff10d94bd0af5b99b0a446cd1f367ae5ff529cc47e09f3018115f3c0ccac2fa05bb65b84945e +92450d52e6c7d13ebfcdf5674d6761bbae2fc5aabc865d35d031b588c383e0a64cf69a73dc93948632e2b98f74a5ed86 +a356f171a98df4ec5a96d556eaccc6ad34b4238aafcf0e94ece27cdbb491749fc9692e78b84dfe80bdef2914079d34b5 +b918703a4d3507d266414712ba8eb7ad17da07cc5f952b5c62ef130cc6ed1ae3bf01237fc8848c179725bdddd465b301 +ad2b0554570bfc9d97510cf59bc38e10ca54a93649c30ac9919bd0255e43bf525ab11b74f78a51ac0973cd0c5a5dcb54 +a7ecaf4b631d179d32ac1632390d95196a0035e00da6c0e6e13b5c09ae44b15ae6c21538b5a31b73bc5f650ecd979b59 +a37704eb4d728df2a367e59fcb6c26023136230e37f3b8a2f3ceeb1467f5cd30186fc0116f98b64a8146fd2c5903e8d9 +b09373ce92314678299ae10ec1f93c702911beb4115c6b5ba6efbcab9c7afb599f59793912df70a98868bce6545a33dd +b52a878a1393094fd2b93f2d1eccabf2830ab10800ba4cc24dcc7849cd0978733263aef2fcb766a7cb575a7a99383db8 +8dac097e006fda4fb9d6d7ae52adabd9448ebc8d5bd5b38ac0c4ed38ceb510763174f7adfb0b473c38e52147ccab4239 +86b19c41efb949937d74a7875549ee5e997f9fdac7f7198085afda233cf74341a38d0ca3767c76cd35f875b89a35f78c +99f0d927e5ad25cd134f1c70b72631cc6b5cb4ddb86c0642b900464e33d971213a5239dddaf71f7a42f2d6d02a12dcc6 +8355c38806c335d747d4e97f0083fb96585677da18b409a85175ec35dc3f74671817b34203eb18c2f729717ce083ede8 +abb3603adb061a036eae0afa5f23d79c3b62442e0e3bcdeef896f88995585c1105cd3065410368456a4d36b5b0485a83 +9051c5c0011784885187d04749f774b9b4f6bc594b0e4e18226de79dedc4d7aefa3529c3d2c728e180f96f3e204d578b +91888213e7d321d0bfac884edbd5cb756b280753bb5f8bc6acfc208f525757beca24bdf86fc68d3d8736ef176a960b49 +91258bd7ce6e3b7516fe2f5391a368d826da299e0e99b1f82eaa44b62b110ab696adc92debab8ba098a52f38dfb3c5d8 +96e3907340dffa9da3602d3b94bacff7e1bb8649edd3b9bbd06e1bc6781e78f91ababab12c0b9be7c66dfedc7001b66e +9513555688fcfb12ba63952ab36a67b36affdd71f7b843e8eb99ccbd45421698024608233efbdc905eaeb26b334b33af +9913ca9bcf11eeb408da02e4317c5ca0010fb2f4490b282ddb758001c08b438c3b35351a8cbe10b7fffc1293ccd22d4b +85dc2471860ebca88e5a2766161fdd77f926d2a34825d1134a30418f91a741759668e32fd1e37c415d07ab5824338e8a +8b128917e828a0b5eb6fa8ed72b52fae2dfaf74febee69a2e2f87e8df702f0c5bc0fb620c8d1d2a07f35a15ec9c0f5a8 +964c39e7840c130b01bb481ae7bfc92682b0f124c9c383f9dbf3027f2249151925f4faf36905af476a54778d69da3f48 +80671ece658cf850e522d46d25678f934ce6df043f25f8707235125765d40c2eaaf39eda6092f75039b22cb58bf2c29d +ad4bb0e79fdaa340b1347a46b0f64e801c72a89770dda0a6e4bfd35f2df5146fce9934e4baecb1c2671077c771eb8089 +80b3bd3adc6cf198fcd997f8867d2839a2eb28f57390352ec423b8a14cc1f2ab21c6e286505d6a21fb134dcd8d8f11cf +a26d46a6b8a75748895a1d599e7fd120d896340e79813167a400b2fe463452532a4cab419074663fe1d29fa716b76a33 +82b1f3a8a1df29207d7ff020809113ab06080a7f0c631f76ad33f47cdfb6a567143144df97b4ed7f676d929195b04bba +ad96633a3744648ff0a2e4491e8219c9c6ba6e655cb058c36320a8f72cd5f72c00bddf97083d07650ea9ddc005fc1ff4 +91d0783788626c91662359dc3ff36a8bcc6831e3f4114f85c99910256b1d8f88a8612f53c7c417d55581dea486f38926 +84edd9e87ff3d193ebb25f43474c33fe502a1e2100fd3f93fda6520f5e42214cc12e9f8045f99aa2423a0ee35e671854 +b55e06a4b1fc3ff9a5520e0b7c8b5ac11b28385cce78d91ce93b82f1bd7f7afdd4195d0c13a76e80d0ed5a4f12325fa7 +b0b15c7ddede2b81d9c835ecaa887650622e75d0d85f81b8bbec7ef24e9a31a9c9e3de1f382d8c76d878d1b01373f6c8 +b1adb47c20f29784116b80f3670182d01b17612d5d91bd6502b0dcecdcf072541f582aafc5e7dd9a765cad52151684f4 +8efd1018df9c9e9814a9c48f68c168551b999914a6719229f0c5bf0f20a288a2f5ba4a48ba966c5bffb0fbd346a4fcc6 +b34ea2bd3269a4ddb2fbf2514401d2712fc46c22642f3557e3b9c7acbce9b454dcf789573ede9aa14f39605fdd03f8c4 +a9e1428ce24eacfc460aec2e787c053327ba612f50d93510d58b2cb0f13291ca3d16358325ab3e86693fe686e4f526f7 +91eac7361af4c66f725c153da665a3c55aca9ae73ead84ca2662cf736fe6a348a301be1954723206dda4a2120202954b +a6f02db89739c686407825fa7e84000ceedb9bd943e8a0908fef6f0d35dbc33c336072ba65e33e15ecfcd5714d01c2f0 +a25666faa12e843a80365c0fef7d328a480c6e3cb7f224763c11d8cbabd0e7e91a5b647585ee905cc036afca14842bae +b4348576439cd2e48c01cb9cded7cc4a0ea364ab936dd679ddc7d58b48807e7fab070f2f1ea88595b11af4500849026a +a8c6c731e0d0464ef7e4fc1b049065eb4ce100c01e1a376365c636a0b23851022bf55805963bc15eb57434a837e81167 +b0952937b154e3a4c206f96cd96c76ba37624956b0e4d43470bdd97b4af878326b589e3eaee82fc192437123096799a2 +97d07ec31ecc9923192e48d37df2cf08750050fb452dcfbdb350fbc43e146bae3590c5b732b31ebfa1ce5d884ad5ad57 +a69359aebbfe4cbc4d39d178150039fbf284cbc0edc68a6bd635ee3a1c76569a4a575c907fff691b2a4d82a384c2945f +b321c2c0f6b5902ee9056cce7404d858da9a573d27348c1a6bfea29b2746f2aee7abcb6192504e5a583b0caeaba117d7 +a74e738aa6eb4eea58855ae6f422af22812fb388c83aacca5bd5fa4a88d4c01463174a229aea2830c348dd9ab9307854 +94306a3b106bc1644346bc45c05cdc8287811d5c86cad691bde0c65d6a686eb9c0ce79ad91baa4547e5d058ae8bf7310 +b64140fd77a07633e4ca8d60786452311dcdb8ce7095ba51dad8486f57c3bf4e69bced92603f71da992a48ad817ab275 +affe7f4310f1dc68e5e3cd640bedf864f51bfb46bb752063bfc18e95930021f784e509261ff9c560f53000c361b142d1 +b0d2fee222c6f963ba3385547f921a48964da031d737892604f8f2677d4905dbf615046db57eae6c6dd756709ae6932a +81700c66aad7c2e51168e028b0fe086dea75d3b17d93a4dc1f47a6a0f025df0bae1c8c997901837ad859a84197e7bb00 +aa4ac5fdd602f8b79cace18690e67bad557a93d00c0e295074185e8c6b4059a65495d9971685de2fc01d2171ac8b706a +a8becb3a64fdf35d65d2857898dcf8053b5057a73ab8c5bb5324af1a8015cff47efb85dc3eae7364cd5c850b7962bedf +b72ea09bd0b72f8cde3466f359ea69b194ede93dced534efba1b9ebc6f3bd53942fe2965e992e82edb6050cac4ed88dd +85bb8dd7eef023a251fb6f220af54687747f4c91983ff728163c4618ffac40ee6edc29a0aa6d455276bbe017f63757c2 +85a485254a11b4c4a943d9ec509c0dd1cbfc0ff5273a00cf5c9f0babec973efb15348e5d9451b548293d778e3a2b62a5 +b109f3ac809391e772b589c196b013db69a9b2b10ac3898feb70b986973731f30722b573cd0c9324158ec20416825385 +8a4eb579a840d438bed008644f373ea9ba2f28470d50cf1d70af38ba0e17326c948527b1719dd1bd9ac656ebd5aedd10 +a52e9d66ead5ee1e02ce6108e4ded790d8ec83164a0fa275ab1f89a32200726c8e988d66df131df9e62dd80203c13dce +b541cee9febf15d252475507e11d65c4b7819c26cf6d90352f5e8a8f5c63e254eddf22df0c35a7be5b244233e8e4ee5e +8153c297772adf4603c39349142f98cc15baeccaeae10c3230ee87d62255f6814d88d6ed208c368d2c02332426589748 +970dc9782f1828474e9fab7dcdec19aa106725465a5844caed948eef5c9e48199c1b6bc1a637ed7864116927e84bc65a +a975a920624967f4ecc77ea5d9869c434caa64c330024194615a8d0640c5d4d4fb139ea11a0c73a5c6ae6dd3fbf0ab5d +811f0f9e0c12acfb4b9dca359eaef3bed18083bad96188befc036ad3143b121fff4777ca6dc70a835bbc4921bd25f5ff +82341c6ebdb97c8b72910da95c7eebccd1308b6a92999886aab552f0642882d5c7cc60931577d200efd6066530c998dd +860f7162c2f5fd1c0953c6ce75bd8c52eaa48032b914410681b8cc05e00b64130d1f96ec5a52df66a04c78a9f9f42981 +8a578e674875571fe1a0459843495a5ee1d9fb6cd684b244feb9488f999a46f43363938cd0542879ea18ed14fba10a6e +8df217aba4da6781f0f5139aced472025523ed6e17e504511c04b677ca8197488e237d8bb5dff7b6b3898cd5a6393dd5 +b2c9230ad35d7b471d3aee6f771517cf3145ad26200bd6fe9c7cf28120e2945fed402e212d2330a692f97bb9ac4dcf12 +b78b89e29e8b782603b222cc8724eeb83b2d9d56bc02f59a3c899ab76429dc721358b07dcdaf422f59520b7e7ab4fb55 +82682a5617843c4ac8d4efb4c3ce715c76c1da2c3bab1ede387db503f3489c1bfdfc07d9231d96f955df84fd225bc81b +b0f53725cc610e78b8e8a4e6823a2ffe44dd15a9a5bc8151ab7a3787ddd97e1d7f2f0e6efd2876e5f96417157143e3bf +92c5a93233085e2b244519078770c7192af62f3562113abc8902f9d72591eacf52bd15ce78653ab9170d5067606287f8 +a43ef97dcd9b6ad288846bf31fccf78df72f94bc7ad768baf5bf0d5dfa27bd74ffcc6b6c6ed1d1f09e09be3afa5eaedf +817d43bd684a261fb30f709f7926cc4e1a31fd3a1a5e7e53ba4d664856827b340d7867e23d55617ab3514c8a26a7040d +a599e22d3286b32fafaaf79bd5b0c5b72f6bf266ec68948478f055391336d756b58f9afea0167b961fd94234989f0f02 +b70db7d8e8356df2e2070f8d658e560081442f3f3b95e20f4bf30106835d76161101163659d5d12cc0f335fb042dc66e +b8f725b70c957aa3cd6b4bef0d9647393f7c9e0b7343e92439372f0e9aa3ceddd0cb9c30be331742b87c53f2eb030593 +b2fb5e7762f26036e7e966f4454f886758804d1f4c2da17f3d13b0b67ca337f1fd89fd3cc798b07da6e05e8582c9537b +a377f944dccc300921e238ed67989872338137fe57f04cb5a913c787842e08b8a1adcfb4d2200abdc911fc1c766a7092 +b82e98a606071c2a33f2ad44e7ace6d9471d5434500de8307b5d4e0083e3a5cbc67f0609ca8055f0ea0ee7501b9ed916 +8e58f9a04d33a41ace4944615041662dc35057e645f63e127cf0d70f96ac307d33a62ce98f164d6eed8536c1a747dcbe +b5b11388071ffbf57ac47fc195736613b964ebb91cc8e2c17b32646f91d64ea506282b881897fca96c317364d3290de2 +a40ee9b7551133856cfb3904837f9949a9558e59a418898affb78adf1500fd6ef6328fc4422161909aea2c79ad08c14b +81f9eb4ef28aacdb43e11dfc9aa92ba990be4d3c14b484fa677edad3a3fbfeaa859a7f9322b5e95818240d7326215abf +84939b2b6bc859437d1a7a8d6ec9a357c6b716c4b4cc22abc274af872655940cfc72c99f5d0283d90e05191fcdb1c232 +b78a5b74a90a805410b6225fb9576d6d73752520f25cc3fd1edf8ea9f6559d3080f9acaa2246809b6a66879cd2ae446b +8d0a92baa88bf38dce5385ccf15d345b28e2e5d0a2d469e689353d80eaed8e8408933816d70ad752f226c59a0d5b5f0c +a7e15f8a8c1655b7b346c9488cff278c793505379b781b31b273b4bf09b3bdfca1c8ab2334746075d636b2e05859f215 +b70daf14f2adce03c7b92d6aa181f0c507a80a37493d8dd12419d5ed5f943a98099fefb46ac827d6e4efb9b8233c99d6 +8c2480814661744d116fba7355bc6b1914975e44cf0e976d50b6a20092bb1c636b7b44ed3fe8d63b5555ffc89fa759d6 +a6059528a4fed36abb74ab992b22a4f9bf1d05c5de2bfe6837b9af1adfed98bc37ed7481b5a99675d432743021fcfdb3 +b7e19f1b25bc159e5a769811e773c3a8ffe8be8ac77ed0b711540915e5c6e7bafdb407cf9b85c551f67fd621ce8142a5 +a2f66d4f7d16ed3e7ef5fc90b42676c61a98ff18bd26ccce91de03b6a0130c1db17a6bc57be135e410a76d2255b15813 +a139c916927dc3d3fb83598da9217ca64f0ae127215332e9a7ed82be923b89a801c44580d5617297175f9dafb1c4eaf3 +af08e1e1b04ec95366a12d99c80a9a9ac40ac984a575dd0230cdf4eb346a7686da55ef0a276f3356f814af31f9cbf1aa +98840aefe287369221c0721cd7c1b15b1d670c3cbbfda191cdb5434bcad757e59c30ec82b2d8c75947405888d44da435 +b7c61c8d42daf2e278a12d8f6eed76090b71c82275f8b33504aba75d95103840e8acd083e97a5a5aa79897876a68940d +a0264048d2a2061d32eee4f661957ff351e78436bf49ef973c059612874ce9c91970869d011dc13a5b7c754476880a68 +897199a4d8db8aa2db5d9be3d4f4312e41fa0739eb06c62e2e046c4b9be829a447e5d47227e2d96195d3b7b66eb59da6 +b512a9082881f5dc90b02f8bc4f38b133348c2e933813852f6a8e7d8c270c9ce68a5524af7d1d3123e53b2d02a53d465 +80b332469254a96f53c95ec79bb5a8bb1c387d40e58b73d72f84384c696ba0d3c81d6ac90be2979c364c44294e90432e +ab680c2e547ea5cbf95bf813020beb461d50ee4341dea944eb48f6a8584d35682d20186e3b190b849a1ba25625a7f499 +9070581993a0531d6be372d370c2e4ab2ee53f30e04a75ae61ea0fc2c320914506c4d2d4b4487c1f8fa88356fc45c895 +8424303dad6b4051ab633ad27ee51783b2ead61c5a6dae1eb3ed72fc1f36e2a9b1f315504a4bd90f9664091f2f403d4c +82225611eee626556553b9316dab4043aff241a81826a33aebd9864a91e299b765ba1fb43eea2c2047e6b75b6d7fe3de +8a3fb221c616ad55c352dd5e0c09ee892022013d6965aef40d4f277a42e9fa01226fe973cb99aaf6ffe4f4f348fb54d1 +b07c07679aa51713e8a7d7bc304dc15ed5664b66bd371877023f3b110b3927e09e259ef22895c4001421a69c6c013cc6 +83556c76bdac0dd8db6da231b863c335be076e7299802eebc259e0818c369f933a4a4b18e2df8ca07e82f60767b462e0 +a516f659b7915d2f7cd0f0f5ea2491b15f0c84dcb191e7671b28adf7cf14a56d42cfc0da94b3c269b45c535f6eeded49 +80d7cc6f26066f753041b17ff1bd27f6d4b5603a43729d33d596e21a67356db84ca9710158089def425f6afaf3207f9e +b802a47f9009dbd48851209ea1e2739020e717f0ae80671d9f97a0e43de923273f66b7fcc136a064c8467372a5b02d28 +ac92fec1864a8a911633f377df87aab56713876316d48240fefeee49ab97f7406c22e70f4938b5912c5c4e766146b7a5 +89224225b9835d04428b0a74edbff53dee2be285ddd1e5a3a8c37307c0500578155f0c4052e4bc8be04c56862fac099d +b1d3c8492fbf22ea60732745edd3b0163ba5a20d1a3315e3773f2540ee38cf308d42ec72cbb3e3dcea457d1d132c3904 +8bd00e38ec30ee6c44a0e5b222f1f737c9ed2a4bb9225f1741d6334df966318c8a0fd2fbb109557fe8c9479694b8d8dc +a930ce5454efc0b247dc148aff869963fc5c240241d5590415cbd36634801a04d3873d93635911bb9c0c42ecb005cc63 +b83d4f80e9e0fa47b42175df74935ba8aad2e559b80e84478ab1685bc3eb65d51b93e5738d5ca968cc055ca0c552a03c +b3ae21258f98051f13af3878b8103bc541fe6f20b1c3f8fb4689ddb8800b3c25cca9b55f0a4104bdf15dc4d5844abb8c +831ef8684c1cd446c58c59d0152aeade5cc305bca6aa296b92162615f052ba280fe289edd62fda6d9f0667c186445f52 +97bf9659b14f133885916733b7d4ac7e215495953caba970fa259f7bf6b79e661090ec8d79e1c9ce8dfb17e8552f93af +84d5a89cc2332baaaf3d19627a65f4b107f8dd9228a1434b327732f59883bb54fb8ce60d6acd026ed4b0e94e545d1c33 +8e66cb743f95ca5486400b0d89d02e20b98044be1e3a12983ff9fe086179e5a0ebf4dcd5098703191552e9aa660a6de5 +87b4cfb35bacec805f8148786788db84eb8f4bcecdd0570ecb592c705450ce1a90b6d183d37ef58780ede3995be67497 +a72a4fece5478011973afa543f6d8a8ea06a64b241cf7d8bd81fa3740ac2a4cf10e5120abcc1c1101f94da89507a40ca +89dc6001a96adcd2679916f43dd19ea00508c8d5dd6b0090eab7982fd2f3571b62f3029588a0649e73f49124525407ea +8ca75edf1259599e873530eff6151c822a4018e71a340534219ef8641cb6683215891df41d4e3c0ca2560e57a7aa913e +9282d32f868e5ee6f7fc229dda5b94b603476de30cec0a44a30edf396b52dc0ebd472b8f726d4b67d76179fecc1666a1 +afa24704223707db89690bcf9761f07a093f6009ca9fc945e0a8801fc29f9f51292bf95243e466fe736088af36c55ca6 +b51332508ddd9a2610edd2b0ad120272ca342e96c28baae37a2c4f07e689303a46c237712d07e446b1d67c75aa8ce32f +9219249f3799dfa4eb4770ee323f821e559e7406bb11b1f1889286221b22c8b40ccacbd9ac50ea3fa9ed754860bc24f0 +993515270c128ede64fe6f06755259105d0ec74947b7eb05924a375fa5c6d14822f3d7d41dd04fa5df8aa2aa205a1dec +a83be4c2511bae430034ab15b194ac719d7b7041f9c0e321317f513a97db39e97b9ee1df92a1962f265b7a3e98cdd753 +8ac7feaecd26f7b99fda3ed0b8a08bd6dd33ed5ba687c913ec0ffc64bbbefcda6f265072add4d944f2005634601ce68b +b4e3ac6b09299db9e1a469f3a0b2d8d724ee47a417a517bebc4c2ac3efc5cde086b57b9aa4efccdef2bcf8f456d973f6 +9262a24a84fb7b2a84d700f98dcf3fefab8b47293778c20bfc356860cb84e0bf102bae9facd9986d92d1762e0a955836 +97be2041c42bd25e5eb519279163b0857f8bef627492c27b1182f8bf0033769246be5886422cbd2409c08a2615352465 +b0b87d059a00e3effa2e5e4925da913b245785f2932ac3ed364ad19a064d3561b8aa6afea22c951316074f0df179af36 +891644b7b3321b06a2a40cd96c2b8b29d81cde5b48546483fdda439000982a9cbf1f6333fb6c089d39da6492cdfaefe9 +8da9149b7f4783a24240b7b9c7e6df4abf8d699d3834e31ee591489bf4744141ab199c173db64397c1f9bd5f9c862ca1 +8ad7f9fb2742654aa2964fd468e7645436cefd1308b064fd63fdf0d3adb4caf6cfe5426354f6cc284f208b03d6b2d918 +8435e4668f7aeb027100d21e4e0b6ee22b401d21966a3736b95610de86c7e2f2c9ee5d0f901353675eee5ff458dad69e +9010895f045538bd11b47bb8996f27198c8d6cffd3220569e6b7407f68f35c47d1efdbcecbf9b5e241c3c2879a4f6936 +92a9aa443b5ee7bf13b6f43f2d8d8db7f6f33fd4073a606ec5772421a55f464831419726130dd97829a7d4bfeb1ab078 +843f3266560be6dcbe0258c3c7d7e332330e10630c069892954290288eda301e247f479505a8a1bf7e59c99ccafd104f +915bd1dad808f8a568725bd243f80b5476a2999d0ef60ea3ef6e754155bc4121b2b879d01570725b510c5a3f09cd83ef +97250d781815b1825be192714884630e9f564b9bd737d55b8ac79ab48d0fb3ca53bd21ead7b2fa82a05f24083f25645d +81e2d52333391ff2faab39611689a62d6ead77039e8703f4e012d53eea17a4d46f2e3342e44b6edbe73a542b461bda45 +89c9f9fd5f638156b018831c1bb70c91215f4a2f5a73c84b1208bdf6ad652a55df7213336ce12bd910a0e1a726474f95 +92bd02984d090ea7e2f3eb7d36d1e7b9d731b6b047e3cdd4af7cc4ee177415fea7a145205e484b366d84191f06af85c9 +85a86fc61d5d916ccbb219db52953e1495230aaaca63237e9165276405f07ad9644e253ae394f1ccdd231944e7143313 +a2ca5b3fbc9f3530f88c0ed7071ec3d89b272174c366eedb5d15d2b648c65d23c0faa4e92c776357e7c6883a0084d03c +ad171f5badcc99c8ffc9d8b707d792046f86cd0aa478e0e2fbb32fe095f96cd134ca548d1f7713057694dc6b26465315 +96bd15d57da9980870fbadc98c68db76824407dff2700c45b859bb70d98374d4a4ba99e3ed0b0c17f480fe08f16c6b8a +8300bac69ca088c3ff35749b437215e9e35a16393e9dc094f520516ba57a485def7029d30adfc72bca36eeb285c19301 +8a09e20be64f346668fcc7b07fee9c0ea8094c935cbf4f3a4cdbb613d4b936c1edb9256b7c884efb72393d97c0da00e1 +b1f85827ee6f041f93ab174d847a55710824fa131c9ade9561168c3962a25c617475ebc4105eba6e738961a754442bc8 +a131558f92e215969f41b6a57d1e2f424149eea531723821dd4cf8c54325cbe66b002de2c8287de6b41ab4b5c35f060a +81ba492b8956f73557f361a856c6c884ebb300d828287d5699e22e0cfa75c8e77a61616551d0be5178263898c461d6f7 +b2608f44d3c22fac8e13cb59e4ade8b9a98c4eb1ec0959ea400c97eb937ae3f66837e91917057148befade8389af2f6a +a6ff0323b5a18a4becb2cc6b376086b47cb2baffbfd1b0f2229ef2286fb4a34c5cd83a5faed5def7bbad519fcab8a856 +857d879cb9eff22501d883071382832730704bfcc5cd5b07cdce7ab8dc41c565a1eb0e7e4befce8e0e03a4975d3f11ef +a2879a20c0360c516811c490289be7dfbf7dbd41d2f172c9239f99e3d091957e0446854f9d0f753d90384a80feb6fa56 +83518624f33f19f87096a47d7b8e5f2d019b927e935a9021823fac6564c4f2328dcb172e25bb052748191e75ac682bd0 +817ec79132faa4e2950665712b2c503d7fb542aa57b7b36e324f77cda79f8b77bde12314e2df65c5b5296a6bca9bb0b4 +b2abf8fb7c3690816fa133d5b4aa509cd5a6e3257cfeb7513d1408b12371c4d58c44d123ac07360be0d0dd378e5bcf99 +a9fe1e4fb1574c1affac5560939face1af6657f5d6abce08d32fc9d98ef03186dbb2dbb9fd1decd6d8f4e4687afecce9 +89b2f41e51f33c3ca3e44b692e8a6681eb42a7f90b81c9e0a0bc538341df9e2039ee61f26d2ebe9e68df5ed1bccf8cdf +8b35aa7b1d9e2135b35a1d801f6c9f47c08a80e48603f3850b425f64e7fb9860d1adda04f92a1ba22d00dd0a26e781ca +960574978cadedbd4cd9f764bee92f94e08b7af65403de36b21bffc9424bcee845b3b028af2e9e545dd77cf1e69a6a7d +840aa0f34b5b6c39471f54d9e85f1eb946468c4fc01963a9027cd7864df01f73c2e864f1f07aeed4b1b1af72808dfa07 +834464a84a11200e3c60f816044c254a7d9baed64aed45a17325cef7fd62338e0a26da78d199d30ac3411714dc813223 +b4ac6fe2f5059546f4ad9a361426ead33237b6b9030b129bf0122085c85fe4ccb33cf90f5a7f23c5b708a5ac64b487f6 +a12aa9035464795f2a67f3eaba478d5ebc838ed9e997c7dfa241e1ed60a94b367d3f969ccf0ef02028c35215698b309f +ac8d926492ec2bb68c6d8aa9bce49085d3d266f3d5f1f924032b87c42b44e41da7c047eeb01e4618f9d0f123dcaa537d +a5142425825d813ed8ce1849d81aa40b11f1cc3daa89a9f798dd83065c74820b4da6122b3308f528b074531df66e1a5e +87ff55c9f5aae079e7bf24084dd9c6b3bc260727d942d79cbe8dc13341d98525b4ece3ed8169994b56a387642f09134a +88e680f148ef2ecdcfed33b61f9e0224790fddc9069bd6999e9bede1791e761637c0fd60b52990b6c93e6e5429e483ce +94bc20bf5aac6e9f1060d02eacd06c42aeac9a1c5635b15a83985dfb03938ddb4999a822e865635201489c7f75601b29 +849221cab7599f25f0b114df092bd5e8c2430503ae959bef1543a101de0790a78245db6a145e26f40b5f9bcf533219a3 +88b6f2c2e7a7954fad11009d839ce50780921f80292320868d481e38d26aecd80fa607e82219a99532d88cf33b39f562 +b0d82947dc23c0b88b86c321b582c15decdb825ed909a731b42d46bc895009515a3dc646c98dbec7d71b0722df82392e +a2cfb9f7c1a76c8073363c1c3bebe5dc29fa76533caea41046c51ea9bbdc693a121b957cd96be5b6da18704d1865cff7 +8f0ffab9a83355a22683a9d998d1c1089449eb308711eaad4265f05927ec6d0d1ca39217082a0b372e02234e78dbaaad +ab024661e2b2937ad374c8cf2e3669f1dc55558a3a881e9ec4d461f27e0fa92e2bc88230f038bfb051cf2145ca747a07 +b98d9b9ec9eefa56d38cca959ce1aee7b6d4b41a8dbbd34b3f50c0a5f97f84ed2502ded1ce8cdb5895872360d4ba6d61 +851244158b3184a62d2c98d148e2b1102cf0d5500906bbc2deda95acc5e3bc4b4a3344febbb31ce05a56dfee86a74913 +860d9e2cb886bd3620b5d7499d14b415532482569bd45fd76e3e8052d78a73ae4b2b41f139f9cfb136564108cd93c0f3 +8305a052a0fb2bcd41f3aca075c5f7f233bd8f861451d03f3a6e6e31f7d08dd89fe1eb4dd7b238a78b12ddceaad9768c +adb703e4778c7e14fb83541ab00b5fc344108243ec6827c5d9b302ee68321aa569da1718424e6a57979ab7536d5eb43b +b1a754b87b9e21aeb86217ec5b4fadb7535344567f1bd15e88ec12a833fed68e26bfbe03b7709ce24ba6c925ea0a0e07 +8c1e2f6bf820e1653f3b8213e9d959d8649196223c2aab57b7ebda094f4919f88d883bcc6a0cd0be335f26f5a2a9c962 +a082deb9865fe8668e91db0e4fd7fb50fb3fdae3e7bf1217ce0aa6f286a624624cf936d762bb2b6c3fead6826694f846 +a10540ca05fbcccdd0a2a66aabab3b36e9bb525794cbae68bc3dace6116f58942218e9d5e9af10d67b5f6fb6c774fdd4 +b81d22c4ab0ccaf447cc5fc2ff3bd21746617e6773bf43257c0d80331be2e8437b88c9c45309ee46402b38d3d4911caf +84c7c6e924713cab3b149f641dabf63ad5abbc17c1d8ee7802a6630507aa1137f7e034ba1d12ec13f1e31efbab79bf13 +8773b9d236e5fcfa8c32e471b555264692006bf9a869a3c327aed33da22dfbf5780ecea7158904d4d6ac4acfe9789388 +a4c2c1bb7290eb7af2013f7dde78282148593f066b09faf42e61a3fcf81297caa5a00fdbf6b93609c8c5782a0f25341a +a7bfa6e3f273da3dcfac7cb9906bbe9fa4fc2872b184d79813ee273e6cc4d7f37f46164362707a1976f5b6a2c5d7ed1a +8b71502019e4263fcda354a0fd10aaa7da47f4abb7a0c715c7b017e9eea14f2b64009b29b467394668c7ca995adedf82 +ad7460fba7deccc3f9a7d204233de47ce30ffa55e1e164975cdf06480a6108720bc397b93ca8c959df77d44a1e1f05f4 +a5b8df96ccb7b078a3918e74b1b10da21df982538d2c9313f5129b2797c8a6db9ff8707241ff72d3e9d5983397321736 +aa6cfa6386660c01879656da6c4e72497690708bae6c5cd1d088f443cb5bbbe75561d6eec256a72b9728377eb83ef973 +b9699ce7c5c878e44114ab7a598646c6c7616b8e08a9ef8ec291189ef9945c1a538d2abf1ce3b0da0f8eecb303b81b43 +b8d0fd1d278f53c455de92ec4357885fc6648dc5f276930263da7dc885b4a9628a2113e28b66b1e64fd08189427c614f +84ad8d262f6ef5d93e82ff6f4af995148eedf6d8e079124daee9b99f506e2968922eac2c7d4aea741fceb7733f20b2d2 +ab5e30ab54641e3a44450118b8235554e0fcfffdfbe1430ceb3f7ef33325725741995fbbbb0c16f0875aef0f1e0c98ec +80e2cf8bf386ebda46045852751611f2af80eca2e910d9ec5f6e2c7376611534604ceafa639272b3d503b02bd66525a6 +aaac69af8fbb87da1c1b7c1b9e59942887ae839a91f0c1d191c40fe8163d7f1dbe984e4fd33619c73e63abfa7058f1e3 +a6194224ad838ab86e84dc80e9b8abb121ae6c3c7fddc476463d81f14168131e429a9757e18219b3896a667edda2c751 +b68f36aa57aedc7d65752b74761e49127afa65466005a42556230dd608ecc8f5efdb2ce90bb445a8466e1fc780eea8c3 +886c3fa235d6977822846b3d6eccb77f1e2cd8ba3dc04780666cf070cae208b7513dc4525d19a3fb6385cb55f5048e2a +a9801273ef850b99eb28f3dee84ba4c4017c95398730c447efe8c1146b0719f252709d3397ce60509e05da74ed0f373f +a58c2a5dd13e08ffa26a6c5e5eb18bd8f761ab64a711e928e6101512401ef2b1c41f67ba6d0823e16e89395d6b03ebb7 +91318b564ec8b2d8c347ca827d4d3a060272aec585e1acd693b2bafa750565c72fec6a52c73bb3ae964fdaa479700532 +a058db5d76f329c7e6873e80c7b6a088974522390ccaf171896066f0476742fd87a12fe9606c20d80920786a88d42cec +9838e07f9ed8b3fbca701be0ef32a3f90752bbe325aca4eaea5150d99eb2243332745c9e544fd1bb17e7e917202edab9 +85a9ae7dd354f36e73baa5ecf8465d03f0c53b24caf510036b3e796e4764a2bc17f0373013af5b9f1b8973226eb58cd1 +896a4ff4508d069a7da6ef7bed66e1080991daee8b227f3c959b4f47feaf75fd1b9e03d0917b247c2db11e105395d685 +a36d9a6a037bf498dfc0e535f2034e6cd433c7b52e520469811eb2e9f04499a6ce40257d2905300df7d81f38d1bba075 +97aac3c5492aca879b4c06db1834b30b8850a244d29296046a84c637d9580c8521ab4752ef814c96f255a139660d7639 +8552bf592a84ab4b356d01643c90347377ebf1f2b38a8c2e55a3f34537b8c7dcbd62e6776d6c2114f2bc2d4344d1567c +84474ad163db8e590943ccd1dc50b4f444beb8275919b33f53d42cba89831e9d42ce2de52b26f4412e2a0676ce913277 +900799dfaf5eafeb297c7b4f892438bf2a65ce04034d66f8e5cc3836e4eaffe782fba4f4455a0fcab49102a240d1780e +817176415e35ad4a204b9fd5771bae6cc270f6ff050996cec89efbe461b2940ae5dd3c6c7d7e31b1da5285b207efed27 +965e5791c927d47569bc54ec9b4c5305788aecd87a26e402aabeaeccc03480df46f0586ca2e2a9918885cd03332af166 +b96d9ada4b5a04a94807d71726bd557de94fbd44042d7dba40560eebe8658d1da49eba54499360619f3b2c38e8b5ed6a +a07b6d641a43e02e7868f30db4dd5069a2f221b4f122ce9b11eac04abadc4f25f3207f1d2d86c7935b1a3d9992ea9814 +8250d4d8ccac846a4b1a9fa392d9279b5bf2283c8b95d8164c3c0d199fec8849eab85755f2a2a99d584a0407742e3200 +8324cf49f56fc14162f9a9ebda1ebda0388d09d8688f1938aef7dbf9505fc119069efc552f68cc7cd9213f96fda2c6de +a98e6f1e85268dccbe3bf4e92c9f455c58dcb53de1dba3b78589adf2e50e79f8e245f956e0d098eb46f5d3746826c6dd +b103ec12f266b4153d67b54d8fc079357ee342cbe5008adc3e0689a7f788534c4601e60e939731f49e4a1e24fd589f82 +b2d7681e866420413cc98eae67614d383943e3762d5742cb3c57e26157633c20880eea1209feaf68402d5d33dd699708 +99fed0ae4112ec9ed74baac70d202a885aa51cb555a3886b49016744dd4017640dd5dd564998c4d842a9f38f3e004e68 +95c35401314467219c8bfb1ccd1f1eae6ef4fa9e48fbea14f70d5315e67b16c46cd03554471840e4a5030b077d2a3856 +8d029380e0c294400d6b8673a23aed43697cb6460fc1bcf217aca3b47cf240886644ed09521d6a05f6abf56f99722d84 +8ef54d1dc0b84575d3a01ecba8a249739edfd25513714dd4d1941fbde99dbbc392f7eb9fb96690d7052609af23aa57f7 +b8ad2b7af4812417aa8de8f33a26547f84bb84f39501d4b7c484cc8bb54c7e166c849b95240fbe459a4719a6e3bf1651 +9858545de898721d19930d8b360cacc5ce262c8e004867a050f849f7a2f2aba968c28d51f24a9af56aaba23a9ded4349 +94ea5043b70df1db63f9b66b4f9d8082776f721b559f27d37b45e0a84faf47f948d7c4532dfd854a4bac49fb2ec8e69e +a2fd88d7b15e3c2778f6c74470d0f9e1a1f979a4d58bd205361eacadab9973d585a6508e685e640b272d6f8a448eae05 +88defd6bccd55db8ca84e3c8d0fc55a3456b41788f1e209d0aec19c9c70febebf3ae32cacaa1dbbf796d7ddea4b17995 +88b8cde2449d5ee7de2ee2f32e845d27e171a51ef64f1d3d8a5fd7dbb9f898ea70eb7f6410cddfd7b7ae70ea8073cc2e +8e044fff6ec557824866ac76301b6d93ed19b7177aa6baa95046330f5d69b572b59200e3653cf2f2b559455e782e8960 +b5446b4d6741c824885790d2d26258729dc0ba2f469c85a47d38886d933b785a4f38a951d37f3ef4bd5091c03fa3a071 +956c8afa8056e9a71ab2e8be5241ddbb3a8b3cff2110cb0e7389493d9fa45e6c4b769ebef540a952db6dcd8bd55baf64 +925950cae25615246e29d594ebf34fa7d52f78a9867338648158f2131e6eb4dc17e18f9db8a5fdd76d017b3a9798b3a7 +a17ea4b43211ba990270c21562690b3ef154a46c3d669c4674c80bd424cdfa95d8850c8e882b8d06504f929cba3d93af +b315ec723973a138508afc387ef651fd8a8804f93975fc36c2eeb796a304eeb1508518d8703e666a74d14318253f526f +a995742d7433b3f230e622de23cb2d81cac76de54831491cc29768eb4a56da60a5cbd573e1da81fddc359b489a98f85c +adb2e89f0d15294d7118fc06d4fdbd9c51d3ecbcc23c69797e5b8197eea0d6cd1240910cf22fcab4ef1e2dc2dd99da91 +b5ec9f9fcd0b5d176b643df989bb4c4c1c167112373d662fb414875662d1a93160dc0b5cdf540e8a30e5fcbe6cfbbd49 +b1291b53f90aed275df8b540c74a1f9c6f582e16c5df9f5393a453a3e95624ab7552e93d6e2999784e164046e92ef219 +8bc7b7b1a584a12d5ae63d0bbe4dc1b63c9df9c89bdd1095ff4b8e7c822bf8c1994c92310a3644033c7c9689f4b7d2b0 +ad7fc45506a10ca48f991714ecc055cea376c0cbe667f3b40ee8dad8446218835439ae59bccc474cf47b053748ceba6d +b134756828a5f5725c0b95109e09ca450e3834b127163a0aeeb544e63cc0cdcdf66f8ed98c331c7c98758f46af369a84 +94535bf1636be0974b112fcec480ed8eafc529933f3065c40e417e608e43a392206cfde8bb5a87b720263446c90de663 +a4df4f6efbc3701000fb072e5cbed2754b9ef5618386c51ff12f95d281d1b700fea81fc1365f4afc66a7c83bd0228fbf +b0336b3552b721087c7e2194976a9119aee13ebed9f1c3c494353707fffde52d004a712965f460062ec9443620716302 +99a39d1d1ee4283b75fa8c1fa42b6a3836b734be48bdd48050f9b05e48db6354fef509623c6ec8d447d630a9b3352b77 +8e3dc3583d40956f9e784e8bbd0b5e65671d2ff2a7c387b20fcb7da9b969f2d122aaf7f054d450dc611737604548c03a +b5068ec5b7bcb5d8583d51cb25345990f50d1f7b82fe535a6a6b17756355885047916f466ea3ab09eef5516bbf2dda90 +a8284ec1eb1d21e693f31a6c074199ee85d8a8da2167bffab5fe240defa2773971c8437e358a18f7e58d1e2954f57f6f +aa7415639d29081acbaac3e9c6b059d68e8702db3f430b86bb6e220d476fa74841c875e9d471c8a5423c58b6fee3cb54 +8afcfe6f65fa6e07c2cb3e1756c0ef2c589830be96edd50c3c248e3b17f51a4b08ba92ef7eed7991d81667ddfbf2bf7f +83b9c8dec8ca8f9b85f0e36c08c5523cfeafb15a544398e6f93b48b5fc4b15a0bd05c0f176a9c2469664acab8dffb0a8 +82a128a89ea46b9debe5c903b950c0ab30cd7570b979ca911500b5c2cca5c4ee6b2c2fa414b5f28e367f4671ffce60f4 +b79fd0ccd2629a361cd6f9307c02ecd4d1f07e4ee03ce4b542997e055b07a026cbc0ba05fe3da309efc58db2e401a8fe +b190751141093823b4b5324cc26c4f3258552f7893241201f2fca1ae9b1a1d4d4964a9abdde8642cf308ded61ce5ef09 +935fd48b95aa6f9eada0cf9a25a573f0ffe039888b3410788c41d173747bf384c0ec40371bb4383ddcc7d9f2db3d386b +b9affe100d878491ff345636ffd874ce1f27852a92417694afce4163e6a80c78b2f28d78102fd06c3283ef273ad37642 +a877670276d49ec1d16c9f1671e43ade11c0c1a1413755f6b92be9ad56bc283e4bd2ad860367c675d5b32ff567301fc4 +8c660d16464878590761bd1990fd0fc30766e7e49e97b82ec24346937856f43990e45aa8ad37283cb83fa16080d4a818 +ae1412087da5a88f3ccc45b1483096aeb4dcf4f519ff3dbe613f63712f484bdd8b2c98a152a9db54cf1a239ae808f075 +ad83cead97a9c3d26a141604268f8a627a100c3db7e5eefaf55a1787ddc1dd5ffc7544e4947784cb73b90d1729003c8f +97c3140ce435512a509e6ff3150da385fdf9e0883a5dc7cb83d616ec8d0a0014e4e0fa57a4d12c7997cd84e07d49a303 +a353773ff68f1615454555bf658eabdcca40a9c7bced8537ea6fa8d54764fd1f032889e910d2a2a342835513352e2d2e +89e8df0c17a36ffe08149c2ef8b27306d04cdf437135aaeba697abc65e3c8e91bcf1817919a8a826acdbbe7dce79a18a +9928c2da15ac6cb20b15859c22508cfcd452c5643cd22eb84abf5f0a1a694fdefcd8fc329c9b40babc52630743d6b65a +99d837b556f8d13108eef6c26333a183f59383b39958dd807b10590c3d37f62ade6c4a320ca2e70567e0218b0ad5807d +9272da080e4aa18720b634640b01bf1fe506c7c8a89dee8759a53e2ca5cdbbd4a4f3aca54924c46b935362cf1eca066e +b4d39752c882de1c1daf3854202c1d58c2bcf35c882006eb640fe54a97be2655281cdb91c30d1a41c698617c2cf64b01 +8bf827f4a7d47e07374d338a3d8b5c2cc3183015b5a474b64b6086fcf0cdcf4852046c9e34d7917d69caa65a9f80346c +901bffc7db9c9416e06f593a76d14f6d9e5dea1c5f9557bd8c93b9e70aa4782bab3518775c2a5b285739323579f7cf0a +af7e204388568627ca23e517bcf95112ca8afd4c6056b7f2c77c4da4b838c48791191565fd38398587761c8047d11c47 +ab2576b5366e6bd88b347703f9549da7947520d4e9de95d7e49966d98249406ed9270fe69347c7752dad47e42c4ea2f4 +b12e3b228b761dedd99d02928105494ded6d4fea3026d73d65ebffa2e85e2cd75b6d091135d418dd95ac102c22b5ee31 +a20b4a752685d5e31ee7e2353c8a1b9a5265f12bb775004d282a3ecd9deda44831bac1ac5151646428b66909b2a423f5 +91a1d4bc0062a86cc6786a96fd3eb4436d8a4a187b7cbba02190d1cd6ed3c3797d9ae7d6ddc413f1c94a21f62bd04ef5 +977f18da1a5df5cfdd0276f583cfba2b2a0fc6139520664e20068f8dfdde33e29d179abfd722f142448f4677aa47be6c +abc3ece90f0f7b1d80fd917de27ab0d88cca584ef959da520825e54cb5a71336b15f8b348532d08d47a6fa600527ef25 +888d36a2c7cc13a1c1aa338a183a74a1f57713e76cb825f9837f43279ce4741999b76a16928147537bcc20f2e0195b0f +af3f5dfdc2dcfe19de893f385f39f550cb1dab67c2e97f1d5fa735e5ec96d6680066803e8a0eb010dd4399f654195513 +a0fb4e08ff56530a940a86c28830956eb6dec2f020f7faaea7566faf0a4fafe0cffe01480e87763ec22f201be51a6451 +92343c5b107910b203c64a79c93d354f7ee5b7d1e62e56732386776e275285561cb887019cc00d3fdbe3b5d54460bec1 +acfe7df83c4624188a1011ad88c1e1490d31a8a8c8016b40aebcdd7590d9c0793e80d2d7ce6a7048876621c252a06a5e +a7da001dc1e33e0e129c192d469d2bd6e5d2982eb38f3ba78bae0670690c8e70f40e8114a57bd0718c870ca5dd25b648 +a903de5ff97dc83628290d781e206ef9d7c6b6d00cadc5bacffb31dc8935623ab96ade616413cb196a50f533e63641d6 +8f9658d42ad14a60bbf7263f6bd516cfee6b37b91a8f53715d69f718a090ad92484061c2cef999816760a78552fae45b +8c15b72b3d5fcb9ffd377fd67d9dfbdd706593fba9629002639973db12aac987bd1db70250ded31c88e19efff612cdb8 +88a2a4034decd854fb557960194ff3404e239953818a8a891bf72a0b26a8e570a65c4a630884de991ae7452b3234f31a +a09cae5c4c190537bf1dd75bd7bce56f7b799762af865bb9d1ee970f6a133c27cce0dd0f14a0e0516ceac41054e6998f +9760ebb1b40f9a97530c3b940d4ef772a225e5b63bf18283f8e302b9436c5209f6294980fd37058060e429fb7fdc3a56 +adaa9400eb86d857dc591b25dbe3bc8f207b69e77b03cb5ee01f7e4b006b5c8f6ba2b51b5a45687479885708509363de +949efe6b00b3248846747a9ad4a934d6e4255994c2b540a59fbbde395fe96d69bb67908441cfadd8c8bbb561fe52da03 +a19a45504b6b1dc3a0fe0e6a1384734a3dcd5a7cb8fb59eb70e49426c4fc44946547443d558e5719a04884ab3a2811ca +8934c9ee21e8d1435426fd0f64232a0670a7946ec524c054cd4f2cc8b1be9f89cc11002ca8aebae646a2050d91716b10 +b1150ff8ffb34ffdcf7d603348c0aed61e5f90ee0a1b814079fc2a41325c75f2f9ee81542797ede3f947884266a772e0 +86ce8cc7c1f92af68de2bca96ccb732f9b3374dad6657dfd523a95e8a931a0af2a80df74098514a06174406a40c16ba5 +90faabb9ace9e13fd9584932846ab28a618f50958d2ce0d50310a50c3bc6b0da4338288e06e5fcbaa499f24a42c000d5 +af4a935c2d8df73332a16dc6da490075cf93365bd0e53e2374ef397514c30c250bcac569b6df443985cf3720a4534889 +b7f948ee90f394789eb0644d9f5ad0b700c8e44e5e9ed0e49da4cc18483676d25740710b1c15a557965da635f425b62e +a917913091245beed6a997ff7043ecf60c4d655c4db0b1ef1c704fd9b0e1ea1335ce8b9f45d6e120f81805ce31555e30 +a48099da8406399bfb1ba834f6f7d864111d0036969a5cb64089947a63dd9467d3857b605e9f57f5ad5f4ec915088d9b +9784c3f9be42eed354542b1446d734521f8e3f01cd9d495ae98f2e4a3a16767fe2ad909e0def5d9a6267f3fc6a172cd2 +8d9afaa323847a3226ad7d7b60d87322ffcda2e4a8df89f58a076f7972d896588de685a2e155e243bcf9456b0a0d6d1f +994413faf0b843f4ec1842c706c45ea5f24351c68674a27887bc8b182eda756856e507a4e8bbfd937e2c4c581b629ee6 +b3e72d9d1ddaa00c7d22f25462d6e9f2faf55e30d138dce8bb1517eb0b67132db758668aac26164fd934d732633bdea5 +8e95875e338f714e9e293df104f0ad66833bbd7a49d53a4f7f5fd5b18a66a61aa0a0f65cc31d55e0c075e0d3e412cb90 +b980091862b1a9f9334b428eae14bbf1cecb4849e3a5809773b0d071d609727270f6ad97f329eca896c178ce65883db9 +915d7ae5ae780bdba27ba51a9788a8852a15355b569581d1f18f0d94bcdfed2c1ed5a4f58e049e9825cda11f92b2c2d4 +83e581058edf9259d0b06128282327cacbb6afc939578223cbf93544599f799a8dce1fb21d52464f990a877086f42506 +803612a38b6f6efb97941997e101ac1878e192456f8fbddb3359aa7f3023434ed8fa92e60ec8e7b4473b1948850e4311 +864a1bf4ac046161617dde282e44ab3cc1843da01a09ca58aa00ed00eaea9351a07a9ec16d910819e7dcc28b8d2c8ada +922eb142845975d5f6f7dcfee6cac8c299b3730400e6bf82cc0bdd9888de21de9d9f1530640f702c003e1ed63b140cc7 +a7db03c5be647dce1385ebc02f4825a654447fa8c4c8d4b22e635dbdd2b3ccdf219384e49a80cfb1e9e6182b6e4227ed +a167289ff0f0967bbab6479e4a8a6f508b001bbe0d16cad36ab4c105ad44f3f180e39a6694e6cd53bc300fe64dac1e8c +b7766431f6379ce62cba22ab938cdbb1b0c7903dfb43980a417e0ee96c10b86b447241e9dd4722fa716283061b847fb3 +90cda18c5d66f5945c07c8c7dc453dee1370217ccb851bbea32578599aa669b4dd245dd8a9711b27c5df918eadf9746c +ac690cd2af39932874385fbf73c22b5d0162f371c2d818ec8a83761e0a57d2db2fca1d757343e141e1a0348016d5fc44 +abac820f170ae9daa820661f32a603ed81013c6130d1ca1659137d94835e1546c39a2be898b187108662cdcbb99d24fe +b2ea5a5950096772f2b210d9f562f1a4cfacc021c2e3801ac3a935f2120d537471307d27b13d538dcbf877a35ff79a2e +ad94af4d0699cd49ba8ca3f15945bd09f3f7d20c3aa282a3113cdf89f943d7793e59468386b067e3c1d53425dfe84db4 +83788367ec97cc4bbc18241cbed465b19baa76fab51759355d5618067009298c79d0a62a22e2a1e6dc63c7b90f21a4a5 +a3e142d879096d90b1e0a778e726351fa71996466c39ee58a964e6b5a29855123d4a8af47e159027e8e6be0ca93d9955 +860831f8d3edaabd41be5d4d79c94921625252aaec806251fb508e364e39fde8808d38b10d557e487603a1b274c9bc3a +88da39f334bd656a73c414ec17dda532059183664bbbac44eb4686c2601629ef8ff9da992c337a842e3885b684dd0032 +b50addbdf7164e8303f33de5ce854d6f023d39c1c1984b214d9e5fb6f6001cd5bdda816f048a438ff3d696872672f805 +999e58c4c69a912b84561cb09610e415b43832beeb95897eca8c403ef4754f4277754d492eef3673afd4362f50060fc9 +b88ea0f60f8119c5a1fd9294796d387472dfad22442b29659713d1d88e7d854cb7cf5c9ef773627781188626bb2fb573 +a068b3844e9dbcf74b54fd55904d56af754d8ce4c619fead7a07f9bfb9d02118db7c512ccec2489d2a84374ec1d1fb6d +871dee023768636003c799e6f6fd8d31315a4c0da7286345cd64264a016693b3485e0732be1bbd34dd5fa04dfa58a983 +8021e8f508680df12e4a5a1bd49f2d7142df65158b0a7198ffa83abd16053a542fb93ffc33e5279020ba8c6a26feacf2 +b5d3cd64df5bc965228b0bd4ce9e5797c409f7b64a172ba165e44a8e4b38e3d5fabc3e0b9a19afbfe427f887c40a315d +a54fdebbb594bafcefb1a03697711e0091c072e1cc24fb441fefd4e0a0518675a1d7b0966cb8294051d7ec0ac175d0cd +93922202337f72969d6d6e14a29c9c75e0420dfba712029941d1504b9f6f9761d706cbc0652cd09a1aa5d22aec766af1 +9711ebf1c7c7426190d4afd5dd03b014a456bbd9d90ed101623866a280550df26a629dde400c03ee3699f7d827dc0bb9 +b4d686d8bc5c1e822a50124c1cc23c6bc3a1577a3d0b8d4b70d1797418aaa763283c09e8a0d31ae6d4e6115f39e713c4 +a533ea2ac683e4ba07e320501a5d82a1cfc4fa1d65451000c3043f0fdac0a765cc1125d6cc14fe69975f3b346be0fdde +94ee563134fe233a4a48cf1380df55ead2a8ec3bf58313c208659003fb615a71477e5c994dc4dcfb2a8c6f2d0cb27594 +93e97d3f3f70664d0925be7aee3a358e95ae7da394220928ae48da7251e287a6dfbd3e04003a31fab771c874328ae005 +b57440d34615e2e7b1f676f2a8e379e1d961209fe00a0cf6798f42b7c28dbd03172fce689305e5b83e54424bc3f4a47c +97644084c6f7b4162bc098bed781dd3af6e49e7661db510975528f1dea8154f3d87e979bcae90c3df3a7752eb0752889 +a923b27b225b2a6dd5bdc2e3d295b101cac5b629a86c483577e073cea1c7d942c457d7ff66b42fcf33e26c510b180bc2 +86698d3b3873ed3f8ab3269556f03ac8d53c6e2c47e5174ec5d14b3ed5c939750245441c00e2e9bb4d6f604179f255ef +87946826d3aa6c7d53435c78005509b178fdb9befc191c107aee0b48fbe4c88a54cebf1aae08c32c3df103c678bad0ca +860864896c32b5d4cb075176f4755ea87fea6b9cb541c255a83d56c0a4092f92396a3e2b357c71833979b23508865457 +b78fa75d687349e28b4ddfe9e2d32bb6a3be13220b8f3ff1ded712088bd0643da9b72778bcca9e3b103b80097f48bdd0 +8a188b940446598d1f0e8c6d81d3cada34c4c1ae0118ec7e0eacc70d1bced28ae34b99667d5793d9d315a414601c3b22 +842ac6f7dc14191ab6dddffcbc7cb9effba42700a77584aa6a8e17a855cd444c5d138f9d61bf55f43c6ffbcc83f92bc9 +b6742902c3d145a6af9738c01cf9880dd05c85f0d0ef7dbe93c06fdd6493333d218339ebc2a02be1895436a2f734a866 +98bf18488483c627b7181b049d3e6f849fce1f15794de59dcde6e5a9b0d76fd484a46e48822a6a93001d3aa12f48bc6d +8769cac10bda8c53a1c19419ef073a5998f73dcf2ba1b849561615a17cbc0a49bfe3eb4ff8801dd36a22fa34b9a3a7e2 +b45c084d58028fdfae792210fcd183abc4ffddeb4cf52ebf3f8a50e4c4eec2a2758f1241b0920bebcb24b757c778577c +85c1216eec8e1fbc1af9b36b93c5d073a81d5fba86a6daae38748ec1573eacc6bef209e76c87a6efbd7a3f80e11d4c3c +b8007e34bb3f927ec06a050b51e633d7eb9e9a44715d5b39712e69c36177a03cd68391090cc3293098e54f6cf65f6caf +8e85527b27c9152b1ba3fdd532a76a79064ab097570508f233e09978761dfe3012d537411b47d0e4b65265eb32cea2ae +899779f3c31a20b76068ec8d59d97a64d2249588ddfd69dcbaac6bfaee8ce0ff3c5afc4e17c934ae7cd041b760eb555d +a5dac3d8f5fbef018509612e25d179f60d2a62451c76426bf546e9666fcdc73263d34aa6fa7e2bfd4c9947bbf5095eff +896900eeef9be2b2e755128e7b1c436af6fb3984f1e66c444bc15fcf3959013b4902c381f0eab1247f878a6ebd1f4ee0 +8cb17f4b0af2e9b2cbb56f46e6a5d6874ea0daf147aae77303020b4e592ddc92e0dd058def7da96258b3a68b223bf22d +a1b6d3f09a9fa7ecc021ab7c5396541895da6e9bf1f9a156c08fc6f2b815a57f18c337ccfe540b62d79e0d261facb2be +ae70888811434ef93da60aeee44f113510069fd21161e5bb787295492eb8df85103794663fc9305f04adcbcf11ff0c5e +a84bbc8624100acfae080ba8cfb48fd4d0229a60b62d070bd08fade709efc6914dc232d3f7bed76a59204f9252321aad +aea47d54652abd8ca213cfc623c8e30780f37b095b59ac4795252a29c2b6bc703a5203acff8831314478b8ee8771d4d7 +8dd438eb8be14935f759aa93021c2b24e1d588f7a162c42c90ec3a647b0ff857f60e24c0a8953eb7bb04e04be70f11ce +922b07b5469680a10e7532766e099896f4dc3d70c522d8add18f5f7765d4ddb840df109146607b51ceddd2189fa7b9c0 +83ef6ebd0ae6c569d580093e8b0b78daa964760556272d202d343e824c38eccb424262e5b7809d3c586f9e2e9c5c5f22 +97f98bd357db6e093e967fe180cf67ed09fa711580a5ad48f07cf095b2e8fabbe6319f97d1f15d62c0ec2227569d8dbf +a1953a4a22fe6c2beaf2a5e39666b0eb53018af6976e3a7aab5515550ff2efa89400605a43fb2c4ac1e51961dbd271d8 +a5cbd67f4c0bc98e20aa74c09e6f5fb6f42c08e59aaa477b4b4e61434c8884bc14f17cf11faecf46dc4b6c055affbad2 +87d96818f2c4f12fd7705cf4060a97bd28037c5ac0f0cc38f71189ec49361e438ce863e6617651977708094d5336d1da +85e7c2daae5fe59f8a1541c94df50402a671a17dbb8838113fa4b7aaff6114cf2bb5969410cf21e6a162857f2f7a83a8 +a19575083e1731bb04bb4a49414e97aaadb36d883aa993d1f6847db50007315444814740e67e10177a14e0e074fd4c7d +a00ebfb5bcc3a6da835078189038a1e56b7dab6be74332b5ff7440e53b0f9e1eb9973effecbbf37000021fcf50c7c1ff +8969d7943abd3b1375fdfc7d6124dde82b0f7193068ed6ec83bcf908734daf3487a6a30f7b322e54a4818ae5f86d91c0 +b959c8d210fa43af9b20d1fe0ea8c4921280eb4544ef6ea913309ff9d61c9327096707e84dc1662960519be8e7d080a4 +9011d8ac651c42e0cb03931a9e960f58e02524c6b666047525e3b9097e9f35fb2b4b278efcce2bd5ad463c6d7fd56694 +937e3b22ed0fcdbd9ea5a1b97b84bbe86b7f5b2de3866a930611112f2217f4ee7d9822c4ab1253823f77bceeae0c8e10 +828997e5d121f4c305e018a0a0ba338bd6a34a7b4dc3c5ceab098ee57490311c130e2c045b9238a83908d07098d9fc32 +8d114808eac0f2e1a942d80dad16756ec24f0276763cd6771acb6049472e05a9bb1d3bbd5957f092936b415d25c746b0 +a063c5c26267ae12887387cbebbe51fd31bc604630b3a6e8e177e71d4f26263be89112cd12d139dd4c39f55f0e496be0 +ab1e1582c8d67196d10f969eeb44e6e16214f1316aa4a2a821f65ba5834326da6cba04373eabfd3b3072e79e5c9717e6 +a17b1dbaa11d41457e71a9d45d032448091df7a006c1a7836557923ab1a8d7290ec92a7a02b7e2a29fcea8f8e374c096 +a1ed7198da3591771c7c6802a1d547cf4fcd055ca9010756d2a89a49a3581dfe9886e02ee08c4a2f00b2688d0600509a +af09aa60c0a185e19b3d99ffdc8c6196d8806169086c8ff577bf3801c8ab371e74165ba0f7329981e9252bfe965be617 +98c04cc8bb26ffce187fa0051d068977c8f09303a08a575175072744e0a5fb61191b1769f663a426c30d405515329986 +a542bf1c9c3262d488ea896f973d62923be982e572172e2461e0146190f2a531f62acd44a5e955a9f1e242b3e46d63ae +aef7b7f30efd50e4a66c87482386f39f095bff6108e68f74fd3bb92156c71c75757912b111060cdee46a6b3452eed657 +8afe1e0ccd00079702f16ab364a23bbbd3da1889d07c4f8cb04fd994bf9353216360dbd364492932bfe20b8b69ae8028 +9896c690999db3c08cd7b25efb1b912c3e0f976db98a3e830f086aef93222d06ce570a7b2babcd7c81d8f9955169669c +ac7bcab6a281468907ef1ea8a6c1cd624159c88839131bef6aa0c22f331fc87ec6128a2c2a333fb79df549e4587e1a12 +987935c08a30b099d19f96901315a2e60591baf898581c40bf5eddcda806ff24a4536e30ed1e6c0b128a83fc77b6e81d +a0a6945bbede3bb09a4a09ef27baa20619d3e15af5673b9350601bcebe952597c989870746cf75767ffb73b32c6c9c6f +b0f5590079f0a0302b08a0cc1b7a5f39cc6900c2a5cdc7baa333d8328a731b2df5dbb67e27a154d3c44ed1a795fc4adb +a7294bdeea210e528f277f3d50e89e6d79950494478998181ecb38de675020130256f2f2a075899170be964d478458b0 +8ab3041b895a631869b439d5599a66facba919226ca9b39d915f19d59f9fc82393ea781377e9bd3bcc5a310e41376914 +8da399b59151fd48b2579948bb82698e3c9804d70ec7d6f3cc7e82901f9f2de5ee850349a7d6f43e5e9ebd47bd78620f +80e8c32de83d1083916d768b11a982955614a345d26d85b457f2280ff6c52bb776958add7c1c8878f7d520d815b8e014 +81bbec7bd99d2917d2dcd8a288722fb33ad5a4bf5416fba8609fa215fb80e0f873535349e7dc287f892aa56eb9e39c4a +9665796fe04c8519206fba58496bc84a8b9113e7ea8e152b65f7f732e88beea271dc97b1ea420dbc8257cc4b18a77463 +a97e342aaaf693ddc87e02790278e4bb50117af4413cd703bdf3b7cad2d1facf31fde1303b43ab2e0265467474f97a8a +925549ebebed348886e37773b05cd8ad04906eca4536bfed951d1ee41b3d362ddc6e1a302c21ff3a2d1e70e95117922c +818fdf74d7903502101551bbf48d3c7819786b04b192d9e94362d2fcb85760d8b6f45165a5443aa5221bef400525ddb4 +a9d29de7e8fd31b59f4a087168d062a478b1329cd3c81c31e56de4fb40de7a5be9a5269ef0be452c487443a0b097dd50 +a85286ad573db4c9aa56221135da1e31d742e0f6ff01d6b159086d7258f78b08dad55ec8eb5c91ee9d3404b2eeb67e1e +92a79b37db5e777f9ebbebde24a95430a199e866e56597c7d0b0e7fb54c7b092c2f6cf61fb24470ddf250cf609898281 +8d79f5ca67ed67d52c82949af342a9fc60fb793c47c76d84b4863c550796fcae2dd59e285897c6fb96fe31cee1efa62c +8ad2e0bda03415ab86324992bb62dfa3612d2d003765bcad1468087c27971d08bdbae5252681f0115a184f4885d444e4 +a08815af979286538c31b4aa5ec805053790af1ca58a8c4341be51136d094a8a05e569d876a079033298ad355ccb7ca8 +b96c2978d0165d619d08281d295e90df78bc2375d0afbc3142ebff9c2cd4b0f0aa97a9a0e3740bc4dce0ff8a9fac8252 +b7752cd0e582f35ab0d0036ca9c0a9fe893a6ad325164d78d865a604a85d3d23729e0362553e8b8a3d51816beeaa30cf +99cef1fafc29e7adfe247c753c475ad4bda7a5f9558b79c86e8a65968ede67adb38dc30071925c9d66a13860027a6735 +b9f6c65af178c791b6137d71980651fb09cb5b42f268999c728c6e129985a9c7d77b3dc3b50751bd29ec9ee0b3111dfc +8d73ae61fff5be883a281782698075c5650083f00399992688738856d76d159803be0059fbd9dec48f4f0432f0590bbb +a8a4a2865226de9bbf19e12c7e75318439fa6cf1cbf344d5e79a8f363439d3bc5bcf4df91b54581e7866e46db04eaf0d +894582aeff222e145f092ba15c60d3207340c38f2c6792ee2ab4d82d50fb544ae366c2985cc2b6c2f970bcc5f4b46385 +956014ba2d20a056fd86cb8c7ceeab9a2c6f905dae24fc1c5278fa5b84335148ebdefec5dcde8eb9b084700724fc93d7 +af217fe2b654eff6d11a2a79fe0339a1d4cb3708b7be9f09d852158b5a44b4f9b04406d6d67c4f144fb6b69a41ae9d0f +a90752a784bc00df94d960e523f5596695d16a534fc806179e0f878fc0e82a91b25e758e91a165debd815dd1af5f1028 +a697606fb32979549ad822b31df8eaaf50de4ead984439a0a33e955937d326519bb9f62c8243ad37f764655f8d32cc80 +a3ad4a30922e45a3e665551e5611384f1c2d414f6fa806184b0c826af05f014dc872585e255543794ee41e43cdadd856 +b29c255843a82ea74a013bac6c36a694646e61e6b9cefc4c130e2ee261e3bb5da3e0fe3ee7e6fbb009deed0530bc1c82 +87e1cc7febefa829cf050aa2aea59385d1048f8617abba691f7ea9ef58eb90ad12eeb9c439af228b0e34897ba1cf1b47 +994d3222f89e9c8c154362190be7167c8c2662f0cfa9d50eb4d8175b255ff0de09dc548ee312fc8226963c8c16f43e8b +8f1a980be640820f2d1e953264ca4c30330878971669852be3d5d6b41c488be1628b935388bfa2bd4de484acb0fe661d +854d90d0721579c8c88e147a4aa83553c960617b18075f8224b975562dccb30b0e02e81fa9df7070f356a0eeffc3b14f +8e156da9d4330a03e32a25a2f0b861fd3ea5c719fa4f834119baab6e5fa5236a9baaf0d44147bf0841418900037f6eac +96586fc49e53a6799242ddf617000db5a0ad20c6cb1686af2102623d64a71aaddb8e468b15fa6d100d0384e448548db4 +b44d8d85c8df95d504f82d597f8c515866d4d4a326fa1b816dcc5bb0cc4ef1a52647aa5d2e84c62e194c01cae0885d21 +b75c43e676a7efd199f8b32ae31f176ec667e714df355e9eecee97246f72af5bef9c5b04c11e7e90fc37bb9163f957ec +a49835ac0565a79f6a9078cf0443c5be20561a68b448289589721fded55188583f1d301925a34eea647f90a6e66c6774 +b47c17ff6824a00b8f29df0adb7f06223208d062bd703b0f763c6eee4ae62d4217eef2da4f4dde33f0b469c2f2db9e42 +957cf039cea6f6d41e368e2bd0cf77315938a0738f15ed9ca342f0a28658b763659ac1d1a85ecb362f13de12b77bb582 +903a52f8d2439fa63f59e1e9aba864d87b0464ded63814474947112375236a6f84e8fa003cc4433c8208d80e05fbd1b0 +8afd524209ff08d1eb6312b078f7afeb8e1155af649e930ab711dedda226dc2db6b0354aab9652eea7f433f90015bf7b +a95c3c9277b11bc8fe191773bf567641be57c0549913b973fb18740ff9cd7b3f7ce198fa4dc1086b2b8a446012459193 +9455ce8163fce04aeff61e7808ef3aac4725e51404f0858fe5d39d7344f55dcc7871ca332aa5cb1a63a4399529e48907 +809fa35b6958f94e781f2c584438b33f5ed528a6b492d08960cf22ecf63ea3aa1e2d29bc879e17296e0a6cc495439cb6 +b0f50774de212dd33e5837f6b496556215c665437e657f674fc5117e5c07dadbd0d057e6ac4c42d50a8eb81edfebf315 +844c65e263891d0b2fea7db6934cc4b7fb6bee2c1d0b9ab4c47f2eb3e9c5d7197dad828d38c54139123740151420280b +b13c78c9efcbb3b28eb3fe0b971380b7d5151c80948a99cd93c78b4c3ab0e86df6226a64d91e0a2ea4a1c0a46bc0404e +90300a541decad460c348b8f4257f7a29687b2362ebee8d92fd03cc0e85b285ccb0ab1cb2ff5e29c5cc5295e351017cd +ac49b409ded770c6d74f6e70104c2cdc95b7b90609da0743c9923179e8e5201ead03becc0ab10d65b3d91a5be0d52371 +a257b815bd8289dfdfc21af218aaba12ccfd84ebf77642cc4cf744d9b0174ca0b0d7ab2a545c2a314fd5f63c140f41ab +a34778d8446e4d74d8fe33de64b2694ef1e50bc140e252af6eff3ce7b57acf8b6577a02ba94b74a8ae32e5113cf0a29b +ab9e935bcf0d8607e3d66f013d9bce7909962cb7a81174923db02dc89e485c2b1c33d6065bdc7bbbe0450b5c49fbe640 +94d2c5c5c309c9eac04be4636f61bc47fd9579b47aded57cc6c736fefb8dfd8f8a5de32210f7baf2052d04c0219d3b4b +b8dda9046ae265214086355101be3460421f7cd0ed01bde9c1621da510941d42bc93cd8060fd73f374fb1b0a5f38d45e +a6674649dab5f92ab9fa811d9da1d342cf89ff6eff13ad49f4d81de45438e81a384098d3ae5ccce4c67bda5dbe246d95 +8d619f7564677bacba29c346c4ef67c211f7a3a14c73433dd1a7692e16a7e2562f1d0532454af62fc04c2fd2bb1789b0 +a2b93d2fd4c707f5908f624a0fc889e20164d3c61850af9125f47a1719757a6ce6375aa1910eafa4c1e8b6e20c312775 +a07d5585447654d82817ef4d199984542328b238157976eb9a267f0bdb2229acc25aee510be68f65a312b68fdd9e0447 +8ef55cf95e2b24d8ec88e4136399a7763bd1b73d5e90ea45e9845123e9d39a625cc336e9b67988374b8ebcbc75f2ed21 +b62c1fc32e27c767c461411b02fe9aa44a86586e1427406f4ef0b346d077db91952abce79318b382ec75b7be23058cac +b252900345f5fa15a4b77fb6af6a2d04db16e878b7bd98005333f7f6e3c8e6e46cf38fc5d1b2bc399c5c2ff4af730dc6 +a4ab5ac0cc15d3d17b1747c6e3133d586870eae0a0d9c8fa7fd990ebd4fbb62e9090557ca2792a6bc6271856aa3c9a05 +8e706b3f2e902faee10b22742c6c33bea6f670a8937c243db96885143c1db5c979e33ab73a38359b52b8d668ccd092a9 +8a6792190ee6c959d79f60c22980ca140c638d88d75660adaf9bcbe6dc4692ab5f01e0c460170f09f74d5e582e85ff1f +97ffeedfc94c98ec85ea937e064d7b290a326838e62cebd407facd1ab4f08d9c0c109d79af7cb6170fccfa6c8243c127 +b79970b67c09453614ffd83a0c923c17f857c6ce3c87a356298f8351cab0def7ed83efd4f6638f48df67e07bef4ad9d8 +b90f1931c7cf1822cc0a97401119910cdfd0482daf09a4d7612e4e05046295cfb4cc50d5214b31676bb1a1c9d15f9c7f +922921ad813c01fb5d12fa7fb7ed8e0b0abbf7b19affa190b36013c55b88fe3c7df0ae663c970eec7725ba37b95a7cb7 +a124f33e7f28feabb4089a063a08d52b7395d24eecd06857a720439dd9414b7073bb86fbd0b04e7bfac62d3dc0fdb2f2 +b252fe50bc6677c004550f240fe670974a33ffe7191ed7675da6ac36c780c2f8d02be7da5d92cbe2d0ce90147847f8b1 +ae5f8c9c56070f919f3df2d2284348fa4b2e39881f7bc42c9b2f5b7cb1ebeef8ecac000f37329bbe04cc1680cefc7f4e +b432a4575caf7337f11eecfcbd34a6705d0f82c216301725ceae2b3c9df20fa53d1ebef65513e305013d1e0c2df522b6 +b7c016fbbc4614cdbb12db1c9ac41f9a45d5e5ce82594d568a30cd2c66c3cc9d91a2c959697b67c582a0913de661505d +8f6f3e5e0347dddc1b2a34ec0dbbbb7cafbf976f19c9c902efb5c1427d1bbd4b71abd9f3fba20dda75c35a39393c989f +b0042a1d33a1ee9fdf3fad2299b8d70c4f1862d8393b5ebe3ac2189a2c5a58bb826128cd7a39b70d524a6dd976097e26 +85297c4e8ae8d9b44c3fe51aa926c77d55db766c2a9f91b659040de36e34c9a4fc6f44380f8d61704498f6fd52395a49 +8c61a988b6a00fe5a277450f30bf6daa932e42a2eae844568e3babf8815e09311f3c352dae6eb2d57a98d16b7beb2d22 +990be28aaecd932e7edb2a97b9be2789a3905cb88737b1c79881302585801c69a3dd5fb230808b39db1352fc06e0b4a8 +82fd14bdb335aa46f022dfe0ed4d631911e6b6f5eefb10d11e9e2e02a7df55012ed8162249d10b58eb76ced5a7b06cda +ac39cb058df764e161db9c39b185f09aa210bddbd66f681f1697ddbe6b305735612d5dd321d3ffbb4876771bdb321e2f +858a3f7e57ccb81387caf8e89f9b6039e9aadeab06886d8688fe6427151a59ab2e77e85ba850c67d099965426c97779a +b57fb9ea623cec432946819937c6bded0b5d03c8c67b52b44a4b67d34adfb055e6cabca67a48e4d859b4be45162c5083 +b84d2990b563d6d7fe1f4c1894989db25b81745090b94b1fe2ef708ac3b2110ef93d647820b2a51fcf78e3f00fef5412 +817d85b9f5e1521733d2b1fa6d4f4957ac445dc803f97fc495e20b819b14e651332f9e0573d684b854fd47824c53f0e8 +b09e18e97e93a8523101af594422fb71afc5b8826002314269016fcc1b44002d91bcb7c90d923d460f0cc03bddfe9af1 +b867cbede82102de7cf6cd0dae68506869576eaa66c3fc806e73585310602682fc912dc37adf5ff6f0f34a07831735b1 +b1126255798368b692f2796a3470ed16e5ffdee2d8c9e0f7ee3d2e92950c3e6365c32895171c3494aff2a6d6356f7e25 +b05f0a0996dec16335c770a5df3f0b08e20020c838c2caaa1d3a4a2490ede98552f5de349de2ce6e4c4a839731d80919 +98c512bb91c8fa191120ddf5d63c88076581cf41e15eec3c168822f12b3dd0ce4d6df74a7e3093d3e35cad1cb3135421 +84ce38fd97f7f90012c2c1e59a67bf9f465a7ccfb6f308bdd0446cc82b8a26ff7c30e5c7cc375011718cad1b31adaa9f +93139db52c9fb96dee97a0825f21e34c5d6d36838e1e42f4d12d01eacbe94426c85a811fe16ca78e89e08f1c27383d28 +81454037b1e7a1765f67e4288b8742eebf6d864d9b0f508ab44fa3243168ce0ed30cb5f33dfcdb995cd2c2710ff97a6d +828deb2a26efb2ff1842f735e2cc27162360f619b6e3e27a85bedf384912d4726bb2759a3016937973092ece1bf90540 +87e5a7d4e7bd301078f625d9a99b99e6e8e1207c9f8a679f8ebbbfb467bfa0b5f7ef4a4d577c7d2670efa88221153012 +b9dc9d0ea48deee201e34379447bec789c8924aecd030eeb93db159af77eff230976ef60ea9f4b4a9e9e95c1f9f4284e +aa6528268d46bf0627d87d58e243d3ac34b863513c725908a2617e4c6a46ccb1d8c8334bd6dd0eea7ffebec44259dae5 +8d26c9ce07293f6a32a664d31e6df9a7ace47e6c38001635918efd9872aceab62de7757b13b783d422eb67bd28ce7bbb +b0d3ca88d9829a7459b89b0dcbdb8bbb5180b00d750bd959bd110f53c2dd5d4db554b6005c4765fbe7ec5903669e5ebc +a94d1c72bf3b2dc6bfebc9dee40f6a89a516b252bd9f4fad96f156e3dbfc151a9b8a02324d764c7656d59230a18eb61f +88996e79171e30b16505638d8ecb25afd875e5f3cc3e29860937f2b5e751c66e78dc77f744a0cc454a8a655142a93ffb +af4d94f342665fe7ecda318de6cf1bc1c40c37dd83d060fedaf827459728152b5f0e280286ff5e6a0012036f6715f53f +96beaa7a2d565ec14a4e5cb895d33624c69da56b75c8d06ac729cb6d0cb64470ed4f9b0387083cd827b1609c8cabde8c +96b773fa2fcb7377bf71a7e286f37f1f24ee42cba5b4f33903c4566e5e5bcc501ea360e3c8435749107c3de84e272d8e +a69ac6218454c3f40ad0beb48821a218fb0a4f33ebade986d2fffd9a3900d8cfa613bc71676c46cfeaa5f644d1f239a9 +857f139c08fcc45370f448ce3e4915bcb30f23daa4134407fc6d78efac7d718b2cd89e9a743eec7bf2cc0eccf55eb907 +adeeba36af137fd3c371a2adbefea614c3ae3a69f8755ce892d0dd7102fb60717f5245d30119c69c582804e7e56f1626 +afa97ca3548b35aeda6bfed7fbb39af907ed82a09348004d5705b4bb000173270ce44eb5d181819088aa5a2f20a547a2 +8423bd2d07073b0e87819b4e81997e4d3188b0a5592621a30981dc0a5a9d0578fde1638a364f015078a001afb00891c2 +b92e9d4ec3966981ee574695d6e4865810b8e75313e48c1e4bc5eebae77eb28740e97ecc3e5c42040f9eb1ee4b13b0ea +b07b218321d54cecfcd2ed54a5fd588a6be8d7a5b6a66dff7facfe061222c40553e076e57cbdfa0bdb08e0a009c94ba5 +a71e1ae4d6096eac9ea4c21f621c875423de7c620544e520fb6ec3cb41a78554aedd79493cbd2c2ba4f0387f902ddd2a +807cdac291246a02f60c8937532c8969e689b1cfe811f239bfdee0791e7aa0545e9686cfb9ed0c1df84748e5efa5e3da +a1faeb4504c057304d27d54fb3ec681462384a354a4f0b6c759d4fa313253a789250c6b0f44f751b0718592637438a19 +996bcd3215182d49f1cd15a05e1e0a4bf57e264400bf14f7253c6611d2571de7130cce81fd28e0411e0a80e9054f4f98 +89d15b38f14bcd46f4b2dcae82b0e7bf9a35e40bf57aa947e9c4a8f87a440b5cea95229708de08ca596762062c34aaa0 +8d8ddcaf79374c750b8b0b3d196acb6bb921e51b4619876a29d09161ba82a42271066187211ef746f9f40a5ca17b75f7 +a3dc7f70f3a6c7edc483e712770abbaa94bfa3174cfee872b2cc011b267e0ef9baa1ab49e4a6c6c30dbba0e0a1237117 +aa9e958bbdcb192b19c43fc6fd34afcd754949fdada98e9f4848e8db0e23acb27d19dd073c951a8819000f2356aa22e1 +a4714e45ec853eadfe5c3bee7f683b81f97857bbd7833192a48936dd1460aee68f700a21658658b74b737c4fecf90c7f +a1ecab4215c1892e4a8ff3405d710163875e5dfef8a8cb84f5cac4e317d89c7696e3f496ed1747ca6f52b304190f4ba1 +b9b48943eca3686219575026d395b969e6ff8159dc5317005df090e79d26901984e40ae4b1af060ed3ff6f42e0417d76 +9644b9f90a66edb0396abd8c00066886f978ebf56fc22081031fbc9ce371bf9b04aa5a4ef59e59319b3a05bb7fb88b43 +b2bb14f1c055a78596488e4e2d4135a6470c1ee43961952160b8498f674a4d23040606e937c02c1fc23dbd47e9bd4633 +8c61f2fce9a42b94a389c7e52d7d093fc011099d0f4914f6d6f05b631df7b88182826edf9bbb1225971a080ca5c0d15a +aa6a7b8499cc7d256043eacad18528d38bf3be970bea4c6d4cb886690280bdb373688ceba3e506471e1d9493dc76f3f4 +8127703363b3b35b06762c2353d4de82b7b85bb860db1028d3640f46bdb78f2d104fa77ee3e0d9db83833d2b12a966f8 +b7b01f5909f2c66ae0fab156be5d79954e3a304615e1fe55945049dd4bd95f973bb3821117eb54db7e9ed1ee9a527652 +8be47ba5dfe212420649193490838670c40540e0ea24adbab18c4a66e7ac3dcf94f068dec2533b60e08c1f64e7533e54 +905a6c7e24b86aa54a05c329a6b4616d335bb0b1f1e9987562eee0acf82ad302c7c44981a1dd6b24c6121ca12fb92996 +86969ccfd91deed93b355a2c21319e3bb08cc652b741463bf68c626b7ba2afce3f7cc397f2fb74588c2893477c948ae2 +b5a9d20eb12c331d0d300fd4b85b0ac0bb74573178a5fac8ec9dce5e95acba07fab444260355ece442a846737a2dcd1c +a13497c11df21b11fc1a63b0ffdcf7f432da4dc2c98f8d07d36da4fa68aceb57af2158088e5b05e334fe0f264aeb7a97 +882e4597cc66498a45e86a2ed9ee24652da4699af00ad35f73b5e74fde6ac3cee70630962d5ddd86162d4aaf11bbc11c +b748858c2bafa4a14ce44af35195e9c52aa75e109719243bbe278095acbfd6a7ae7e084caf8dae6939039b5a4e8fd675 +83a2e0524507e74f51fe976441108f8226ba1b3a33f4e16ec45c5661ce80cb1840a93d17122cb8ca9e0f80d14f69877d +846cd2946c93ee5f24243d9ebc69936b3a1a6d59f45fec6c79b1eddf15ce30a8e73ad03cf606ee66baea3d8ff115f70f +8d98d0a3a94f6efe158f8423c041b546416145c5c2254bfa157efea0d1c99fe58acc7df6424ef29f75960b18d664ea4e +a39fa47e4b79f54dbf59d0b1726f1e78bc219fcfc56ad238c84b4b610e7892ff1e65d537baf5118a32f5e2eb80d5ee0c +8c30969a4519131de5e30121c84c04f67b98c8ad109fa4710dd3149cae303d51778add3f258f0482f1c89c169824dffc +af7f80d141ceb78b4762015de17fef49d7ff6202d292e9604deb508272ee7569f7fd5be3b2438da1dfecf0c26533ef86 +97cf82f70128251944d79b8845506975405bd720e150d836205b048ff36ba8801eb74cdcc6425f28f6bc0acec0a81463 +8c276c876eb88688957d1868bf3a1462375e608ff72b49870a5dac82cbf6584e00e3f36f236f732348a47502ccf9539d +964765f1a5c8a41d8025ddf56dc01b78424703d8a64a4e5539e477cb2445cb541c70127c561e717256d13f91a830ba83 +a2aacd9e21b8c8efaf2319611addea1b9f41430aee42e7f2a640cc693aa395287cc8fdc2806b76b577d84fbd05378ead +ab11eabbf5be4345a77323a3b75f9ee93b011fd2a9d0154e88183cafe47f82a7888666af16b40d3cb677c94bcc755ff7 +a0bfe715a7af5a29b1b6148b8cbee585d2b49fa6ce59bcd173ea3bbc60d71a62f9da27ffcbbd5a6da75502112fe44d70 +902e6cc38ee42245103d90b65028a471bc7a48b825599d361aa81d8c56e0fcf9fbe8d4c13802040d2cfb85b7e022eea1 +8832e2b5014fdef4003bdbb87e3298fdbdbbe49673f6b66e2373f1cb2605f9c4af2cdf9bfd45d1993208681d29ee1c9d +a7d39d3fa1ec1e0c87730fa43d4900e91932d1cafb36c76b2934907becf7d15a1d84d7234591ad4c322b5a24673bba8d +836ed5f09d99624204aa3aa7ac601980fda223f3b4b96b4a8fb235c574a3545d518787c12f81bd5851987f2860d41886 +94235e94445e6086f6e9331923262070a4c2ed930ec519eabb8a30133bd4fc6debb99185f4b668431fae1b485c5c81b7 +9828ffe20b9405f117dac044159be2d3c6e2b50ecdd1651d6a73f7633e6e2a7ba3d783ae939973604446d3a1ef0fb20f +92f03dc365dfe9154743ca70e6dd2758f064e3286fc543cf8c50f68effdf7c554bd17b3507c6ff4127046d9bbb5522ef +91ed07df479d8eb3d31292a0e987672a7f3d45ecafe72935b7abbc3f23493605134ce573f309e226c9efe830b6868220 +93bee582661e6d6cefeff29002afc2f36dd2c13dbf33f0574c35b290ddc426170a5f7f196369ad592efcd72cfb6f8fc0 +89a51467d966f48fed15dea5a12dda54d0015f69e2169b5e34f44c7b5a5d4c282d6f138116a0cd06a8476980e420f8d8 +b8ccebc14b6679ba2399370848864f15f63512fd6139df7359b7b93e82c1007fd85137ecb0597294b46643e1a9e7ab5e +841fa301567fc57b2cd09508ce75326684e12bfb8add671dc208f579b2500b93d5b641e9f59bba798ed4ed1259757f7d +b3cb45c15eb00b4ccb7013299f761cb8fefc17adf6db50e9ecb8abe927a3bc7f28e359e64693813e078e1dac800ad55b +96e55d3b9f445f5679e34fa5425b3e87cb221cfbdd07f8353868c7f7f4ba388ee3841cb9a1d638583bc20d03a9d071f2 +a7dee9377de740270c5b57cf86699004ba8dc2766af56b388b5cb0814ec71bb99ecf43ee3d82a552733854ecc7def0fe +b129dfff23b3c1c95ddb214c4711961fcb129efe2b6557ec9e116ada909593d0d2eec2c628434493393c58c52aa86847 +aed2670e201cb3e38a8be3c86735a4d76255e1e5a4c67b91df6ed262d09c8d10b0a3891da3e6ab934058cc9a7178931b +b20b8921ae52e5b3c94fa3a8b46489044174f7b897779e7763d6eb419e808d76705b7e7ba5131576f425aa81b6b0de53 +a7e45bbc3ba1bc36617291ba7663806e247f1b57a89e31520c64a90cbf8d426cac2e2f381338baf78c8f92fdbbcb7026 +a99e651e73a507e9e663e2364fcc193ec77e8afdc08c2bed6ad864e49b537ec31e9114ee72291a7657899f2033a849e2 +af966033636c2e9e8280d173f556fe07f8b6940bbcf6b2df7e2165c30bea66cced2596f6c17ca7c1aa0e614174953ba9 +b69ca7a79e3d55ef21e0ebdc6f0c4bd17182d30cf6290cccca7d2551c91c12b966020d8e40e4ee4179488c9809c03ae4 +b981cd36244e035fef043f70b1d7188d7cd045b4de0581c459fc5730e10eb7f3d5893b54cc4243849c0855e4e621167a +b20fea858a36921b35a3051ce787b73f70fdecd3fef283c15a2eb1bffb1dcba5991eee4a047ce4e87802da923fd9457b +b040e6f2e56dc1860274c263d4045837456f74b354a679f6b5ea70919835ebe5d32bf1f519e218730096c98ff396dc9d +8d2dd60e702c923a7204b530e7d6c193c6f93ca648c4f7bb38f4edbeb0aaed84184213afafb8db6aeb9197c24364276c +95dfa7348709e43d71285b28a0bfad3ca805b6ed4ae99753e9f736c79d58a35a3a50b42760ccdd03eda50f6e59494968 +b8585632a13f18c139a411bb2f02df809591834d127cd1ff081e26d0abfe0e3fbb54abea26538b25a0dcb4d7e969590e +b46ba47858a29c6d523c9982660949567666daf2582b93393a4802a9e077eedbc0d49d454731696bc8e46ca50c7caa40 +84b756b901b98a4404e58d70f39f6ccac877146c866732ae65e7e82727448d1550343bf7cdff1bfd4ee1ed73793db255 +83e5be888eaf877a2c755897410865f64a6d1169a8ccf0336092f3932abab915e542ab75a35ffe016042340d581ee987 +8cb274fc39285aed451a7def72cfbf73168ee10be02affe355a2bf87cf361a81ad284e9334cf00c5bf99a13d9f75e116 +91ff6220924b94ae13f50eeac16a159232e4f16a73fbd5c22c0e185cd1998403904d36bad203baa82b85819ee4a8ac10 +87f46e08e09aea2ab37b55fc300689d9b58ff3e72f1cffe023386035888f714fac4673c7c5193d3f3f3c568c640694f0 +835d7d84ca7641e1b15095830114aa6072fe12260d2202456cafe2308c22651af9ffbcf6b7e56af97167dd0c4e2a4cf2 +91202183f79794f114fd9e3b9bd05553c0e8985919965101a57d97ef666b028863e6cea9735af016dc1864f1542dee51 +81ab2b02a9b0a490a74ae615ddd4fe560734c1bfdde6b8dd13303c1481ba0e8ab14473535a93cfe4e824a0ab29445f8c +8a32d73f4fc006551d4e2c61eec6130355ec9b8c39a65c24ec1edc00e80155ca83a8ef2455e892521a3d47634d82a987 +af70d7b8f13bc90193cc1cfb0c400c4224cf10f1887848aa93e6380f7087782fc41a159926ab53c53eb95c2383b1a849 +989bf42f9d357c51774f1c7c0f7c0c46a8cb7398a74497141c32685be098e38b4230ffe833a6d880ec391a35b1a747b6 +94cb6715ee95700020c630b8c19e35f231de970219bd7e6ba7ced01899197da473b6c45cacfab0d652ddaf547b4ea58c +b12e3331f1f7d7458393a785e22e9a5e1d1daea521b4e78c0ee8ca59b41ade1735a29820e18f6afb2f2c3c56fecc16b6 +ad4b7cf654349d136fb41fb0dd65b588199f68b462b05f5c4e5c2b468bfaa6c26329033e3c3f7873dc8ace89cf873ea5 +a3279969e1ab596df0559ffc5ac7a6dc849680354e01c3f4fd34c6413a3f9f046f89c1e1be0b315d8b6dfab3d23d5c14 +ac74cc5562836ed89d09a9ae6a3644c936d64bdda9e77659d9982f1be29541b03ef2723236d5465e398373ea19a4ccc6 +98138ebce1af531dd8b631b3e74c84f0c700355a2a9bde31e5e51bb10c8bbd766559c63f6041f4002568803fe08438e0 +9006445da131349fe5714e0777a4f82a82da343612589a0c1596393e8b6894ce1cf42784f95ff67a8384ffe1f1a4ad76 +88502a84a85e4ce54cfed297b5d355867cc770a8ffd0714a6f23b1ab320a9903c6e42809e034bb67dbf94c4fc0d9c790 +aa8b4bf123d1a6ccaa44b86be8f980005f2a0a388a76cb111b0e85cd072ef64167fb0c097c7b23c4bca64c0260f6cce0 +ad49eb35dfea9feabb513a78dd1152ad7eba22fbb02a80cefc494a7037699c8df81202dfec12acc1b9e33ad680cb72d2 +8694da730231b29afd5196371ddcb15b4dcc499574bdd063f4864ab80749833ea38ab8b0ca1629a367fe378e87a60a86 +8eca7b488e810c479e7e32e24b8afcd837f7df183fe4f621a0336b53a9ed77603c84bdc365d8be68179a32b71a1deb7e +8875cd3e23c7e1af55af1b091025a08255743984186770bcd43f30b4a58d175cfdf1984bad97a15e08dac2da27198c3d +abdafcf58ec72997e494d4714645f40d09dcd0fbd0733e640eca44eeea67c25bb0c270299c459991f2fae59d13b4f4d5 +8f040970141e61489284f3efd907705eae6ec757fe8e1d284eac123d313e9ac1e8dc14ae3f04d281e1effc49d5d2f51d +a7ff115f0d2dbf66c0e8770b3d05157b37357b9e33e9a447f0f3fa9da69ad04e371fd1e4848cfb9e8d05e3165bd969d8 +a39b1a8c39d317fcc97bf6c396e6ed4a85640aeeadbf45166bd02bc3bdfb6266509159c03afd492e642384c635b824c0 +a2e1b90f3dd2d0038eaa5be52127844ccf35d997143179d95ffd3749c0896398b130094d01eb1bb31ffe80ef34b42b48 +a2bbe31f89b0c3c375ffaf63c8b7831860a921d5e388eb7907dbf61f2601ea40db86bb3952ecaa26a5eca4317a848ff9 +87d885bb0f2ce04b40ce94d2557c15f1698dc652e938f9a2d69a73ccf4899e08eafa1a59a20cae92823795f5b94f04b9 +8f7746370f8a24a2889d351f3e36b8a7d60e75e50e8f5abeea7dafc75441e95915721654e61ceac51bb6f112780d352c +a7272847526ed3d9e0d0fea1d8685b07b5b908971490bf8a46748c8b1783c629b8644feb5bac772ae615daae383d5e72 +978c9aa2996d8bd6fda7e0393fa8b38747f8f99712427705c00f6e9a12c36f8d8b4cedb03fcb9867155cbddb5200e6e1 +a4dec4a2354b2b32434c5bcdc380bf84580c6f9940f94dc0498a5bfe89c675a0921e66b807a3d859a6059a464cb2a9ac +99459ddecc7abce437f68722dae556d8ffaf8ed974f459e52e6d4a64f176caa4d42c2f2ec57e8a5b5f2034638e8acb0a +928c68c0c9213fe6258ab5bb0c693d97203d15da359784de7824dec143212da57d062a1fc70a79172cee31adc7aff382 +aad3f318f1622ea87e12541dfd982d71629b8f1ded4c301f9f6b6af9432716ad057773c33bdaa6f15dc151b0ee4505ea +8eb8e978f149a983fd6ad01773f9aacf57bd0cc622d8a301e404184b37e610123dd081faeda571a0ab1f149a3960af10 +851e7191d7b94bd422bcece5b92609fc1b1c8556229bc53e32963b2d2fd1cacd8ce5da9040b599eca6e610540f8a7987 +9414157fe9d50e5a0b5a7397417681bcb3a651eec1cab63f2a88d5df68ab1fef6e4c1d7ba657cbaf241a7cb790297633 +b5cb2dafdc5408959780754a58b2da55b2a9136672ebca42f34da4e329ddc89360e7218cde3efdbf784ddb390deacc57 +ac6b70f65503a8e94b773fda3e72615745824930114fe72b6d833484285462392617c1b2eea4a250fedbee88f503f3ba +b0829a5312f9ac6c06fddee2f835a3452fe994f6d42c9edfc390d7d5b3240ca544433b544cbbddd6516b38a6d5d7c21d +95f8e2c59905957e34d53be3d6fb85732f834e2cb9ab4c333fea2f502452a87ccd035fc9075d7c0bd8530bb0a0c96527 +b93f279b7045f2d97c674495f6e69a3e352f32f43cc60300193b936c2850b2805c15457251f7e3f633f435cb2b60405c +915abf16cba1a0b655b92a8a70c03e7fb306b86f3bbfb66967ca63e64c003b59c7a5953675efa4fa0bce9bed536b6700 +ac2047f50a319d09df1ec44d71afdcec5ac3bd2765dc98aba347734aa780863545df9f6d71214d443e3f37edc0dae45a +ad49c74ddb24c8a26b14ec08bc807313c77c5967fbb36237f55994d7511bbac8d7e7b9b8ec53eb1b3b066989f078dbd9 +961483105f605e959213fe9e8a52b76dac62d7efd2319ec71fc4e92d68fbe44cd2f65d7adefb2eb64d591b91648b8085 +b67fcafc97d8df2b3075bbff7b3d7471dbf1f3048f309e55d5e2c5bcbc7a73aebcb0697859be9f387cbc7ce98041e154 +8da70ac16468cab6066992389cb37c79ff5e0babbe67d76878aef9408b9597a3dc2eb5de87428bc761a0d78957b0eb28 +aec0ce89770d299b631f15ae12f94b1e1014ac57d38fcf037c2c7712d770d074affa06e97c60691bad8733874b6ad2ed +8b702c85fa4c915a09fc86507f44d7aeda0993b77af87780d70cc98d580c6e996b64b7c16cdb4dd4562cb0f75da36ee7 +aaeb43aa472aac2253e211fd1066c3a5422ea041cef20168702d0618a1a742a44f7fb30a76677640fea1a24e7fae1996 +a8820e92825d6e02b9b4ad5ebc86161d3244cddd3d244333ba1576b6ae10948145b68d9e926bf6b7a2c25dab4cf43f3e +8ffdae28a1f1d15d7ffa473628a66ee9a739073f59ba781248286b39cb8f7255f66d62337064246713cbb5017e615174 +adfc5dd142b7911326d8424881d5d92006f3b17de4cce91674d6ea37f00fbb266c791ac13f6c7a0f61d04f2a952e6a04 +87f98982444bf661f539bec73a10256f079a4baa88a1cea0351ae3de929e1c500485b2d1b5d933063cd7d9123d5050e4 +8f217ba4dd404c5ee384f0c9a126686db001ff0344c01c82174c5e5ef89d1a241b146008c534b13a0da6c8afe7450fbb +afc85476dddaf1cbb4ba8b22186789f3818c7964f9f613e55010278800cd95422702248bdf9c73760702ef24854795ec +a59e0f6ac2ccdfbd01f002008034390c0ea78716f5e0de4e474e3558755705c9c7afb6e3c5c4370e7bbc85958a9c7a63 +97c0695c58d792ec31d9b86d3b2fc1382f0855057b24d5f6a54c41f76f9e2f52882cadc89a8b2f121530e7f1393faa95 +8e49112de0b2649c08a96cf737af68fa8055f1af594846a2d0534c94df6f926f200405edaa6e6ac9db7e380707a2571d +99a1bd83a7ac5f8d77ddf044c80ebfc5745b998714696d67b94d185c97e9d6db989bacac646d9def463127a8b2febc00 +aba80725f9f9f7abe10760eca73ba427ca8df864a157122eb9af828a05b0199de3add02019a297750bdab5380e505c58 +ae18f62573275c1eb268f74c5e54e8958547f9e7d1d36a05b084eb53e5704fafe2200b8aff95cc7e9af5be2391c42b7c +908b8031d09d22b2aefeaa876a998e0a97c7a1070aad9e9c97836cc5aa6d2d5ef94230e1222074837b5e21b4e6490f01 +b3132282e8b41ca6789ec5c43c1fecf3a65b8eefbc2f3d10f746a843b9ba4ce6db664678e75e424f7b11a00c1440de15 +a1eb49440cc106ebc09cf198c93e8070271eb5a936d31c04858a2b311a037350100c7957d5545c9653f396aa968b91f4 +81df6ad1bdd5eee4cc2f94318467b8602d15cc1be2b48b09ade12cc46ee05cbaaf77a20397e5015030b1f1db5dd9dac0 +87236c68a2a93c8442d15d7f1d1dc01d1fd123439c183e1d843f4ddd2bcf638c128f66f1ef9b710e5d1f64a52726007a +84f2e7f85563bb2f61b10a712c7605d63f79af5be0dba056814fd3efebc20e9c53227c56577b72c68d185571b775eff6 +a36d4ae06688ece2927aeb2c7f058a3cd2aa1de1601282d4e688e1d76ef20728b892928deda2314eba41675eba3912f1 +b8326dcbcdcfce017b263c456c47692fb476c4225c95981666fff0b7d4522fc23b7f12273f0f47cf0442662124e6648f +84c66463ab277cda2cc7007d0509269e89cdd41c5e0d3773a92615f0fc5da63811186b05d7a11088048a5d4834a7e0df +b20d3571d970712ef4699b0e7034fd269c361f53e1572e2ea2676b4245e992d43b8b5931a801439a44d977a988cc360b +94dba6007e6d4998ca1eb84aa8e2a7e9f5c164b9d80df2825f2208ce5640a05aacac2e4f08918268990f43ae1ccab69a +a1c25f0b3ef9d1982153207570d9ce8d692e1b6963b509958dc4d9bcd80074bb221c46804a6d9a29e76149cc7787c282 +8857748fcdab1199fc96084323a81d3bd8b5a7f0b1abc5bc3b5252a19268344e2e7d2d086c90fc9b5fa4b92feedb93a4 +8b9c1d841447354b6c086549e4d1d435ab64c13933488c34bc30f0f6eb36c5c5b838b7b6bb018542247edd1ada091045 +8f5b655416da0e719a204fc567e93792c301acb4374cf7bbabc6ce51dbeaaadfd75c2db0e16ce073ab8e91fd3d7ea9d4 +90f2846b19be46a75c5cd0cafefcf9192e6fd80c479e8d6320c4b8d8d7d96703c9e77ff31a67afa9858e6b7bde1f7cce +a53e383947fd98aa1a55ac956214b46b20a52758461e8ba41341a23a835ebb713038bf048edb1202bbfd0b56a96bf292 +9542d7debbcfb9cda6fa279c699a7b655c03b9a9b456a5d3cfc41a826c94eafa43e01155a29e39ff0bcd965f4c0c512d +a43792864ec5fc549f7afc02622454afc0e425c310c4039ba615067243ebb26a4c7ebfd19bd4d57ff412a4bb2a7958a0 +b85123950e30c048465bf32365d24a5d4b21fffc6183cdbf71643a07b87463989b72dd9a6a47f134856f704909a6b38f +944ea689aec1376f855c0bc9c51378ad06ff758a2c075b95a60b535b88b36eca0be11e4edb5152e98cb2137d6e749f27 +a6bef52cda22325e4c62d323e2a0e3fa91c5552fcfce951edfd52ad6f652bfdcc2341f1cd349e6b5d447924dc569bfe2 +b56bff8ffe981bfcb30791836da10b87f2ccbe17ed969e7f7a650af07d27ae0223805b1264d985148208483be50578a6 +8b209cac898dd580c82d854a553e2517497ad1a4cd198e1360b8b50639b380aee70ee4b87625d9b2278228ff644cd25c +877cce233fec74c7158b3c5bf108365e98238418b8a71f058f1aca44a0fd3a1021e3e9025bd11fe244d9fe0f5034ce7f +b1b871aeedb03d6f6accc99816b89f5958178738d8d8cd9717527d04363c80fdb5f6848122ae19fdbc450cfa11e753c8 +858aca51b9e5b0a724e88688d5124eb24c9faf01a3d465e74d31de6da315f311143f22f60201ea09f62c92f61f09d889 +8521d409615dfc8c8289e00f6aaa6297c2c4e1439b25952afd76aac641b81c70b9cef07cd58c1c0198382bddd2bd8544 +88647c3e41666b88acca42505f1f5da226937e0522b538fe0cebb724e9a99730ca2522989e94a96cac94109aef675c0f +b417fdaf719caf38854e89ce52031b30ce61a632e6c3135adec9002280e022d82ab0ea4ac5ebdb21f1f0169e4c37bcda +9367a6feb5e23ea2eab8ddd5e7bdf32b4d2419fad1c71a1ed327b77362d8942dad971a1c2e6f7073885149cdf0a0c339 +a71c5c08d50c57d094d6a4f02e97d3799bada92f238ffc07bd223bbe8379507b7310d20b28f5bbbf331e5e153515e491 +9630a9a3bcb044b51299c4d3d3388a4ff47308dd27be3229601985478c0f6b55faa7e20815d8694f910611396a9d0d45 +b0bfaf56a5aa59b48960aa7c1617e832e65c823523fb2a5cd44ba606800501cf873e8db1d0dda64065285743dc40786e diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs index 78aa0803da4..85ff50211ea 100644 --- a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs @@ -45,12 +45,12 @@ pub enum FftError { } static KZG_SETTINGS: LazyLock = LazyLock::new(|| { - KzgSettings::parse_kzg_trusted_setup(TRUSTED_SETUP) + KzgSettings::parse_kzg_trusted_setup(TRUSTED_SETUP, 0) .unwrap_or_else(|error| panic!("Failed to load trusted setup: {error}.")) }); fn blob_to_kzg_commitment(blob: &Blob) -> Result { - Ok(KzgCommitment::blob_to_kzg_commitment(blob, &KZG_SETTINGS)?) + Ok(KZG_SETTINGS.blob_to_kzg_commitment(blob)?) } fn pad_bytes(input_bytes: Vec, length: usize) -> Vec { @@ -225,7 +225,7 @@ pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result Date: Sun, 19 Oct 2025 16:13:15 +0300 Subject: [PATCH 066/313] papyrus_node: Papyrus cleanup - papyrus_state.rs (#9629) --- crates/apollo_batcher/src/block_builder.rs | 2 +- .../src/{papyrus_state.rs => apollo_state.rs} | 2 +- .../src/{papyrus_state_test.rs => apollo_state_test.rs} | 2 +- crates/apollo_state_reader/src/lib.rs | 2 +- crates/native_blockifier/src/py_block_executor.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename crates/apollo_state_reader/src/{papyrus_state.rs => apollo_state.rs} (99%) rename crates/apollo_state_reader/src/{papyrus_state_test.rs => apollo_state_test.rs} (98%) diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index 0a3a41e9619..5fe5a19f6ec 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -12,7 +12,7 @@ use apollo_class_manager_types::transaction_converter::{ }; use apollo_class_manager_types::SharedClassManagerClient; use apollo_infra_utils::tracing::LogCompatibleToStringExt; -use apollo_state_reader::papyrus_state::{ApolloReader, ClassReader}; +use apollo_state_reader::apollo_state::{ApolloReader, ClassReader}; use apollo_storage::StorageReader; use async_trait::async_trait; use blockifier::blockifier::concurrent_transaction_executor::ConcurrentTransactionExecutor; diff --git a/crates/apollo_state_reader/src/papyrus_state.rs b/crates/apollo_state_reader/src/apollo_state.rs similarity index 99% rename from crates/apollo_state_reader/src/papyrus_state.rs rename to crates/apollo_state_reader/src/apollo_state.rs index f3eed8942dc..73336578a18 100644 --- a/crates/apollo_state_reader/src/papyrus_state.rs +++ b/crates/apollo_state_reader/src/apollo_state.rs @@ -24,7 +24,7 @@ use starknet_api::state::{SierraContractClass, StateNumber, StorageKey}; use starknet_types_core::felt::Felt; #[cfg(test)] -#[path = "papyrus_state_test.rs"] +#[path = "apollo_state_test.rs"] mod test; type RawApolloReader<'env> = apollo_storage::StorageTxn<'env, RO>; diff --git a/crates/apollo_state_reader/src/papyrus_state_test.rs b/crates/apollo_state_reader/src/apollo_state_test.rs similarity index 98% rename from crates/apollo_state_reader/src/papyrus_state_test.rs rename to crates/apollo_state_reader/src/apollo_state_test.rs index ad926f1ee17..d8d7c0db766 100644 --- a/crates/apollo_state_reader/src/papyrus_state_test.rs +++ b/crates/apollo_state_reader/src/apollo_state_test.rs @@ -19,7 +19,7 @@ use starknet_api::contract_class::ContractClass; use starknet_api::state::{StateDiff, StorageKey}; use starknet_api::{calldata, felt}; -use crate::papyrus_state::ApolloReader; +use crate::apollo_state::ApolloReader; #[test] fn test_entry_point_with_papyrus_state() -> apollo_storage::StorageResult<()> { diff --git a/crates/apollo_state_reader/src/lib.rs b/crates/apollo_state_reader/src/lib.rs index 378444d69a2..2f4fcab7c63 100644 --- a/crates/apollo_state_reader/src/lib.rs +++ b/crates/apollo_state_reader/src/lib.rs @@ -1 +1 @@ -pub mod papyrus_state; +pub mod apollo_state; diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index aec6db91551..8b147f273c9 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -2,7 +2,7 @@ use std::str::FromStr; -use apollo_state_reader::papyrus_state::ApolloReader; +use apollo_state_reader::apollo_state::ApolloReader; use blockifier::blockifier::config::{ContractClassManagerConfig, TransactionExecutorConfig}; use blockifier::blockifier::transaction_executor::{ BlockExecutionSummary, From 2706011aee467f155e2867d32975cca7e81fbce2 Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Sun, 19 Oct 2025 16:26:11 +0300 Subject: [PATCH 067/313] apollo_batcher: fix config again Signed-off-by: Dori Medini --- crates/apollo_batcher/src/config.rs | 113 ------------------ crates/apollo_batcher_config/src/config.rs | 6 + .../apollo_node/resources/config_schema.json | 12 +- 3 files changed, 12 insertions(+), 119 deletions(-) delete mode 100644 crates/apollo_batcher/src/config.rs diff --git a/crates/apollo_batcher/src/config.rs b/crates/apollo_batcher/src/config.rs deleted file mode 100644 index 86da97ab951..00000000000 --- a/crates/apollo_batcher/src/config.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::collections::BTreeMap; - -use apollo_config::dumping::{prepend_sub_config_name, ser_param, SerializeConfig}; -use apollo_config::{ParamPath, ParamPrivacyInput, SerializedParam}; -use blockifier::blockifier::config::ContractClassManagerConfig; -use serde::{Deserialize, Serialize}; -use validator::{Validate, ValidationError}; - -use crate::block_builder::BlockBuilderConfig; -use crate::pre_confirmed_block_writer::PreconfirmedBlockWriterConfig; -use crate::pre_confirmed_cende_client::PreconfirmedCendeConfig; - -/// The batcher related configuration. -#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] -#[validate(schema(function = "validate_batcher_config"))] -pub struct BatcherConfig { - pub storage: apollo_storage::StorageConfig, - pub outstream_content_buffer_size: usize, - pub input_stream_content_buffer_size: usize, - pub block_builder_config: BlockBuilderConfig, - pub pre_confirmed_block_writer_config: PreconfirmedBlockWriterConfig, - pub contract_class_manager_config: ContractClassManagerConfig, - pub max_l1_handler_txs_per_block_proposal: usize, - pub pre_confirmed_cende_config: PreconfirmedCendeConfig, - pub propose_l1_txs_every: u64, -} - -impl SerializeConfig for BatcherConfig { - fn dump(&self) -> BTreeMap { - // TODO(yair): create nicer function to append sub configs. - let mut dump = BTreeMap::from([ - ser_param( - "outstream_content_buffer_size", - &self.outstream_content_buffer_size, - "The maximum number of items to include in a single get_proposal_content response.", - ParamPrivacyInput::Public, - ), - ser_param( - "input_stream_content_buffer_size", - &self.input_stream_content_buffer_size, - "Sets the buffer size for the input transaction channel. Adding more transactions \ - beyond this limit will block until space is available.", - ParamPrivacyInput::Public, - ), - ser_param( - "max_l1_handler_txs_per_block_proposal", - &self.max_l1_handler_txs_per_block_proposal, - "The maximum number of L1 handler transactions to include in a block proposal.", - ParamPrivacyInput::Public, - ), - ser_param( - "propose_l1_txs_every", - &self.propose_l1_txs_every, - "Only propose L1 transactions every N proposals.", - ParamPrivacyInput::Public, - ), - ]); - dump.append(&mut prepend_sub_config_name(self.storage.dump(), "storage")); - dump.append(&mut prepend_sub_config_name( - self.block_builder_config.dump(), - "block_builder_config", - )); - dump.append(&mut prepend_sub_config_name( - self.pre_confirmed_block_writer_config.dump(), - "pre_confirmed_block_writer_config", - )); - dump.append(&mut prepend_sub_config_name( - self.contract_class_manager_config.dump(), - "contract_class_manager_config", - )); - dump.append(&mut prepend_sub_config_name( - self.pre_confirmed_cende_config.dump(), - "pre_confirmed_cende_config", - )); - dump - } -} - -impl Default for BatcherConfig { - fn default() -> Self { - Self { - storage: apollo_storage::StorageConfig { - db_config: apollo_storage::db::DbConfig { - path_prefix: "/data/batcher".into(), - enforce_file_exists: false, - ..Default::default() - }, - scope: apollo_storage::StorageScope::StateOnly, - ..Default::default() - }, - // TODO(AlonH): set a more reasonable default value. - outstream_content_buffer_size: 100, - input_stream_content_buffer_size: 400, - block_builder_config: BlockBuilderConfig::default(), - pre_confirmed_block_writer_config: PreconfirmedBlockWriterConfig::default(), - contract_class_manager_config: ContractClassManagerConfig::default(), - max_l1_handler_txs_per_block_proposal: 3, - pre_confirmed_cende_config: PreconfirmedCendeConfig::default(), - propose_l1_txs_every: 1, // Default is to propose L1 transactions every proposal. - } - } -} - -fn validate_batcher_config(batcher_config: &BatcherConfig) -> Result<(), ValidationError> { - if batcher_config.input_stream_content_buffer_size - < batcher_config.block_builder_config.n_concurrent_txs - { - return Err(ValidationError::new( - "input_stream_content_buffer_size must be at least n_concurrent_txs", - )); - } - Ok(()) -} diff --git a/crates/apollo_batcher_config/src/config.rs b/crates/apollo_batcher_config/src/config.rs index 5a76f1df3f6..ad50ba101dd 100644 --- a/crates/apollo_batcher_config/src/config.rs +++ b/crates/apollo_batcher_config/src/config.rs @@ -159,6 +159,12 @@ impl SerializeConfig for BatcherConfig { "The maximum number of L1 handler transactions to include in a block proposal.", ParamPrivacyInput::Public, ), + ser_param( + "propose_l1_txs_every", + &self.propose_l1_txs_every, + "Only propose L1 transactions every N proposals.", + ParamPrivacyInput::Public, + ), ]); dump.append(&mut prepend_sub_config_name(self.storage.dump(), "storage")); dump.append(&mut prepend_sub_config_name( diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 8420234e8aa..95ee62e7b3b 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -2324,6 +2324,11 @@ "privacy": "TemporaryValue", "value": false }, + "sierra_compiler_config.audited_libfuncs_only": { + "description": "If true, restrict to audited libfuncs. Otherwise allow all.", + "privacy": "Public", + "value": true + }, "sierra_compiler_config.max_bytecode_size": { "description": "Limitation of compiled CASM bytecode size (felts).", "privacy": "Public", @@ -2339,11 +2344,6 @@ "privacy": "TemporaryValue", "value": false }, - "sierra_compiler_config.audited_libfuncs_only": { - "description": "If true, restrict to audited libfuncs. Otherwise allow all.", - "privacy": "Public", - "value": true - }, "starknet_url": { "description": "URL for communicating with Starknet.", "privacy": "TemporaryValue", @@ -2749,4 +2749,4 @@ "privacy": "TemporaryValue", "value": 1000000 } -} \ No newline at end of file +} From 2f2437d8450f63de8f77f13bb5aec51bc0834fb7 Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Sun, 19 Oct 2025 17:08:06 +0300 Subject: [PATCH 068/313] apollo_deployments: regenerate deployments Signed-off-by: Dori Medini --- .../deployments/potc_mock/deployment_config_override.json | 4 ++-- .../resources/deployments/potc_mock/hybrid_0.json | 4 ---- .../resources/deployments/potc_mock/hybrid_1.json | 4 ---- .../resources/deployments/potc_mock/hybrid_2.json | 4 ---- .../resources/services/distributed/batcher.json | 2 +- .../resources/services/distributed/consensus_manager.json | 2 +- crates/apollo_deployments/resources/services/hybrid/core.json | 2 +- 7 files changed, 5 insertions(+), 17 deletions(-) diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json index 52b96a275f4..fae638de90a 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json @@ -2,12 +2,12 @@ "base_layer_config.starknet_contract_address": "0xd8A5518cf4AC3ECD3b4cec772478109679a73E78", "chain_id": "PRIVATE_SN_POTC_MOCK_SEPOLIA", "consensus_manager_config.context_config.num_validators": 3, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-2-sepolia-mock-sharp-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.potc-testnet-mock-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_0.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_0.json index 975c81eb4cd..1b4d7f8b4d2 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_0.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_0.json @@ -1,11 +1,7 @@ { "consensus_manager_config.network_config.advertised_multiaddr": "", "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "mempool_p2p_config.network_config.advertised_multiaddr": "", "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "validator_id": "0x64" } diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_1.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_1.json index 967e3aaeeb2..191efac5768 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_1.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_1.json @@ -1,11 +1,7 @@ { "consensus_manager_config.network_config.advertised_multiaddr": "", "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "mempool_p2p_config.network_config.advertised_multiaddr": "", "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "validator_id": "0x65" } diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_2.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_2.json index b5c8059d531..25524322d64 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_2.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_2.json @@ -1,11 +1,7 @@ { "consensus_manager_config.network_config.advertised_multiaddr": "", "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "mempool_p2p_config.network_config.advertised_multiaddr": "", "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "validator_id": "0x66" } diff --git a/crates/apollo_deployments/resources/services/distributed/batcher.json b/crates/apollo_deployments/resources/services/distributed/batcher.json index bb07e9677bf..9986b9b2575 100644 --- a/crates/apollo_deployments/resources/services/distributed/batcher.json +++ b/crates/apollo_deployments/resources/services/distributed/batcher.json @@ -72,7 +72,7 @@ "components.l1_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_provider.remote_client_config.retries": 150, + "components.l1_provider.remote_client_config.retries": 2, "components.l1_provider.url": "sequencer-l1-service", "components.l1_scraper.execution_mode": "Disabled", "components.mempool.execution_mode": "Remote", diff --git a/crates/apollo_deployments/resources/services/distributed/consensus_manager.json b/crates/apollo_deployments/resources/services/distributed/consensus_manager.json index def5e308e2b..4d6e40f9516 100644 --- a/crates/apollo_deployments/resources/services/distributed/consensus_manager.json +++ b/crates/apollo_deployments/resources/services/distributed/consensus_manager.json @@ -66,7 +66,7 @@ "components.l1_gas_price_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_gas_price_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_gas_price_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_gas_price_provider.remote_client_config.retries": 150, + "components.l1_gas_price_provider.remote_client_config.retries": 2, "components.l1_gas_price_provider.url": "sequencer-l1-service", "components.l1_gas_price_scraper.execution_mode": "Disabled", "components.l1_provider.execution_mode": "Disabled", diff --git a/crates/apollo_deployments/resources/services/hybrid/core.json b/crates/apollo_deployments/resources/services/hybrid/core.json index 9824cbb010d..6e4ba841090 100644 --- a/crates/apollo_deployments/resources/services/hybrid/core.json +++ b/crates/apollo_deployments/resources/services/hybrid/core.json @@ -55,7 +55,7 @@ "components.l1_endpoint_monitor.remote_client_config.idle_timeout_ms": 30000, "components.l1_endpoint_monitor.remote_client_config.initial_retry_delay_ms": 1, "components.l1_endpoint_monitor.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_endpoint_monitor.remote_client_config.retries": 150, + "components.l1_endpoint_monitor.remote_client_config.retries": 2, "components.l1_endpoint_monitor.url": "sequencer-l1-service", "components.l1_gas_price_provider.execution_mode": "Remote", "components.l1_gas_price_provider.ip": "0.0.0.0", From be3ea97ac95a7d6fbf46899620acb770207d01cd Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 17:18:55 +0300 Subject: [PATCH 069/313] apollo_dashboard: reduce consensus round above zero severity to informational (#9637) --- .../resources/dev_grafana_alerts_mainnet.json | 56 +++++++++---------- .../resources/dev_grafana_alerts_testnet.json | 56 +++++++++---------- .../apollo_dashboard/src/alert_definitions.rs | 4 +- .../alert_scenarios/block_production_delay.rs | 24 ++------ 4 files changed, 62 insertions(+), 78 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json index 8f5426a0b23..8762f2ad3b5 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json @@ -252,6 +252,34 @@ "severity": "p4", "observer_applicable": "true" }, + { + "name": "consensus_round_above_zero", + "title": "Consensus round above zero", + "ruleGroup": "consensus", + "expr": "increase(consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1h])", + "conditions": [ + { + "evaluator": { + "params": [ + 0.0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "30s", + "intervalSec": 30, + "severity": "p5", + "observer_applicable": "false" + }, { "name": "consensus_votes_num_sent_messages", "title": "Consensus votes num sent messages", @@ -980,34 +1008,6 @@ "severity": "p2", "observer_applicable": "true" }, - { - "name": "consensus_round_above_zero", - "title": "Consensus round above zero", - "ruleGroup": "consensus", - "expr": "increase(consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1h])", - "conditions": [ - { - "evaluator": { - "params": [ - 0.0 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "for": "30s", - "intervalSec": 30, - "severity": "p4", - "observer_applicable": "false" - }, { "name": "consensus_round_above_zero_multiple_times", "title": "Consensus round above zero multiple times", diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json index ff60cf18448..6ad7a9e4371 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json @@ -252,6 +252,34 @@ "severity": "p4", "observer_applicable": "true" }, + { + "name": "consensus_round_above_zero", + "title": "Consensus round above zero", + "ruleGroup": "consensus", + "expr": "increase(consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1h])", + "conditions": [ + { + "evaluator": { + "params": [ + 0.0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "for": "30s", + "intervalSec": 30, + "severity": "p5", + "observer_applicable": "false" + }, { "name": "consensus_votes_num_sent_messages", "title": "Consensus votes num sent messages", @@ -1064,34 +1092,6 @@ "severity": "p4", "observer_applicable": "true" }, - { - "name": "consensus_round_above_zero", - "title": "Consensus round above zero", - "ruleGroup": "consensus", - "expr": "increase(consensus_round_above_zero{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1h])", - "conditions": [ - { - "evaluator": { - "params": [ - 0.0 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "for": "30s", - "intervalSec": 30, - "severity": "p4", - "observer_applicable": "false" - }, { "name": "consensus_round_above_zero_multiple_times", "title": "Consensus round above zero multiple times", diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index bacf38a73e3..e04fd002191 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -35,8 +35,8 @@ use crate::alert_scenarios::block_production_delay::{ get_cende_write_blob_failure_once_alert, get_consensus_block_number_progress_is_slow_vec, get_consensus_p2p_peer_down_vec, + get_consensus_round_above_zero, get_consensus_round_above_zero_multiple_times_vec, - get_consensus_round_above_zero_vec, }; use crate::alert_scenarios::block_production_halt::{ get_batched_transactions_stuck_vec, @@ -526,6 +526,7 @@ pub fn get_apollo_alerts(alert_env_filtering: AlertEnvFiltering) -> Alerts { get_consensus_l1_gas_price_provider_failure(), get_consensus_l1_gas_price_provider_failure_once(), get_consensus_p2p_disconnections(), + get_consensus_round_above_zero(), get_consensus_votes_num_sent_messages_alert(), get_eth_to_strk_error_count_alert(), get_gateway_add_tx_idle(), @@ -554,7 +555,6 @@ pub fn get_apollo_alerts(alert_env_filtering: AlertEnvFiltering) -> Alerts { alerts.append(&mut get_consensus_block_number_stuck_vec()); alerts.append(&mut get_consensus_p2p_not_enough_peers_for_quorum_vec()); alerts.append(&mut get_consensus_p2p_peer_down_vec()); - alerts.append(&mut get_consensus_round_above_zero_vec()); alerts.append(&mut get_consensus_round_above_zero_multiple_times_vec()); alerts.append(&mut get_consensus_round_high_vec()); alerts.append(&mut get_eth_to_strk_success_count_alert_vec()); diff --git a/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs b/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs index defceba0c0b..cfa7fe2568a 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs @@ -16,11 +16,8 @@ use crate::alerts::{ PENDING_DURATION_DEFAULT, }; -/// The was a round larger than zero in the last hour. -fn get_consensus_round_above_zero( - alert_env_filtering: AlertEnvFiltering, - alert_severity: AlertSeverity, -) -> Alert { +/// There was a consensus round number higher than zero. +pub(crate) fn get_consensus_round_above_zero() -> Alert { Alert::new( "consensus_round_above_zero", "Consensus round above zero", @@ -33,25 +30,12 @@ fn get_consensus_round_above_zero( }], PENDING_DURATION_DEFAULT, EVALUATION_INTERVAL_SEC_DEFAULT, - alert_severity, + AlertSeverity::Informational, ObserverApplicability::NotApplicable, - alert_env_filtering, + AlertEnvFiltering::All, ) } -pub(crate) fn get_consensus_round_above_zero_vec() -> Vec { - vec![ - get_consensus_round_above_zero( - AlertEnvFiltering::MainnetStyleAlerts, - AlertSeverity::WorkingHours, - ), - get_consensus_round_above_zero( - AlertEnvFiltering::TestnetStyleAlerts, - AlertSeverity::WorkingHours, - ), - ] -} - fn get_consensus_round_above_zero_multiple_times( alert_env_filtering: AlertEnvFiltering, alert_severity: AlertSeverity, From 0fad822c0e1ff0a7f6c500918ca8e1ba588f169e Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 17:26:01 +0300 Subject: [PATCH 070/313] apollo_node_config: include base prefix when pruning unset optionals (#9497) --- crates/apollo_node_config/src/config_utils.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/apollo_node_config/src/config_utils.rs b/crates/apollo_node_config/src/config_utils.rs index 25611925f21..4b820a5e744 100644 --- a/crates/apollo_node_config/src/config_utils.rs +++ b/crates/apollo_node_config/src/config_utils.rs @@ -98,7 +98,8 @@ pub fn config_to_preset(config_map: &Value) -> Value { } } -/// Keep "{prefix}.#is_none": true, remove all other "{prefix}.*" keys. +/// Keep "{prefix}.#is_none": true, remove all other keys that begin with "{prefix}" (including +/// the bare prefix). pub fn prune_by_is_none(mut v: Value) -> Value { let obj: &mut Map = v.as_object_mut().expect("prune_by_is_none: expected a JSON object"); @@ -110,16 +111,17 @@ pub fn prune_by_is_none(mut v: Value) -> Value { for (k, val) in obj.iter() { if let Some(prefix) = k.strip_suffix(&is_none_suffix) { if val.as_bool() == Some(true) { - unset_optional_param_paths.insert(format!("{prefix}{FIELD_SEPARATOR}")); + unset_optional_param_paths.insert(prefix.to_string()); } } } - // Remove keys that begin with any such prefix, except the "#is_none" flag itself + // Remove keys that begin with any such prefix (including the bare prefix), except the + // "#is_none" flag itself obj.retain(|k, _| { if let Some(p) = unset_optional_param_paths.iter().find(|p| k.starts_with(&***p)) { // keep only the "{prefix}.#is_none" key - k == &format!("{p}{IS_NONE_MARK}") + k == &format!("{p}{FIELD_SEPARATOR}{IS_NONE_MARK}") } else { true } @@ -202,6 +204,7 @@ impl DeploymentBaseAppConfig { // Extract only the required fields from the config map. let preset = config_to_preset(&config_as_map); + let preset = prune_by_is_none(preset); validate_all_pointer_targets_set(preset.clone()).expect("Pointer target not set"); preset } From 37bf43080801eaa30b9bce549261a1aee3f71899 Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 17:38:58 +0300 Subject: [PATCH 071/313] starknet_os: delete SerializableBlobs (#9635) --- Cargo.lock | 1 + .../src/kzg_cli/run_kzg_cli.rs | 8 +-- crates/starknet_os/Cargo.toml | 1 + .../hints/hint_implementation/kzg/utils.rs | 52 ++++++------------- 4 files changed, 20 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c87fb44942..c0e394d4c19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12323,6 +12323,7 @@ dependencies = [ "rstest", "serde", "serde_json", + "serde_with", "sha2", "sha3", "shared_execution_objects", diff --git a/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs b/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs index 828243ac2c8..d73ae6fe271 100644 --- a/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs +++ b/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs @@ -1,8 +1,5 @@ use clap::{Parser, Subcommand}; -use starknet_os::hints::hint_implementation::kzg::utils::{ - compute_blob_commitments, - SerializableBlobs, -}; +use starknet_os::hints::hint_implementation::kzg::utils::compute_blob_commitments; use tracing::info; use crate::shared_utils::read::{load_input, write_to_file}; @@ -29,8 +26,7 @@ pub fn run_kzg_cli(kzg_command: KzgCliCommand) { let raw_blobs: Vec> = load_input(input_path); let blobs = compute_blob_commitments(raw_blobs) .unwrap_or_else(|error| panic!("Failed to calculate blob commitments: {error}")); - let serializable_blobs = SerializableBlobs::from(blobs); - write_to_file(&output_path, &serializable_blobs); + write_to_file(&output_path, &blobs); } }; } diff --git a/crates/starknet_os/Cargo.toml b/crates/starknet_os/Cargo.toml index 1735dd89499..6603a7f1f50 100644 --- a/crates/starknet_os/Cargo.toml +++ b/crates/starknet_os/Cargo.toml @@ -45,6 +45,7 @@ paste.workspace = true regex.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["raw_value"] } +serde_with.workspace = true sha2.workspace = true sha3.workspace = true shared_execution_objects.workspace = true diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs index 85ff50211ea..2ac1aeefd3c 100644 --- a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs @@ -4,10 +4,11 @@ use std::sync::LazyLock; use ark_bls12_381::Fr; use ark_ff::{BigInteger, PrimeField}; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; -use c_kzg::{Blob, KzgCommitment, KzgProof, KzgSettings, BYTES_PER_FIELD_ELEMENT}; +use c_kzg::{Blob, KzgCommitment, KzgSettings, BYTES_PER_FIELD_ELEMENT}; use num_bigint::{BigInt, BigUint, ParseBigIntError}; use num_traits::{Num, Signed, Zero}; use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, Bytes}; use sha2::{Digest, Sha256}; use starknet_types_core::felt::Felt; @@ -160,35 +161,16 @@ pub fn split_bigint3(num: BigInt) -> Result<[Felt; 3], OsHintError> { Ok([d0, d1, Felt::from(d2)]) } -/// Structure to hold blob data, commitments, proofs, and versioned hashes. -pub struct Blobs { - pub blobs: Vec>, - pub commitments: Vec, - pub proofs: Vec, - pub versioned_hashes: Vec<[u8; 32]>, -} - -/// Serializable structure to hold blob data, commitments, proofs, and versioned hashes. -/// All cryptographic objects are converted to byte arrays for easy serialization. +/// Structure to hold blob artifacts: commitments, proofs, and versioned hashes. +#[serde_as] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct SerializableBlobs { - pub blobs: Vec>, - pub commitments: Vec>, // 48 bytes each - pub proofs: Vec>, // 48 bytes each - pub versioned_hashes: Vec>, // 32 bytes each -} -impl From for SerializableBlobs { - fn from(Blobs { blobs, commitments, proofs, versioned_hashes }: Blobs) -> Self { - Self { - blobs, - commitments: commitments - .into_iter() - .map(|commitment| commitment.to_bytes().as_ref().to_vec()) - .collect(), - proofs: proofs.into_iter().map(|proof| proof.to_bytes().as_ref().to_vec()).collect(), - versioned_hashes: versioned_hashes.into_iter().map(|hash| hash.to_vec()).collect(), - } - } +pub struct BlobArtifacts { + #[serde_as(as = "Vec")] + pub commitments: Vec<[u8; 48]>, + #[serde_as(as = "Vec")] + pub proofs: Vec<[u8; 48]>, + #[serde_as(as = "Vec")] + pub versioned_hashes: Vec<[u8; 32]>, } /// Computes a versioned hash from a KZG commitment. @@ -210,9 +192,8 @@ fn kzg_to_versioned_hash(commitment: &KzgCommitment) -> [u8; 32] { /// Computes KZG commitments, proofs, and versioned hashes for a list of raw blobs. /// /// For each blob, computes the KZG commitment and the corresponding KZG proof that is used -/// to verify the commitment. Returns the internal `Blobs` structure with native KZG types. -pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result { - let mut blobs = Vec::new(); +/// to verify the commitment. Returns `BlobArtifacts` structure. +pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result { let mut commitments = Vec::new(); let mut proofs = Vec::new(); let mut versioned_hashes = Vec::new(); @@ -230,11 +211,10 @@ pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result Date: Sun, 19 Oct 2025 17:56:06 +0300 Subject: [PATCH 072/313] papyrus_node: Papyrus cleanup - consensus README (#9620) * papyrus_node: Papyrus cleanup - papyrus_state.rs * papyrus_node: Papyrus cleanup - consensus README --- crates/apollo_consensus/README.md | 36 ------------------------------- 1 file changed, 36 deletions(-) delete mode 100644 crates/apollo_consensus/README.md diff --git a/crates/apollo_consensus/README.md b/crates/apollo_consensus/README.md deleted file mode 100644 index 35c2230a1ba..00000000000 --- a/crates/apollo_consensus/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# papyrus-consensus - -This crate provides an implementation of consensus for a Starknet node. - -### Disclaimer -This crate is still under development and is not keeping backwards compatibility with previous -versions. Breaking changes are expected to happen in the near future. - -## How to run -1. You must turn consensus on and provide a validator ID by passing: `--consensus.#is_none false --consensus.validator_id 0x` -2. Start by running any nodes which are validators for `consensus.start_height` which is by default 0 to avoid them missing the proposal. - 1. You can change the default number of validators by passing: `--consensus.num_validators ` - 2. You can change the default topic by passing: `--consensus.topic "TOPIC"` - 3. You can test the consensus under simulated network conditions, by passing: `--consensus.test.#is_none false` - 1. Optional arguments: - `--consensus.test.cache_size ` - `--consensus.test.random_seed ` - `--consensus.test.drop_probability 0` (set to 0 for now) - `--consensus.test.invalid_probability ` (0 to 1) - -#### Bootstrap Node -This must be run first: -``` -cargo run --package papyrus_node --bin papyrus_node -- --base_layer_url --network.#is_none false --consensus.#is_none false --consensus.validator_id 0x1 --storage.db_config.path_prefix -``` -- This will log `local_peer_id` which is used by other nodes. (Alternatively pass `network.secret_key` to have a fixed peer id). - -#### Other Nodes -Run each of the other nodes separately, using different `consensus.validator_id` {`0x2`, `0x3`, `0x0`}: - -``` -cargo run --package papyrus_node --bin papyrus_node -- --base_layer_url --network.#is_none false --consensus.#is_none false --consensus.validator_id 0x --network.port --network.bootstrap_peer_multiaddr.#is_none false --rpc.server_address 127.0.0.1: --monitoring_gateway.server_address 127.0.0.1: --storage.db_config.path_prefix --network.bootstrap_peer_multiaddr /ip4/127.0.0.1/tcp/10000/p2p/ -``` -- Node 0 is the first proposer and should be run last. - -UNIQUE - a value unique among all nodes running locally. From d49f57f3ee7e08ebfff486b4666d3c1350a0e911 Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 18:11:09 +0300 Subject: [PATCH 073/313] apollo_consensus_orchestrator: add validators_ids to ContextConfig (#9468) --- Cargo.lock | 2 + config/papyrus/default_config.json | 10 +++++ crates/apollo_config/Cargo.toml | 2 + crates/apollo_config/src/converters.rs | 38 ++++++++++++++++++ .../src/sequencer_consensus_context.rs | 9 +++-- .../src/config.rs | 20 +++++++++- .../app_configs/consensus_manager_config.json | 1 + crates/apollo_gateway_config/src/config.rs | 39 +------------------ .../apollo_node/resources/config_schema.json | 22 ++++++++--- ...fig__config_test__dump_default_config.snap | 10 +++++ 10 files changed, 105 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34cce6b0427..3e0161302a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1079,6 +1079,8 @@ dependencies = [ "lazy_static", "serde", "serde_json", + "starknet-types-core", + "starknet_api", "strum_macros 0.25.3", "tempfile", "thiserror 1.0.69", diff --git a/config/papyrus/default_config.json b/config/papyrus/default_config.json index d0d8d93d32e..985fda0e98c 100644 --- a/config/papyrus/default_config.json +++ b/config/papyrus/default_config.json @@ -214,6 +214,16 @@ "privacy": "Public", "value": 10000 }, + "context.validator_ids": { + "description": "Optional explicit set of validator IDs (comma separated).", + "privacy": "Public", + "value": "" + }, + "context.validator_ids.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, "monitoring_gateway.collect_metrics": { "description": "If true, collect and return metrics in the monitoring gateway.", "pointer_target": "collect_metrics", diff --git a/crates/apollo_config/Cargo.toml b/crates/apollo_config/Cargo.toml index 2471cd4846c..9c24efd715e 100644 --- a/crates/apollo_config/Cargo.toml +++ b/crates/apollo_config/Cargo.toml @@ -14,6 +14,8 @@ const_format.workspace = true itertools.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } +starknet-types-core.workspace = true +starknet_api.workspace = true strum_macros.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/apollo_config/src/converters.rs b/crates/apollo_config/src/converters.rs index 22f23ce6de0..e5da6500624 100644 --- a/crates/apollo_config/src/converters.rs +++ b/crates/apollo_config/src/converters.rs @@ -31,6 +31,8 @@ use std::time::Duration; use serde::de::Error; use serde::{Deserialize, Deserializer, Serialize}; +use starknet_api::core::ContractAddress; +use starknet_types_core::felt::Felt; use url::Url; /// Deserializes milliseconds to duration object. @@ -272,3 +274,39 @@ where .map(|s| T::from_str(s).map_err(|e| D::Error::custom(format!("Invalid value '{s}': {e}")))) .collect() } + +// TODO(Asmaa): refactor this to `deserialize_comma_separated_str` where +// T: TryFrom<&str>, to support deserializing comma-separated lists of any type. +/// Deserializes an optional comma-separated list of contract addresses into +/// `Option>`. An empty string is invalid if the `#is_none` flag is false. +pub fn deserialize_optional_contract_addresses<'de, D>( + de: D, +) -> Result>, D::Error> +where + D: Deserializer<'de>, +{ + let raw: String = match Option::::deserialize(de)? { + Some(addresses) => addresses, + None => return Ok(None), + }; + + if raw.is_empty() { + return Err(D::Error::custom( + "Empty string is not a valid input for contract addresses. The config field is marked \ + as not none.", + )); + } + + let mut result = Vec::new(); + for addresses_str in raw.split(',') { + let felt = Felt::from_str(addresses_str).map_err(|err| { + D::Error::custom(format!("Failed to parse Felt from '{addresses_str}': {err}")) + })?; + let addr = ContractAddress::try_from(felt).map_err(|err| { + D::Error::custom(format!("Invalid contract address '{addresses_str}': {err}")) + })?; + result.push(addr); + } + + Ok(Some(result)) +} diff --git a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs index d049e6e744a..b469f9968e8 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -188,13 +188,16 @@ impl SequencerConsensusContext { } else { L1DataAvailabilityMode::Calldata }; + let validators = if let Some(ids) = config.validator_ids.clone() { + ids.into_iter().collect() + } else { + (0..num_validators).map(|i| ValidatorId::from(DEFAULT_VALIDATOR_ID + i)).collect() + }; Self { config, deps, // TODO(Matan): Set the actual validator IDs (contract addresses). - validators: (0..num_validators) - .map(|i| ValidatorId::from(DEFAULT_VALIDATOR_ID + i)) - .collect(), + validators, valid_proposals: Arc::new(Mutex::new(BuiltProposals::new())), proposal_id: 0, current_height: None, diff --git a/crates/apollo_consensus_orchestrator_config/src/config.rs b/crates/apollo_consensus_orchestrator_config/src/config.rs index 6c1b81134fd..37f40e379cd 100644 --- a/crates/apollo_consensus_orchestrator_config/src/config.rs +++ b/crates/apollo_consensus_orchestrator_config/src/config.rs @@ -4,6 +4,7 @@ use std::time::Duration; use apollo_config::converters::{ deserialize_milliseconds_to_duration, + deserialize_optional_contract_addresses, deserialize_seconds_to_duration, }; use apollo_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; @@ -93,6 +94,10 @@ pub struct ContextConfig { pub proposal_buffer_size: usize, /// The number of validators. pub num_validators: u64, + /// Optional explicit set of validator IDs (contract addresses) to use. + /// If provided, this overrides `num_validators`. + #[serde(default, deserialize_with = "deserialize_optional_contract_addresses")] + pub validator_ids: Option>, /// The chain id of the Starknet chain. pub chain_id: ChainId, /// Maximum allowed deviation (seconds) of a proposed block's timestamp from the current time. @@ -132,7 +137,7 @@ pub struct ContextConfig { impl SerializeConfig for ContextConfig { fn dump(&self) -> BTreeMap { - BTreeMap::from_iter([ + let mut config = BTreeMap::from_iter([ ser_param( "proposal_buffer_size", &self.proposal_buffer_size, @@ -227,7 +232,17 @@ impl SerializeConfig for ContextConfig { "If true, sets STRK gas price to its minimum price from the versioned constants.", ParamPrivacyInput::Public, ), - ]) + ]); + config.extend(ser_optional_param( + &self.validator_ids.as_ref().map(|accounts| { + accounts.iter().map(|addr| addr.0.to_string()).collect::>().join(",") + }), + "".to_string(), + "validator_ids", + "Optional explicit set of validator IDs (comma separated).", + ParamPrivacyInput::Public, + )); + config } } @@ -236,6 +251,7 @@ impl Default for ContextConfig { Self { proposal_buffer_size: 100, num_validators: 1, + validator_ids: None, chain_id: ChainId::Mainnet, block_timestamp_window_seconds: 1, l1_da_mode: true, diff --git a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json index 041c2dd6c92..3f9c83c3aee 100644 --- a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json +++ b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json @@ -26,6 +26,7 @@ "consensus_manager_config.context_config.max_l1_gas_price_wei": 1000000000000, "consensus_manager_config.context_config.min_l1_data_gas_price_wei": 1, "consensus_manager_config.context_config.max_l1_data_gas_price_wei": 1000000000000, + "consensus_manager_config.context_config.validator_ids.#is_none": true, "consensus_manager_config.immediate_active_height": 1, "consensus_manager_config.assume_no_malicious_validators": true, "consensus_manager_config.network_config.broadcasted_message_metadata_buffer_size": 100000, diff --git a/crates/apollo_gateway_config/src/config.rs b/crates/apollo_gateway_config/src/config.rs index b09f452f198..bea97c34ed2 100644 --- a/crates/apollo_gateway_config/src/config.rs +++ b/crates/apollo_gateway_config/src/config.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use std::str::FromStr; +use apollo_config::converters::deserialize_optional_contract_addresses; use apollo_config::dumping::{ prepend_sub_config_name, ser_optional_param, @@ -10,7 +10,7 @@ use apollo_config::dumping::{ use apollo_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use blockifier::blockifier_versioned_constants::VersionedConstantsOverrides; use blockifier::context::ChainInfo; -use serde::{de, Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use starknet_api::core::{ContractAddress, Nonce}; use starknet_types_core::felt::Felt; use validator::Validate; @@ -69,41 +69,6 @@ impl GatewayConfig { } } -fn deserialize_optional_contract_addresses<'de, D>( - de: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - let raw: String = match Option::deserialize(de)? { - Some(addresses) => addresses, - None => return Ok(None), - }; - - if raw.is_empty() { - return Err(de::Error::custom( - "Empty string is not a valid input for contract addresses. The config field \ - `gateway_config.authorized_declarer_accounts.#is_none` is false and should be true \ - if you don't want to use this feature.", - )); - } - - let mut result = Vec::new(); - for addresses_str in raw.split(',') { - let felt = Felt::from_str(addresses_str).map_err(|err| { - de::Error::custom(format!("Failed to parse Felt from '{addresses_str}': {err}")) - })?; - - let addr = ContractAddress::try_from(felt).map_err(|err| { - de::Error::custom(format!("Invalid contract address '{addresses_str}': {err}")) - })?; - - result.push(addr); - } - - Ok(Some(result)) -} - #[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)] pub struct StatelessTransactionValidatorConfig { // If true, ensures that at least one resource bound (L1, L2, or L1 data) is greater than zero. diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 94b7ea6534e..f2c6d9176a0 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -1634,6 +1634,16 @@ "privacy": "Public", "value": 10000 }, + "consensus_manager_config.context_config.validator_ids": { + "description": "Optional explicit set of validator IDs (comma separated).", + "privacy": "Public", + "value": "" + }, + "consensus_manager_config.context_config.validator_ids.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, "consensus_manager_config.immediate_active_height": { "description": "The height at which the node may actively participate in consensus.", "privacy": "Public", @@ -2289,6 +2299,11 @@ "privacy": "TemporaryValue", "value": false }, + "sierra_compiler_config.audited_libfuncs_only": { + "description": "If true, restrict to audited libfuncs. Otherwise allow all.", + "privacy": "Public", + "value": true + }, "sierra_compiler_config.max_bytecode_size": { "description": "Limitation of compiled CASM bytecode size (felts).", "privacy": "Public", @@ -2304,11 +2319,6 @@ "privacy": "TemporaryValue", "value": false }, - "sierra_compiler_config.audited_libfuncs_only": { - "description": "If true, restrict to audited libfuncs. Otherwise allow all.", - "privacy": "Public", - "value": true - }, "starknet_url": { "description": "URL for communicating with Starknet.", "privacy": "TemporaryValue", @@ -2714,4 +2724,4 @@ "privacy": "TemporaryValue", "value": 1000000 } -} \ No newline at end of file +} diff --git a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap index 04d5d43fdc3..007fd1642ef 100644 --- a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap +++ b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap @@ -264,6 +264,16 @@ expression: dumped_default_config }, "privacy": "Public" }, + "context.validator_ids": { + "description": "Optional explicit set of validator IDs (comma separated).", + "value": "", + "privacy": "Public" + }, + "context.validator_ids.#is_none": { + "description": "Flag for an optional field.", + "value": true, + "privacy": "TemporaryValue" + }, "monitoring_gateway.collect_metrics": { "description": "If true, collect and return metrics in the monitoring gateway.", "value": false, From a1bfef3f2a76596ea920f1e9e2947a4f8bd5a744 Mon Sep 17 00:00:00 2001 From: Meshi Peled <141231558+meship-starkware@users.noreply.github.com> Date: Sun, 19 Oct 2025 21:05:55 +0300 Subject: [PATCH 074/313] starknet_os: rename encrypt_dest to output_ptr (#9618) --- .../starkware/starknet/core/os/encrypt.cairo | 54 ++++++++++--------- .../starkware/starknet/core/os/output.cairo | 6 +-- .../starknet_os/src/hints/enum_definition.rs | 2 +- .../src/hints/hint_implementation/output.rs | 6 +-- .../state_diff_encryption_test.rs | 24 ++++----- .../stateless_compression/implementation.rs | 2 +- crates/starknet_os/src/hints/vars.rs | 2 +- 7 files changed, 49 insertions(+), 47 deletions(-) diff --git a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/encrypt.cairo b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/encrypt.cairo index b46fe645e35..f0d5dfbfa9b 100644 --- a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/encrypt.cairo +++ b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/encrypt.cairo @@ -21,19 +21,19 @@ from starkware.cairo.common.alloc import alloc // Part 1: Generate StarkNet keys for each committee member // - An hint generates a symmetric_key and sn_private_keys by hashing the compressed state diff. // - The private keys are validated to be in range [1, StarkCurve.ORDER - 1]. -// - Public keys are computed from the private keys and output to encrypted_dst. +// - Public keys are computed from the private keys and output to output_pointer. // // Part 2: Share one symmetric_key with multiple committee members // - For each committee member, derive a shared secret from their public key // and the corresponding StarkNet private key. // (Shared secret generation uses Elliptic-Curve Diffie–Hellman (ECDH) on StarkCurve). -// - Hash the shared secret's x-coordinate using BLAKE2s to get a mask, then output to encrypted_dst +// - Hash the shared secret's x-coordinate using BLAKE2s to get a mask, then output to output_pointer // encrypted_symmetric_key[i] = symmetric_key + mask[i]. // (A committee member can recompute the same mask with their private key to recover symmetric_key.) // // Part 3: Encrypt a list of felts with the symmetric_key // - For index i, compute mask_i = BLAKE2s(encode([symmetric_key, i])). -// - Output to encrypted_dst ciphertext[i] = plaintext[i] + mask_i (modulo the field prime). +// - Output to output_pointer ciphertext[i] = plaintext[i] + mask_i (modulo the field prime). // // Output structure: // encrypted = [n_keys, sn_public_keys, encrypted_symmetric_keys, ciphertext] @@ -44,14 +44,14 @@ from starkware.cairo.common.alloc import alloc // - Field addition is used for masking; this provides confidentiality only. // - Reference: Elliptic-Curve Diffie–Hellman (ECDH) https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman func encrypt_state_diff{range_check_ptr, ec_op_ptr: EcOpBuiltin*}( - compressed_start: felt*, compressed_dst: felt*, n_keys: felt, public_keys: felt* -) -> (encrypted_start: felt*, encrypted_dst: felt*) { + compressed_start: felt*, compressed_end: felt*, n_keys: felt, public_keys: felt* +) -> (encrypted_start: felt*, encrypted_end: felt*) { alloc_locals; // Generate random symmetric key and random starknet private keys. local symmetric_key: felt; local sn_private_keys: felt*; - %{ generate_keys_from_hash(ids.compressed_start, ids.compressed_dst, ids.n_keys) %} + %{ generate_keys_from_hash(ids.compressed_start, ids.compressed_end, ids.n_keys) %} local encrypted_start: felt*; %{ @@ -62,11 +62,11 @@ func encrypt_state_diff{range_check_ptr, ec_op_ptr: EcOpBuiltin*}( ids.encrypted_start = segments.add_temp_segment() %} - let encrypted_dst = encrypted_start; - assert encrypted_dst[0] = n_keys; - let encrypted_dst = &encrypted_dst[1]; + let output_pointer = encrypted_start; + assert output_pointer[0] = n_keys; + let output_pointer = &output_pointer[1]; - with encrypted_dst { + with output_pointer { output_sn_public_keys(n_keys=n_keys, sn_private_keys=sn_private_keys); output_encrypted_symmetric_key( n_keys=n_keys, @@ -74,17 +74,17 @@ func encrypt_state_diff{range_check_ptr, ec_op_ptr: EcOpBuiltin*}( sn_private_keys=sn_private_keys, symmetric_key=symmetric_key, ); - encrypt(data_start=compressed_start, data_end=compressed_dst, symmetric_key=symmetric_key); + encrypt(data_start=compressed_start, data_end=compressed_end, symmetric_key=symmetric_key); } - return (encrypted_start=encrypted_start, encrypted_dst=encrypted_dst); + return (encrypted_start=encrypted_start, encrypted_end=output_pointer); } // Compute public keys from private keys. // Step-by-step for each key: // 1) Multiply the private key by the curve generator to get the public point (x, y). -// 2) Write x into `encrypted_dst` (y can be recovered later when needed). -func output_sn_public_keys{range_check_ptr, ec_op_ptr: EcOpBuiltin*, encrypted_dst: felt*}( +// 2) Write x into `output` (y can be recovered later when needed). +func output_sn_public_keys{range_check_ptr, ec_op_ptr: EcOpBuiltin*, output_pointer: felt*}( n_keys: felt, sn_private_keys: felt* ) { if (n_keys == 0) { @@ -94,8 +94,8 @@ func output_sn_public_keys{range_check_ptr, ec_op_ptr: EcOpBuiltin*, encrypted_d let (sn_public_key) = ec_mul( m=sn_private_keys[0], p=EcPoint(x=StarkCurve.GEN_X, y=StarkCurve.GEN_Y) ); - assert encrypted_dst[0] = sn_public_key.x; - let encrypted_dst = &encrypted_dst[1]; + assert output_pointer[0] = sn_public_key.x; + let output_pointer = &output_pointer[1]; // Validates that the private keys are within the range [1, StarkCurve.ORDER - 1]. assert_not_zero(sn_private_keys[0]); assert_le_felt(sn_private_keys[0], StarkCurve.ORDER - 1); @@ -108,23 +108,25 @@ func output_sn_public_keys{range_check_ptr, ec_op_ptr: EcOpBuiltin*, encrypted_d // 2) Compute a shared secret point = our private key * recipient public point (Diffie–Hellman). // 3) Hash the x-coordinate of the shared point to get a mask. // 4) encrypted symmetric key = symmetric_key + hash(shared_secret.x)`. -func output_encrypted_symmetric_key{range_check_ptr, ec_op_ptr: EcOpBuiltin*, encrypted_dst: felt*}( - n_keys: felt, public_keys: felt*, sn_private_keys: felt*, symmetric_key: felt -) { +func output_encrypted_symmetric_key{ + range_check_ptr, ec_op_ptr: EcOpBuiltin*, output_pointer: felt* +}(n_keys: felt, public_keys: felt*, sn_private_keys: felt*, symmetric_key: felt) { if (n_keys == 0) { return (); } alloc_locals; + // Using recover_y(x) is safe because on short-Weierstrass curves (x, y) and (x, -y) share the same x. + // Scalar multiplication depends only on x(Q), so we can reconstruct y later without ambiguity. let (public_key) = recover_y(public_keys[0]); let (__fp__, _) = get_fp_and_pc(); let (local shared_secret) = ec_mul(m=sn_private_keys[0], p=public_key); let (hash) = calc_blake_hash_single(item=shared_secret.x); - assert encrypted_dst[0] = symmetric_key + hash; - let encrypted_dst = &encrypted_dst[1]; + assert output_pointer[0] = symmetric_key + hash; + let output_pointer = &output_pointer[1]; return output_encrypted_symmetric_key( n_keys=n_keys - 1, @@ -134,11 +136,11 @@ func output_encrypted_symmetric_key{range_check_ptr, ec_op_ptr: EcOpBuiltin*, en ); } -// Encrypt a list of numbers (felts) using symmetric_key into encrypted_dst. +// Encrypt a list of numbers (felts) using symmetric_key into output_pointer. // Step-by-step for item i: // 1) mask = Hash [encoded_symmetric_key, i] . // 2) ciphertext[i] = plaintext[i] + mask. -func encrypt{range_check_ptr, encrypted_dst: felt*}( +func encrypt{range_check_ptr, output_pointer: felt*}( data_start: felt*, data_end: felt*, symmetric_key: felt ) { // For all elements of the state diff, write the input and output to the same output to @@ -164,7 +166,7 @@ func encrypt{range_check_ptr, encrypted_dst: felt*}( // Helper for `encrypt` that processes one element at a time. // Stops when we reach `data_end`. -func encrypt_inner{range_check_ptr, encrypted_dst: felt*}( +func encrypt_inner{range_check_ptr, output_pointer: felt*}( data_start: felt*, data_end: felt*, index: felt, @@ -205,9 +207,9 @@ func encrypt_inner{range_check_ptr, encrypted_dst: felt*}( let blake_segment = &blake_segment[8]; // Encrypt the current element. - assert encrypted_dst[0] = hash + data_start[0]; + assert output_pointer[0] = hash + data_start[0]; - let encrypted_dst = &encrypted_dst[1]; + let output_pointer = &output_pointer[1]; return encrypt_inner( data_start=&data_start[1], diff --git a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/output.cairo b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/output.cairo index 6c19090245c..23ef0189931 100644 --- a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/output.cairo +++ b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/output.cairo @@ -265,14 +265,14 @@ func process_data_availability{range_check_ptr, ec_op_ptr: EcOpBuiltin*}( } // Encrypt the compressed state updates. - let (encrypted_start, encrypted_dst) = encrypt_state_diff( + let (encrypted_start, encrypted_end) = encrypt_state_diff( compressed_start=compressed_start, - compressed_dst=compressed_dst, + compressed_end=compressed_dst, n_keys=n_keys, public_keys=public_keys, ); - return (da_start=encrypted_start, da_end=encrypted_dst); + return (da_start=encrypted_start, da_end=encrypted_end); } func serialize_data_availability{output_ptr: felt*}(da_start: felt*, da_end: felt*) { diff --git a/crates/starknet_os/src/hints/enum_definition.rs b/crates/starknet_os/src/hints/enum_definition.rs index b997a562c40..248a2bb062f 100644 --- a/crates/starknet_os/src/hints/enum_definition.rs +++ b/crates/starknet_os/src/hints/enum_definition.rs @@ -939,7 +939,7 @@ ids.initial_carried_outputs = segments.gen_arg( ( GenerateKeysUsingSha256Hash, calculate_keys_using_sha256_hash, - "generate_keys_from_hash(ids.compressed_start, ids.compressed_dst, ids.n_keys)" + "generate_keys_from_hash(ids.compressed_start, ids.compressed_end, ids.n_keys)" ) ); diff --git a/crates/starknet_os/src/hints/hint_implementation/output.rs b/crates/starknet_os/src/hints/hint_implementation/output.rs index 19547edaa84..97fc48759a8 100644 --- a/crates/starknet_os/src/hints/hint_implementation/output.rs +++ b/crates/starknet_os/src/hints/hint_implementation/output.rs @@ -196,9 +196,9 @@ pub(crate) fn calculate_keys_using_sha256_hash( // randomness source. let compressed_start = get_ptr_from_var_name(Ids::CompressedStart.into(), vm, ids_data, ap_tracking)?; - let compressed_dst = - get_ptr_from_var_name(Ids::CompressedDst.into(), vm, ids_data, ap_tracking)?; - let array_size = (compressed_dst - compressed_start)?; + let compressed_end = + get_ptr_from_var_name(Ids::CompressedEnd.into(), vm, ids_data, ap_tracking)?; + let array_size = (compressed_end - compressed_start)?; for i in 0..array_size { let felt = vm.get_integer((compressed_start + i)?)?; hasher.update(felt.to_bytes_be()); diff --git a/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/state_diff_encryption_test.rs b/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/state_diff_encryption_test.rs index bb8dbe1e48c..f03ba2dfb3a 100644 --- a/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/state_diff_encryption_test.rs +++ b/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/state_diff_encryption_test.rs @@ -137,9 +137,9 @@ fn test_state_diff_encryption_function( HashMap::new(), ) .unwrap(); - let encrypted_dst = runner.vm.add_memory_segment(); + let output_pointer = runner.vm.add_memory_segment(); implicit_args - .push(ImplicitArg::NonBuiltin(EndpointArg::Value(ValueArg::Single(encrypted_dst.into())))); + .push(ImplicitArg::NonBuiltin(EndpointArg::Value(ValueArg::Single(output_pointer.into())))); // Use the parameterized data instead of hardcoded values. let (data_start, data_end) = add_memory_segment_and_load_explicit_arg(&mut runner, &data); @@ -173,13 +173,13 @@ fn test_state_diff_encryption_function( ); }; - let encrypted_dst_length = (encrypted_dst_end - encrypted_dst).unwrap(); + let encrypted_dst_length = (encrypted_dst_end - output_pointer).unwrap(); assert_eq!(data.len(), encrypted_dst_length); // Only try to get encrypted data if there is data to encrypt. let encrypted_data = if encrypted_dst_length > 0 { let encrypted_range = - runner.vm.get_integer_range(encrypted_dst, encrypted_dst_length).unwrap(); + runner.vm.get_integer_range(output_pointer, encrypted_dst_length).unwrap(); encrypted_range.into_iter().map(|felt| *felt).collect() } else { vec![] @@ -242,9 +242,9 @@ fn test_compute_public_keys_function(#[case] seed: u64, #[case] num_committee_me ) .unwrap(); - let encrypted_dst = runner.vm.add_memory_segment(); + let output_pointer = runner.vm.add_memory_segment(); implicit_args - .push(ImplicitArg::NonBuiltin(EndpointArg::Value(ValueArg::Single(encrypted_dst.into())))); + .push(ImplicitArg::NonBuiltin(EndpointArg::Value(ValueArg::Single(output_pointer.into())))); let (sn_private_keys, _) = add_memory_segment_and_load_explicit_arg(&mut runner, &sn_private_keys_vector); @@ -275,13 +275,13 @@ fn test_compute_public_keys_function(#[case] seed: u64, #[case] num_committee_me panic!("Unexpected implicit return value"); }; - let actual_public_keys_length = (encrypted_dst_end - encrypted_dst).unwrap(); + let actual_public_keys_length = (encrypted_dst_end - output_pointer).unwrap(); assert_eq!(sn_private_keys_vector.len(), actual_public_keys_length); // Only try to get public keys if there are private keys. let sn_public_keys_from_memory = if actual_public_keys_length > 0 { let public_keys_range = - runner.vm.get_integer_range(encrypted_dst, actual_public_keys_length).unwrap(); + runner.vm.get_integer_range(output_pointer, actual_public_keys_length).unwrap(); public_keys_range.into_iter().map(|felt| *felt).collect() } else { vec![] @@ -336,9 +336,9 @@ fn test_symmetric_key_encryption_function(#[case] seed: u64, #[case] num_committ ) .unwrap(); - let encrypted_dst = runner.vm.add_memory_segment(); + let output_pointer = runner.vm.add_memory_segment(); implicit_args - .push(ImplicitArg::NonBuiltin(EndpointArg::Value(ValueArg::Single(encrypted_dst.into())))); + .push(ImplicitArg::NonBuiltin(EndpointArg::Value(ValueArg::Single(output_pointer.into())))); let (sn_private_keys, _) = add_memory_segment_and_load_explicit_arg(&mut runner, &sn_private_keys_vector); @@ -375,13 +375,13 @@ fn test_symmetric_key_encryption_function(#[case] seed: u64, #[case] num_committ panic!("Unexpected implicit return value"); }; - let actual_symmetric_keys_length = (encrypted_dst_end - encrypted_dst).unwrap(); + let actual_symmetric_keys_length = (encrypted_dst_end - output_pointer).unwrap(); assert_eq!(public_keys_vector.len(), actual_symmetric_keys_length); // Only try to get encrypted symmetric keys if there are keys to encrypt. let encrypted_symmetric_keys = if actual_symmetric_keys_length > 0 { let encrypted_range = - runner.vm.get_integer_range(encrypted_dst, actual_symmetric_keys_length).unwrap(); + runner.vm.get_integer_range(output_pointer, actual_symmetric_keys_length).unwrap(); encrypted_range.into_iter().map(|felt| *felt).collect() } else { vec![] diff --git a/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs index 7c1e9b742e5..ddc71b922b0 100644 --- a/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs +++ b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs @@ -45,7 +45,7 @@ pub(crate) fn compression_hint( let data_size = (data_end - data_start)?; let compressed_dst = - get_ptr_from_var_name(Ids::CompressedDst.into(), vm, ids_data, ap_tracking)?; + get_ptr_from_var_name(Ids::CompressedEnd.into(), vm, ids_data, ap_tracking)?; let data = vm.get_integer_range(data_start, data_size)?.into_iter().map(|f| *f).collect::>(); let compress_result = diff --git a/crates/starknet_os/src/hints/vars.rs b/crates/starknet_os/src/hints/vars.rs index 155d1c79ecf..c5dc907b231 100644 --- a/crates/starknet_os/src/hints/vars.rs +++ b/crates/starknet_os/src/hints/vars.rs @@ -147,7 +147,7 @@ define_string_enum! { (CompiledClassFact), (CompiledClassFacts), (CompiledClassHash), - (CompressedDst), + (CompressedEnd), (CompressedStart), (CompressStateUpdates), (ConstructorCalldata), From a2ec13f217daffbe10cc0752c999c0ef6369239d Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:59:16 +0300 Subject: [PATCH 075/313] papyrus_node: Papyrus cleanup - apollo storage README (#9621) --- crates/apollo_storage/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/apollo_storage/README.md b/crates/apollo_storage/README.md index e58a8e50901..cc380f32876 100644 --- a/crates/apollo_storage/README.md +++ b/crates/apollo_storage/README.md @@ -1,5 +1,5 @@ -# papyrus-storage +# apollo-storage ## Description -papyrus-storage provides a writing and reading interface for various Starknet data structures to a database, designed specifically for Papyrus, a Starknet node. +apollo-storage provides a writing and reading interface for various Starknet data structures to a database, designed specifically for Apollo, a Starknet sequencer. From 470b87b64cc1ffd3b39c8dad54979afe7257580e Mon Sep 17 00:00:00 2001 From: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:07:04 +0300 Subject: [PATCH 076/313] apollo_consensus_orchestrator: panic instead of infinite loop (#9631) --- .../src/sequencer_consensus_context.rs | 82 +++++++------------ .../src/validate_proposal.rs | 2 + 2 files changed, 32 insertions(+), 52 deletions(-) diff --git a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs index b469f9968e8..f9e0aa4c701 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -16,7 +16,7 @@ use apollo_batcher_types::batcher_types::{ ProposalId, StartHeightInput, }; -use apollo_batcher_types::communication::{BatcherClient, BatcherClientError}; +use apollo_batcher_types::communication::BatcherClient; use apollo_class_manager_types::transaction_converter::TransactionConverterTrait; use apollo_consensus::types::{ ConsensusContext, @@ -747,7 +747,7 @@ impl SequencerConsensusContext { async fn interrupt_active_proposal(&mut self) { if let Some((token, handle)) = self.active_proposal.take() { token.cancel(); - handle.await.expect("Proposal task failed, propogating panic"); + handle.await.expect("Proposal task failed, propagating panic"); } } @@ -755,19 +755,13 @@ impl SequencerConsensusContext { &mut self, proposal_id: ProposalId, ) -> DecisionReachedResponse { - loop { - let input = DecisionReachedInput { proposal_id }; - match self.deps.batcher.decision_reached(input).await { - Ok(response) => break response, - Err(BatcherClientError::BatcherError(e)) => { - panic!("Failed to add decision due to batcher error: {e:?}"); - } - Err(BatcherClientError::ClientError(e)) => { - error!("Failed to add decision due to client error: {e:?}"); - } - } - tokio::task::yield_now().await; - } + // TODO(Dafna): Properly handle errors. Not all errors should be propagated as panics. We + // should have a way to report an error and continue to the next height. + self.deps + .batcher + .decision_reached(DecisionReachedInput { proposal_id }) + .await + .expect("Failed to add decision due to batcher error: {e:?}") } async fn batcher_add_sync_block(&mut self, sync_block: SyncBlock) { @@ -775,50 +769,34 @@ impl SequencerConsensusContext { "Adding sync block to Batcher for height {}", sync_block.block_header_without_hash.block_number, ); - loop { - match self.deps.batcher.add_sync_block(sync_block.clone()).await { - Ok(_) => break, - Err(BatcherClientError::BatcherError(e)) => { - panic!("Failed to add sync block due to batcher error: {e:?}"); - } - Err(BatcherClientError::ClientError(e)) => { - error!("Failed to add sync block due to client error: {e:?}"); - } - } - tokio::task::yield_now().await; - } + // TODO(Dafna): Properly handle errors. Not all errors should be propagated as panics. We + // should have a way to report an error and continue to the next height. + self.deps + .batcher + .add_sync_block(sync_block.clone()) + .await + .expect("Failed to add sync block due to batcher error: {e:?}"); } // `add_new_block` returns immediately, it doesn't wait for sync to fully process the block. async fn sync_add_new_block(&mut self, sync_block: SyncBlock) { - loop { - match self.deps.state_sync_client.add_new_block(sync_block.clone()).await { - Ok(_) => break, - Err(StateSyncClientError::StateSyncError(e)) => { - panic!("Failed to add new block due to sync error: {e:?}"); - } - Err(StateSyncClientError::ClientError(e)) => { - error!("Failed to add new block due to client error: {e:?}"); - } - } - tokio::task::yield_now().await; - } + // TODO(Dafna): Properly handle errors. Not all errors should be propagated as panics. We + // should have a way to report an error and continue to the next height. + self.deps + .state_sync_client + .add_new_block(sync_block.clone()) + .await + .expect("Failed to add new block due to sync error: {e:?}"); } async fn batcher_start_height(&mut self, height: BlockNumber) { - loop { - let input = StartHeightInput { height }; - match self.deps.batcher.start_height(input).await { - Ok(_) => break, - Err(BatcherClientError::BatcherError(e)) => { - panic!("Failed to start height due to batcher error: height={height} {e:?}"); - } - Err(BatcherClientError::ClientError(e)) => { - error!("Failed to start height due to client error: height={height} {e:?}"); - } - } - tokio::task::yield_now().await; - } + // TODO(Dafna): Properly handle errors. Not all errors should be propagated as panics. We + // should have a way to report an error and continue to the next height. + self.deps + .batcher + .start_height(StartHeightInput { height }) + .await + .expect("Failed to start height due to batcher error: {e:?}"); } } diff --git a/crates/apollo_consensus_orchestrator/src/validate_proposal.rs b/crates/apollo_consensus_orchestrator/src/validate_proposal.rs index 04aa63e91d0..34f58ba937c 100644 --- a/crates/apollo_consensus_orchestrator/src/validate_proposal.rs +++ b/crates/apollo_consensus_orchestrator/src/validate_proposal.rs @@ -561,6 +561,8 @@ async fn batcher_abort_proposal(batcher: &dyn BatcherClient, proposal_id: Propos return; } + // TODO(Dafna): Properly handle errors. Not all errors should be propagated as panics. + // We should have a way to report an error and continue to the next height. Err(BatcherClientError::BatcherError(e)) => { panic!("Batcher failed to abort proposal {proposal_id:?}: {e:?}"); } From 505b38b3b817a20a5c026588585cb27cacdfc2a8 Mon Sep 17 00:00:00 2001 From: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:07:55 +0300 Subject: [PATCH 077/313] apollo_consensus: minor refactor to panics in the code. (#9613) --- crates/apollo_consensus/src/manager.rs | 3 +++ .../src/single_height_consensus.rs | 27 ++++++++++--------- crates/apollo_consensus/src/state_machine.rs | 2 +- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/crates/apollo_consensus/src/manager.rs b/crates/apollo_consensus/src/manager.rs index 5d570f5b348..2fcd9ad4a0d 100644 --- a/crates/apollo_consensus/src/manager.rs +++ b/crates/apollo_consensus/src/manager.rs @@ -84,7 +84,10 @@ where register_metrics(); // Add a short delay to allow peers to connect and avoid "InsufficientPeers" error tokio::time::sleep(run_consensus_args.consensus_delay).await; + + // Ensure the node begins observing consensus no later than it becomes active. assert!(run_consensus_args.start_observe_height <= run_consensus_args.start_active_height); + let mut current_height = run_consensus_args.start_observe_height; let mut manager = MultiHeightManager::new( run_consensus_args.validator_id, diff --git a/crates/apollo_consensus/src/single_height_consensus.rs b/crates/apollo_consensus/src/single_height_consensus.rs index adbd651aa44..5388e6ad54e 100644 --- a/crates/apollo_consensus/src/single_height_consensus.rs +++ b/crates/apollo_consensus/src/single_height_consensus.rs @@ -295,10 +295,10 @@ impl SingleHeightConsensus { // this round. While this prevents spam attacks it also prevents re-receiving after // a network issue. let old = self.proposals.insert(round, proposal_id); - let old = old.unwrap_or_else(|| { - panic!("Proposal entry should exist from init. round={round}") - }); - assert!(old.is_none(), "Proposal already exists for this round={round}. {old:?}"); + assert!( + old.is_some_and(|p| p.is_none()), + "Proposal entry for round {round} should exist and be empty: {old:?}" + ); let sm_events = self.state_machine.handle_event( StateMachineEvent::Proposal(proposal_id, round, valid_round), &leader_fn, @@ -479,14 +479,15 @@ impl SingleHeightConsensus { }; let proposal_id = proposal_id.expect("Reproposal must have a valid ID"); - let id = self - .proposals - .get(&valid_round) - .unwrap_or_else(|| panic!("A proposal should exist for valid_round: {valid_round}")) - .unwrap_or_else(|| { - panic!("A valid proposal should exist for valid_round: {valid_round}") - }); - assert_eq!(id, proposal_id, "reproposal should match the stored proposal"); + // Make sure there is an existing proposal for the valid round and it matches the proposal + // ID. + let existing = self.proposals.get(&valid_round).and_then(|&inner| inner); + assert!( + existing.is_some_and(|id| id == proposal_id), + "A proposal with ID {proposal_id:?} should exist for valid_round: {valid_round}. \ + Found: {existing:?}", + ); + let old = self.proposals.insert(round, Some(proposal_id)); assert!(old.is_none(), "There should be no proposal for round {round}."); let init = ProposalInit { @@ -496,7 +497,7 @@ impl SingleHeightConsensus { valid_round: Some(valid_round), }; CONSENSUS_REPROPOSALS.increment(1); - context.repropose(id, init).await; + context.repropose(proposal_id, init).await; } async fn handle_state_machine_vote( diff --git a/crates/apollo_consensus/src/state_machine.rs b/crates/apollo_consensus/src/state_machine.rs index 791cf63a65c..6d1a01f6506 100644 --- a/crates/apollo_consensus/src/state_machine.rs +++ b/crates/apollo_consensus/src/state_machine.rs @@ -204,7 +204,7 @@ impl StateMachine { return output_events; } StateMachineEvent::GetProposal(_, _) => { - // LOC 18. + // LOC 18 in the paper. assert!(resultant_events.is_empty()); assert!(!self.is_observer); output_events.push_back(e); From bcaddf8c69b974a38c5f6253e2f91ad0026e944f Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:11:12 +0300 Subject: [PATCH 078/313] apollo_protobuf: use ProposalCommitment instead of BlockHash in fin (#9434) --- Cargo.lock | 1 + crates/apollo_consensus/src/manager_test.rs | 10 ++-- .../src/single_height_consensus.rs | 27 ++++++---- .../src/single_height_consensus_test.rs | 11 +++-- .../src/state_machine_test.rs | 3 +- crates/apollo_consensus/src/test_utils.rs | 16 +++--- crates/apollo_consensus/src/types.rs | 4 +- .../src/build_proposal.rs | 4 +- .../src/build_proposal_test.rs | 6 +-- .../src/sequencer_consensus_context_test.rs | 49 +++++++++++-------- .../src/validate_proposal.rs | 4 +- .../src/validate_proposal_test.rs | 31 ++++++++---- crates/apollo_protobuf/Cargo.toml | 1 + crates/apollo_protobuf/src/consensus.rs | 27 ++++++++-- .../src/converters/consensus.rs | 34 ++++++++++--- .../src/converters/test_instances.rs | 9 ++-- 16 files changed, 153 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e0161302a2..88951142bd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2143,6 +2143,7 @@ version = "0.16.0-rc.0" dependencies = [ "apollo_test_utils", "bytes", + "derive_more 0.99.20", "indexmap 2.11.0", "lazy_static", "papyrus_common", diff --git a/crates/apollo_consensus/src/manager_test.rs b/crates/apollo_consensus/src/manager_test.rs index ceeda301207..da1faf3c47b 100644 --- a/crates/apollo_consensus/src/manager_test.rs +++ b/crates/apollo_consensus/src/manager_test.rs @@ -8,12 +8,12 @@ use apollo_network::network_manager::test_utils::{ TestSubscriberChannels, }; use apollo_network_types::network_types::BroadcastedMessageMetadata; -use apollo_protobuf::consensus::{Vote, DEFAULT_VALIDATOR_ID}; +use apollo_protobuf::consensus::{ProposalCommitment, Vote, DEFAULT_VALIDATOR_ID}; use apollo_test_utils::{get_rng, GetTestInstance}; use futures::channel::{mpsc, oneshot}; use futures::{FutureExt, SinkExt}; use lazy_static::lazy_static; -use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::block::BlockNumber; use starknet_types_core::felt::Felt; use super::{run_consensus, MultiHeightManager, RunHeightRes}; @@ -59,7 +59,7 @@ fn expect_validate_proposal(context: &mut MockTestContext, block_hash: Felt, tim .expect_validate_proposal() .returning(move |_, _, _| { let (block_sender, block_receiver) = oneshot::channel(); - block_sender.send(BlockHash(block_hash)).unwrap(); + block_sender.send(ProposalCommitment(block_hash)).unwrap(); block_receiver }) .times(times); @@ -67,7 +67,7 @@ fn expect_validate_proposal(context: &mut MockTestContext, block_hash: Felt, tim fn assert_decision(res: RunHeightRes, id: Felt) { match res { - RunHeightRes::Decision(decision) => assert_eq!(decision.block, BlockHash(id)), + RunHeightRes::Decision(decision) => assert_eq!(decision.block, ProposalCommitment(id)), _ => panic!("Expected decision"), } } @@ -156,7 +156,7 @@ async fn run_consensus_sync() { context.expect_broadcast().returning(move |_| Ok(())); context .expect_decision_reached() - .withf(move |block, votes| *block == BlockHash(Felt::TWO) && votes[0].height == 2) + .withf(move |block, votes| *block == ProposalCommitment(Felt::TWO) && votes[0].height == 2) .return_once(move |_, _| { decision_tx.send(()).unwrap(); Ok(()) diff --git a/crates/apollo_consensus/src/single_height_consensus.rs b/crates/apollo_consensus/src/single_height_consensus.rs index 5388e6ad54e..6f11e9e96f3 100644 --- a/crates/apollo_consensus/src/single_height_consensus.rs +++ b/crates/apollo_consensus/src/single_height_consensus.rs @@ -354,12 +354,14 @@ impl SingleHeightConsensus { } let (votes, sm_vote) = match vote.vote_type { - VoteType::Prevote => { - (&mut self.prevotes, StateMachineEvent::Prevote(vote.block_hash, vote.round)) - } - VoteType::Precommit => { - (&mut self.precommits, StateMachineEvent::Precommit(vote.block_hash, vote.round)) - } + VoteType::Prevote => ( + &mut self.prevotes, + StateMachineEvent::Prevote(vote.proposal_commitment, vote.round), + ), + VoteType::Precommit => ( + &mut self.precommits, + StateMachineEvent::Precommit(vote.proposal_commitment, vote.round), + ), }; match votes.entry((vote.round, vote.voter)) { @@ -368,7 +370,7 @@ impl SingleHeightConsensus { } Entry::Occupied(entry) => { let old = entry.get(); - if old.block_hash != vote.block_hash { + if old.proposal_commitment != vote.proposal_commitment { warn!("Conflicting votes: old={:?}, new={:?}", old, vote); CONSENSUS_CONFLICTING_VOTES.increment(1); return Ok(ShcReturn::Tasks(Vec::new())); @@ -529,7 +531,7 @@ impl SingleHeightConsensus { vote_type, height: self.height.0, round, - block_hash: proposal_id, + proposal_commitment: proposal_id, voter: self.id, }; if let Some(old) = votes.insert((round, self.id), vote.clone()) { @@ -577,7 +579,8 @@ impl SingleHeightConsensus { })?; if block != proposal_id { return Err(invalid_decision(format!( - "StateMachine block hash should match the stored block. Shc.block_id: {block}" + "StateMachine proposal commitment should match the stored block. Shc.block_id: \ + {block}" ))); } let supporting_precommits: Vec = self @@ -585,7 +588,11 @@ impl SingleHeightConsensus { .iter() .filter_map(|v| { let vote = self.precommits.get(&(round, *v))?; - if vote.block_hash == Some(proposal_id) { Some(vote.clone()) } else { None } + if vote.proposal_commitment == Some(proposal_id) { + Some(vote.clone()) + } else { + None + } }) .collect(); diff --git a/crates/apollo_consensus/src/single_height_consensus_test.rs b/crates/apollo_consensus/src/single_height_consensus_test.rs index 3867eff35ce..ba41aa43a25 100644 --- a/crates/apollo_consensus/src/single_height_consensus_test.rs +++ b/crates/apollo_consensus/src/single_height_consensus_test.rs @@ -3,7 +3,7 @@ use apollo_protobuf::consensus::{ProposalFin, ProposalInit, Vote, DEFAULT_VALIDA use futures::channel::{mpsc, oneshot}; use futures::SinkExt; use lazy_static::lazy_static; -use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::block::BlockNumber; use starknet_types_core::felt::Felt; use test_case::test_case; @@ -11,7 +11,7 @@ use super::SingleHeightConsensus; use crate::single_height_consensus::{ShcReturn, ShcTask}; use crate::state_machine::StateMachineEvent; use crate::test_utils::{precommit, prevote, MockTestContext, TestBlock, TestProposalPart}; -use crate::types::ValidatorId; +use crate::types::{ProposalCommitment, ValidatorId}; use crate::votes_threshold::QuorumType; lazy_static! { @@ -21,7 +21,8 @@ lazy_static! { static ref VALIDATOR_ID_3: ValidatorId = (DEFAULT_VALIDATOR_ID + 3).into(); static ref VALIDATORS: Vec = vec![*PROPOSER_ID, *VALIDATOR_ID_1, *VALIDATOR_ID_2, *VALIDATOR_ID_3]; - static ref BLOCK: TestBlock = TestBlock { content: vec![1, 2, 3], id: BlockHash(Felt::ONE) }; + static ref BLOCK: TestBlock = + TestBlock { content: vec![1, 2, 3], id: ProposalCommitment(Felt::ONE) }; static ref PROPOSAL_INIT: ProposalInit = ProposalInit { proposer: *PROPOSER_ID, ..Default::default() }; static ref TIMEOUTS: TimeoutsConfig = TimeoutsConfig::default(); @@ -38,14 +39,14 @@ const CHANNEL_SIZE: usize = 1; fn prevote_task(block_felt: Option, round: u32) -> ShcTask { ShcTask::Prevote( TIMEOUTS.prevote_timeout, - StateMachineEvent::Prevote(block_felt.map(BlockHash), round), + StateMachineEvent::Prevote(block_felt.map(ProposalCommitment), round), ) } fn precommit_task(block_felt: Option, round: u32) -> ShcTask { ShcTask::Precommit( TIMEOUTS.precommit_timeout, - StateMachineEvent::Precommit(block_felt.map(BlockHash), round), + StateMachineEvent::Precommit(block_felt.map(ProposalCommitment), round), ) } diff --git a/crates/apollo_consensus/src/state_machine_test.rs b/crates/apollo_consensus/src/state_machine_test.rs index 44a1888dfbc..3a4cb34f609 100644 --- a/crates/apollo_consensus/src/state_machine_test.rs +++ b/crates/apollo_consensus/src/state_machine_test.rs @@ -2,7 +2,6 @@ use std::collections::VecDeque; use apollo_protobuf::consensus::DEFAULT_VALIDATOR_ID; use lazy_static::lazy_static; -use starknet_api::block::BlockHash; use starknet_types_core::felt::Felt; use test_case::test_case; @@ -16,7 +15,7 @@ lazy_static! { static ref VALIDATOR_ID: ValidatorId = (DEFAULT_VALIDATOR_ID + 1).into(); } -const PROPOSAL_ID: Option = Some(BlockHash(Felt::ONE)); +const PROPOSAL_ID: Option = Some(ProposalCommitment(Felt::ONE)); const ROUND: Round = 0; struct TestWrapper ValidatorId> { diff --git a/crates/apollo_consensus/src/test_utils.rs b/crates/apollo_consensus/src/test_utils.rs index 6a5447cf3bd..01a62155b6c 100644 --- a/crates/apollo_consensus/src/test_utils.rs +++ b/crates/apollo_consensus/src/test_utils.rs @@ -1,20 +1,20 @@ use std::time::Duration; -use apollo_protobuf::consensus::{ProposalInit, Vote, VoteType}; +use apollo_protobuf::consensus::{ProposalCommitment, ProposalInit, Vote, VoteType}; use apollo_protobuf::converters::ProtobufConversionError; use async_trait::async_trait; use futures::channel::{mpsc, oneshot}; use mockall::mock; -use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::block::BlockNumber; use starknet_types_core::felt::Felt; -use crate::types::{ConsensusContext, ConsensusError, ProposalCommitment, Round, ValidatorId}; +use crate::types::{ConsensusContext, ConsensusError, Round, ValidatorId}; /// Define a consensus block which can be used to enable auto mocking Context. #[derive(Debug, PartialEq, Clone)] pub struct TestBlock { pub content: Vec, - pub id: BlockHash, + pub id: ProposalCommitment, } #[derive(Debug, PartialEq, Clone)] @@ -97,13 +97,13 @@ mock! { } pub fn prevote(block_felt: Option, height: u64, round: u32, voter: ValidatorId) -> Vote { - let block_hash = block_felt.map(BlockHash); - Vote { vote_type: VoteType::Prevote, height, round, block_hash, voter } + let proposal_commitment = block_felt.map(ProposalCommitment); + Vote { vote_type: VoteType::Prevote, height, round, proposal_commitment, voter } } pub fn precommit(block_felt: Option, height: u64, round: u32, voter: ValidatorId) -> Vote { - let block_hash = block_felt.map(BlockHash); - Vote { vote_type: VoteType::Precommit, height, round, block_hash, voter } + let proposal_commitment = block_felt.map(ProposalCommitment); + Vote { vote_type: VoteType::Precommit, height, round, proposal_commitment, voter } } pub fn proposal_init(height: u64, round: u32, proposer: ValidatorId) -> ProposalInit { ProposalInit { height: BlockNumber(height), round, proposer, ..Default::default() } diff --git a/crates/apollo_consensus/src/types.rs b/crates/apollo_consensus/src/types.rs index afca6e34327..07454929dbc 100644 --- a/crates/apollo_consensus/src/types.rs +++ b/crates/apollo_consensus/src/types.rs @@ -8,11 +8,12 @@ use apollo_network::network_manager::{ GenericReceiver, }; use apollo_network_types::network_types::BroadcastedMessageMetadata; +pub use apollo_protobuf::consensus::ProposalCommitment; use apollo_protobuf::consensus::{ProposalInit, Vote}; use apollo_protobuf::converters::ProtobufConversionError; use async_trait::async_trait; use futures::channel::{mpsc, oneshot}; -use starknet_api::block::{BlockHash, BlockNumber}; +use starknet_api::block::BlockNumber; use starknet_api::core::ContractAddress; /// Used to identify the node by consensus. @@ -22,7 +23,6 @@ use starknet_api::core::ContractAddress; // TODO(matan): Determine the actual type of NodeId. pub type ValidatorId = ContractAddress; pub type Round = u32; -pub type ProposalCommitment = BlockHash; /// Interface for consensus to call out to the node. /// diff --git a/crates/apollo_consensus_orchestrator/src/build_proposal.rs b/crates/apollo_consensus_orchestrator/src/build_proposal.rs index 39134803117..29077a1e7f9 100644 --- a/crates/apollo_consensus_orchestrator/src/build_proposal.rs +++ b/crates/apollo_consensus_orchestrator/src/build_proposal.rs @@ -26,7 +26,7 @@ use apollo_protobuf::consensus::{ TransactionBatch, }; use apollo_time::time::{Clock, DateTime}; -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; +use starknet_api::block::{BlockNumber, GasPrice}; use starknet_api::consensus_transaction::InternalConsensusTransaction; use starknet_api::core::ContractAddress; use starknet_api::data_availability::L1DataAvailabilityMode; @@ -241,7 +241,7 @@ async fn get_proposal_content( .expect("Failed to broadcast proposal content"); } GetProposalContent::Finished { id, final_n_executed_txs } => { - let proposal_commitment = BlockHash(id.state_diff_commitment.0.0); + let proposal_commitment = ProposalCommitment(id.state_diff_commitment.0.0); content = truncate_to_executed_txs(&mut content, final_n_executed_txs); info!( diff --git a/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs b/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs index 907eb7d7542..e80dfdd6e5b 100644 --- a/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs +++ b/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs @@ -12,7 +12,7 @@ use apollo_class_manager_types::transaction_converter::{ MockTransactionConverterTrait, TransactionConverterError, }; -use apollo_consensus::types::Round; +use apollo_consensus::types::{ProposalCommitment as ConsensusProposalCommitment, Round}; use apollo_consensus_orchestrator_config::config::ContextConfig; use apollo_infra::component_client::ClientError; use apollo_protobuf::consensus::{ConsensusBlockInfo, ProposalInit, ProposalPart}; @@ -22,7 +22,7 @@ use assert_matches::assert_matches; use blockifier::abi::constants::STORED_BLOCK_HASH_BUFFER; use futures::channel::mpsc; use num_rational::Ratio; -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; +use starknet_api::block::{BlockNumber, GasPrice}; use starknet_api::core::{ClassHash, ContractAddress}; use starknet_api::data_availability::L1DataAvailabilityMode; use tokio_util::sync::CancellationToken; @@ -147,7 +147,7 @@ async fn build_proposal_succeed() { tokio::time::sleep(Duration::from_millis(100)).await; let res = build_proposal(proposal_args.into()).await.unwrap(); - assert_eq!(res, BlockHash::default()); + assert_eq!(res, ConsensusProposalCommitment::default()); } #[tokio::test] 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 35c67a1a15c..d42198f75f9 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs @@ -13,7 +13,14 @@ use apollo_l1_gas_price_types::errors::{ L1GasPriceProviderError, }; use apollo_l1_gas_price_types::{MockL1GasPriceProviderClient, PriceInfo, DEFAULT_ETH_TO_FRI_RATE}; -use apollo_protobuf::consensus::{ProposalFin, ProposalInit, ProposalPart, TransactionBatch, Vote}; +use apollo_protobuf::consensus::{ + ProposalCommitment, + ProposalFin, + ProposalInit, + ProposalPart, + TransactionBatch, + Vote, +}; use apollo_time::time::MockClock; use chrono::{TimeZone, Utc}; use futures::channel::mpsc; @@ -23,7 +30,6 @@ use futures::{FutureExt, SinkExt, StreamExt}; use metrics_exporter_prometheus::PrometheusBuilder; use rstest::rstest; use starknet_api::block::{ - BlockHash, BlockNumber, GasPrice, TEMP_ETH_BLOB_GAS_FEE_IN_WEI, @@ -83,7 +89,7 @@ async fn validate_proposal_success() { .unwrap(); content_sender .send(ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), })) .await .unwrap(); @@ -145,7 +151,7 @@ async fn validate_then_repropose(#[case] execute_all_txs: bool) { .await .unwrap(); let fin = ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), }); content_sender.send(fin.clone()).await.unwrap(); let fin_receiver = @@ -154,7 +160,7 @@ async fn validate_then_repropose(#[case] execute_all_txs: bool) { assert_eq!(fin_receiver.await.unwrap().0, STATE_DIFF_COMMITMENT.0.0); let init = ProposalInit { round: 1, ..Default::default() }; - context.repropose(BlockHash(STATE_DIFF_COMMITMENT.0.0), init).await; + context.repropose(ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), init).await; let (_, mut receiver) = network.outbound_proposal_receiver.next().await.unwrap(); assert_eq!(receiver.next().await.unwrap(), ProposalPart::Init(init)); assert_eq!(receiver.next().await.unwrap(), block_info); @@ -185,7 +191,7 @@ async fn proposals_from_different_rounds() { let prop_part_executed_count = ProposalPart::ExecutedTransactionCount(INTERNAL_TX_BATCH.len().try_into().unwrap()); let prop_part_fin = ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), }); // The proposal from the past round is ignored. @@ -255,7 +261,7 @@ async fn interrupt_active_proposal() { .unwrap(); content_sender_1 .send(ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), })) .await .unwrap(); @@ -304,7 +310,7 @@ async fn build_proposal() { assert_eq!( receiver.next().await.unwrap(), ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), }) ); assert!(receiver.next().await.is_none()); @@ -405,7 +411,7 @@ async fn propose_then_repropose(#[case] execute_all_txs: bool) { // Re-propose. context .repropose( - BlockHash(STATE_DIFF_COMMITMENT.0.0), + ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), ProposalInit { round: 1, ..Default::default() }, ) .await; @@ -504,7 +510,7 @@ async fn gas_price_limits(#[case] maximum: bool) { .unwrap(); content_sender .send(ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), })) .await .unwrap(); @@ -513,7 +519,7 @@ async fn gas_price_limits(#[case] maximum: bool) { // the proposal should be still be valid due to the clamping of limit prices. let fin_receiver = context.validate_proposal(ProposalInit::default(), TIMEOUT, content_receiver).await; - assert_eq!(fin_receiver.await, Ok(BlockHash(STATE_DIFF_COMMITMENT.0.0))); + assert_eq!(fin_receiver.await, Ok(ProposalCommitment(STATE_DIFF_COMMITMENT.0.0))); } #[tokio::test] @@ -565,7 +571,10 @@ async fn decision_reached_sends_correct_values() { ..Default::default() }; - context.decision_reached(BlockHash(STATE_DIFF_COMMITMENT.0.0), vec![vote]).await.unwrap(); + context + .decision_reached(ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), vec![vote]) + .await + .unwrap(); let metrics = recorder.handle().render(); CONSENSUS_L2_GAS_PRICE @@ -638,7 +647,7 @@ async fn oracle_fails_on_startup(#[case] l1_oracle_failure: bool) { assert_eq!( receiver.next().await.unwrap(), ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), }) ); assert!(receiver.next().await.is_none()); @@ -726,22 +735,22 @@ async fn oracle_fails_on_second_block(#[case] l1_oracle_failure: bool) { .unwrap(); content_sender .send(ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), })) .await .unwrap(); let fin_receiver = context.validate_proposal(ProposalInit::default(), TIMEOUT, content_receiver).await; content_sender.close_channel(); - let block_hash = fin_receiver.await.unwrap().0; - assert_eq!(block_hash, STATE_DIFF_COMMITMENT.0.0); + let proposal_commitment = fin_receiver.await.unwrap(); + assert_eq!(proposal_commitment.0, STATE_DIFF_COMMITMENT.0.0); // Decision reached context .decision_reached( - BlockHash(block_hash), - vec![Vote { block_hash: Some(BlockHash(block_hash)), ..Default::default() }], + proposal_commitment, + vec![Vote { proposal_commitment: Some(proposal_commitment), ..Default::default() }], ) .await .unwrap(); @@ -779,7 +788,7 @@ async fn oracle_fails_on_second_block(#[case] l1_oracle_failure: bool) { assert_eq!( receiver.next().await.unwrap(), ProposalPart::Fin(ProposalFin { - proposal_commitment: BlockHash(STATE_DIFF_COMMITMENT.0.0), + proposal_commitment: ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), }) ); assert!(receiver.next().await.is_none()); @@ -820,7 +829,7 @@ async fn constant_l2_gas_price_behavior( // Run proposal and decision logic. let _fin_receiver = context.build_proposal(ProposalInit::default(), TIMEOUT).await.await; context - .decision_reached(BlockHash(STATE_DIFF_COMMITMENT.0.0), vec![Vote::default()]) + .decision_reached(ProposalCommitment(STATE_DIFF_COMMITMENT.0.0), vec![Vote::default()]) .await .unwrap(); diff --git a/crates/apollo_consensus_orchestrator/src/validate_proposal.rs b/crates/apollo_consensus_orchestrator/src/validate_proposal.rs index 34f58ba937c..f7ec2e5d7ff 100644 --- a/crates/apollo_consensus_orchestrator/src/validate_proposal.rs +++ b/crates/apollo_consensus_orchestrator/src/validate_proposal.rs @@ -23,7 +23,7 @@ use apollo_state_sync_types::communication::StateSyncClient; use apollo_time::time::{sleep_until, Clock, DateTime}; use futures::channel::mpsc; use futures::StreamExt; -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; +use starknet_api::block::{BlockNumber, GasPrice}; use starknet_api::consensus_transaction::InternalConsensusTransaction; use starknet_api::data_availability::L1DataAvailabilityMode; use starknet_api::transaction::TransactionHash; @@ -463,7 +463,7 @@ async fn handle_proposal_part( unreachable!("Unexpected batcher status for fin: {status:?}"); } }; - let batcher_block_id = BlockHash(response_id.state_diff_commitment.0.0); + let batcher_block_id = ProposalCommitment(response_id.state_diff_commitment.0.0); info!( network_block_id = ?fin.proposal_commitment, diff --git a/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs b/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs index e2430fc9043..4452574d2a6 100644 --- a/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs +++ b/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs @@ -12,13 +12,18 @@ use apollo_batcher_types::batcher_types::{ use apollo_batcher_types::communication::BatcherClientError; use apollo_consensus_orchestrator_config::config::ContextConfig; use apollo_infra::component_client::ClientError; -use apollo_protobuf::consensus::{ProposalFin, ProposalPart, TransactionBatch}; +use apollo_protobuf::consensus::{ + ProposalCommitment as ConsensusProposalCommitment, + ProposalFin, + ProposalPart, + TransactionBatch, +}; use assert_matches::assert_matches; use futures::channel::mpsc; use futures::SinkExt; use num_rational::Ratio; use rstest::rstest; -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; +use starknet_api::block::{BlockNumber, GasPrice}; use starknet_api::core::StateDiffCommitment; use starknet_api::data_availability::L1DataAvailabilityMode; use starknet_api::hash::PoseidonHash; @@ -123,12 +128,14 @@ async fn validate_empty_proposal() { let (proposal_args, mut content_sender) = create_proposal_validate_arguments(); // Send an empty proposal. content_sender - .send(ProposalPart::Fin(ProposalFin { proposal_commitment: BlockHash::default() })) + .send(ProposalPart::Fin(ProposalFin { + proposal_commitment: ConsensusProposalCommitment::default(), + })) .await .unwrap(); let res = validate_proposal(proposal_args.into()).await; - assert_matches!(res, Ok(val) if val == BlockHash::default()); + assert_matches!(res, Ok(val) if val == ConsensusProposalCommitment::default()); } #[tokio::test] @@ -150,12 +157,14 @@ async fn validate_proposal_success() { .await .unwrap(); content_sender - .send(ProposalPart::Fin(ProposalFin { proposal_commitment: BlockHash::default() })) + .send(ProposalPart::Fin(ProposalFin { + proposal_commitment: ConsensusProposalCommitment::default(), + })) .await .unwrap(); let res = validate_proposal(proposal_args.into()).await; - assert_matches!(res, Ok(val) if val == BlockHash::default()); + assert_matches!(res, Ok(val) if val == ConsensusProposalCommitment::default()); } #[tokio::test] @@ -264,7 +273,9 @@ async fn receive_fin_without_executed_transaction_count() { content_sender.send(ProposalPart::BlockInfo(block_info)).await.unwrap(); // Send Fin part without sending executed transaction count. content_sender - .send(ProposalPart::Fin(ProposalFin { proposal_commitment: BlockHash::default() })) + .send(ProposalPart::Fin(ProposalFin { + proposal_commitment: ConsensusProposalCommitment::default(), + })) .await .unwrap(); @@ -334,7 +345,7 @@ async fn proposal_fin_mismatch() { .await .unwrap(); // Send Fin part. - let received_fin = BlockHash::default(); + let received_fin = ConsensusProposalCommitment::default(); content_sender .send(ProposalPart::Fin(ProposalFin { proposal_commitment: received_fin })) .await @@ -372,7 +383,9 @@ async fn batcher_returns_invalid_proposal() { .await .unwrap(); content_sender - .send(ProposalPart::Fin(ProposalFin { proposal_commitment: BlockHash::default() })) + .send(ProposalPart::Fin(ProposalFin { + proposal_commitment: ConsensusProposalCommitment::default(), + })) .await .unwrap(); diff --git a/crates/apollo_protobuf/Cargo.toml b/crates/apollo_protobuf/Cargo.toml index 080450b4548..ab4a083af13 100644 --- a/crates/apollo_protobuf/Cargo.toml +++ b/crates/apollo_protobuf/Cargo.toml @@ -17,6 +17,7 @@ required-features = ["bin-deps"] [dependencies] apollo_test_utils = { workspace = true, optional = true } bytes.workspace = true +derive_more.workspace = true indexmap.workspace = true lazy_static.workspace = true papyrus_common.workspace = true diff --git a/crates/apollo_protobuf/src/consensus.rs b/crates/apollo_protobuf/src/consensus.rs index 6d638f1f7e6..aa2e43e7c6b 100644 --- a/crates/apollo_protobuf/src/consensus.rs +++ b/crates/apollo_protobuf/src/consensus.rs @@ -7,12 +7,29 @@ use std::fmt::Display; use bytes::{Buf, BufMut}; use prost::DecodeError; use serde::{Deserialize, Serialize}; -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; +use starknet_api::block::{BlockNumber, GasPrice}; use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::core::ContractAddress; use starknet_api::data_availability::L1DataAvailabilityMode; +use starknet_api::hash::StarkHash; use crate::converters::ProtobufConversionError; +#[derive( + Debug, + Default, + Copy, + Clone, + Eq, + PartialEq, + Hash, + Deserialize, + Serialize, + PartialOrd, + Ord, + derive_more::Display, + derive_more::Deref, +)] +pub struct ProposalCommitment(pub StarkHash); pub trait IntoFromProto: Into> + TryFrom, Error = ProtobufConversionError> {} impl IntoFromProto for T where @@ -32,7 +49,7 @@ pub struct Vote { pub vote_type: VoteType, pub height: u64, pub round: u32, - pub block_hash: Option, + pub proposal_commitment: Option, pub voter: ContractAddress, } @@ -101,12 +118,12 @@ pub struct TransactionBatch { pub transactions: Vec, } -/// The proposal is done when receiving this fin message, which contains the block hash. +/// The proposal is done when receiving this fin message, which contains the proposal commitment. #[derive(Debug, Clone, PartialEq)] pub struct ProposalFin { - /// The block hash of the proposed block. + /// The commitment identifying the proposed block. /// TODO(Matan): Consider changing the content ID to a signature. - pub proposal_commitment: BlockHash, + pub proposal_commitment: ProposalCommitment, } /// A part of the proposal. diff --git a/crates/apollo_protobuf/src/converters/consensus.rs b/crates/apollo_protobuf/src/converters/consensus.rs index 7512eedb0ce..0133997e6a4 100644 --- a/crates/apollo_protobuf/src/converters/consensus.rs +++ b/crates/apollo_protobuf/src/converters/consensus.rs @@ -5,7 +5,7 @@ mod consensus_test; use std::convert::{TryFrom, TryInto}; use prost::Message; -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; +use starknet_api::block::{BlockNumber, GasPrice}; use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::hash::StarkHash; @@ -17,6 +17,7 @@ use super::common::{ use crate::consensus::{ ConsensusBlockInfo, IntoFromProto, + ProposalCommitment, ProposalFin, ProposalInit, ProposalPart, @@ -29,6 +30,21 @@ use crate::consensus::{ use crate::converters::ProtobufConversionError; use crate::{auto_impl_into_and_try_from_vec_u8, protobuf}; +impl TryFrom for ProposalCommitment { + type Error = ProtobufConversionError; + + fn try_from(value: protobuf::Hash) -> Result { + let stark_hash: StarkHash = value.try_into()?; + Ok(ProposalCommitment(stark_hash)) + } +} + +impl From for protobuf::Hash { + fn from(value: ProposalCommitment) -> Self { + value.0.into() + } +} + impl TryFrom for VoteType { type Error = ProtobufConversionError; @@ -57,11 +73,14 @@ impl TryFrom for Vote { let height = value.height; let round = value.round; - let block_hash: Option = - value.block_hash.map(|block_hash| block_hash.try_into()).transpose()?.map(BlockHash); + let proposal_commitment: Option = value + .block_hash + .map(|block_hash| block_hash.try_into()) + .transpose()? + .map(ProposalCommitment); let voter = value.voter.ok_or(missing("voter"))?.try_into()?; - Ok(Vote { vote_type, height, round, block_hash, voter }) + Ok(Vote { vote_type, height, round, proposal_commitment, voter }) } } @@ -76,7 +95,7 @@ impl From for protobuf::Vote { vote_type: i32::from(vote_type), height: value.height, round: value.round, - block_hash: value.block_hash.map(|hash| hash.0.into()), + block_hash: value.proposal_commitment.map(|hash| hash.0.into()), voter: Some(value.voter.into()), } } @@ -258,16 +277,15 @@ auto_impl_into_and_try_from_vec_u8!(TransactionBatch, protobuf::TransactionBatch impl TryFrom for ProposalFin { type Error = ProtobufConversionError; fn try_from(value: protobuf::ProposalFin) -> Result { - let proposal_commitment: StarkHash = + let proposal_commitment: ProposalCommitment = value.proposal_commitment.ok_or(missing("proposal_commitment"))?.try_into()?; - let proposal_commitment = BlockHash(proposal_commitment); Ok(ProposalFin { proposal_commitment }) } } impl From for protobuf::ProposalFin { fn from(value: ProposalFin) -> Self { - protobuf::ProposalFin { proposal_commitment: Some(value.proposal_commitment.0.into()) } + protobuf::ProposalFin { proposal_commitment: Some(value.proposal_commitment.into()) } } } diff --git a/crates/apollo_protobuf/src/converters/test_instances.rs b/crates/apollo_protobuf/src/converters/test_instances.rs index 15d2549ee11..80df71b5f4b 100644 --- a/crates/apollo_protobuf/src/converters/test_instances.rs +++ b/crates/apollo_protobuf/src/converters/test_instances.rs @@ -3,14 +3,16 @@ use std::fmt::Display; use apollo_test_utils::{auto_impl_get_test_instance, get_number_of_variants, GetTestInstance}; use prost::DecodeError; use rand::Rng; -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; +use starknet_api::block::{BlockNumber, GasPrice}; use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::core::ContractAddress; use starknet_api::data_availability::L1DataAvailabilityMode; +use starknet_api::hash::StarkHash; use super::ProtobufConversionError; use crate::consensus::{ ConsensusBlockInfo, + ProposalCommitment, ProposalFin, ProposalInit, ProposalPart, @@ -26,7 +28,7 @@ auto_impl_get_test_instance! { pub vote_type: VoteType, pub height: u64, pub round: u32, - pub block_hash: Option, + pub proposal_commitment: Option, pub voter: ContractAddress, } pub enum VoteType { @@ -39,8 +41,9 @@ auto_impl_get_test_instance! { pub valid_round: Option, pub proposer: ContractAddress, } + pub struct ProposalCommitment(pub StarkHash); pub struct ProposalFin { - pub proposal_commitment: BlockHash, + pub proposal_commitment: ProposalCommitment, } pub struct TransactionBatch { pub transactions: Vec, From 9729593a1b3fceedda127dd56ab815b240553405 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Mon, 20 Oct 2025 10:30:44 +0300 Subject: [PATCH 079/313] papyrus_node: Papyrus cleanup - deployment (#9623) --- .github/workflows/papyrus_docker-publish.yml | 95 - deployments/images/papyrus/Dockerfile | 34 - deployments/papyrus/helm/CI/values.yaml | 24 - deployments/papyrus/helm/Chart.yaml | 18 - .../papyrus/helm/Monitoring/.gitignore | 4 - deployments/papyrus/helm/README.md | 9 - deployments/papyrus/helm/backup-values.yaml | 21 - deployments/papyrus/helm/config/example.json | 8 - deployments/papyrus/helm/files/backup.sh | 40 - .../papyrus/helm/reference/template.yaml | 164 - .../papyrus/helm/templates/_helpers.tpl | 62 - .../helm/templates/aws-creds-secret.yaml | 12 - .../papyrus/helm/templates/configmap-env.yaml | 19 - .../papyrus/helm/templates/configmap-run.yaml | 12 - .../papyrus/helm/templates/configmap.yaml | 19 - .../papyrus/helm/templates/deployment.yaml | 152 - .../helm/templates/grafana-alerts.yaml | 12 - .../helm/templates/grafana-dashboard.yaml | 12 - .../papyrus/helm/templates/ingress.yaml | 36 - deployments/papyrus/helm/templates/pdb.yaml | 15 - deployments/papyrus/helm/templates/pvc.yaml | 22 - .../papyrus/helm/templates/service-p2p.yaml | 28 - .../papyrus/helm/templates/service.yaml | 26 - .../papyrus/helm/templates/statefulset.yaml | 161 - deployments/papyrus/helm/values.yaml | 171 - deployments/papyrus/install_papyrus.py | 121 - .../monitoring/templates/grafana_alerts.json | 7768 -------------- .../templates/grafana_dashboard.json | 9286 ----------------- 28 files changed, 18351 deletions(-) delete mode 100644 .github/workflows/papyrus_docker-publish.yml delete mode 100644 deployments/images/papyrus/Dockerfile delete mode 100644 deployments/papyrus/helm/CI/values.yaml delete mode 100644 deployments/papyrus/helm/Chart.yaml delete mode 100644 deployments/papyrus/helm/Monitoring/.gitignore delete mode 100644 deployments/papyrus/helm/README.md delete mode 100644 deployments/papyrus/helm/backup-values.yaml delete mode 100644 deployments/papyrus/helm/config/example.json delete mode 100644 deployments/papyrus/helm/files/backup.sh delete mode 100644 deployments/papyrus/helm/reference/template.yaml delete mode 100644 deployments/papyrus/helm/templates/_helpers.tpl delete mode 100644 deployments/papyrus/helm/templates/aws-creds-secret.yaml delete mode 100644 deployments/papyrus/helm/templates/configmap-env.yaml delete mode 100644 deployments/papyrus/helm/templates/configmap-run.yaml delete mode 100644 deployments/papyrus/helm/templates/configmap.yaml delete mode 100644 deployments/papyrus/helm/templates/deployment.yaml delete mode 100644 deployments/papyrus/helm/templates/grafana-alerts.yaml delete mode 100644 deployments/papyrus/helm/templates/grafana-dashboard.yaml delete mode 100644 deployments/papyrus/helm/templates/ingress.yaml delete mode 100644 deployments/papyrus/helm/templates/pdb.yaml delete mode 100644 deployments/papyrus/helm/templates/pvc.yaml delete mode 100644 deployments/papyrus/helm/templates/service-p2p.yaml delete mode 100644 deployments/papyrus/helm/templates/service.yaml delete mode 100644 deployments/papyrus/helm/templates/statefulset.yaml delete mode 100644 deployments/papyrus/helm/values.yaml delete mode 100644 deployments/papyrus/install_papyrus.py delete mode 100644 deployments/papyrus/monitoring/templates/grafana_alerts.json delete mode 100644 deployments/papyrus/monitoring/templates/grafana_dashboard.json diff --git a/.github/workflows/papyrus_docker-publish.yml b/.github/workflows/papyrus_docker-publish.yml deleted file mode 100644 index 47513718b88..00000000000 --- a/.github/workflows/papyrus_docker-publish.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: Papyrus-Docker-Publish - -on: - workflow_dispatch: - push: - branches: - - main - - main-v[0-9].** - tags: - - v[0-9].** - - papyrus-v[0-9].** - paths: - - ".github/workflows/papyrus_docker-publish.yml" - - "crates/papyrus**/**" - - "scripts/dependencies.sh" - - "deployments/images/base/Dockerfile" - - "deployments/images/papyrus/Dockerfile" - - pull_request: - paths: - - ".github/workflows/papyrus_docker-publish.yml" - - "crates/papyrus**/**" - - "scripts/dependencies.sh" - - "deployments/images/base/Dockerfile" - - "deployments/images/papyrus/Dockerfile" - -# On PR events, cancel existing CI runs on this same PR for this workflow. -# Also, create different concurrency groups for different pushed commits, on push events. -concurrency: - group: > - ${{ github.workflow }}- - ${{ github.ref }}- - ${{ github.event_name == 'pull_request' && 'PR' || github.sha }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -env: - REGISTRY: ghcr.io - REPO_NAME: ${{ github.repository }} - RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" - -jobs: - docker-build-push: - runs-on: namespace-profile-large-ubuntu-24-04-amd64 - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Not required but recommended - enables build multi-platform images, export cache, etc - # Also workaround for: https://github.com/docker/build-push-action/issues/461 - # https://github.com/docker/setup-buildx-action - - name: Setup Docker buildx - uses: docker/setup-buildx-action@v2.2.1 - - # Login to a Docker registry except on PR - # https://github.com/docker/login-action - - name: Login to registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@v2.1.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - logout: true - - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v4.1.1 - with: - images: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/papyrus - tags: | - type=semver,pattern={{raw}} - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=ref,event=pr - # set `main*` tag for the default / release branches. - type=raw,value={{branch}},enable=${{ github.event_name == 'push' && contains(github.ref, 'main') }} - # set `{branch}-{tag}` tag for tag push events. - type=raw,value={{tag}},enable=${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }} - # For manual triggers of the workflow: - type=raw,value={{branch}}{{tag}}-{{sha}},enable=${{ github.event_name == 'workflow_dispatch' }} - - # Build and push Docker image with Buildx - # https://github.com/docker/build-push-action - - name: Build and push Docker image - uses: docker/build-push-action@v6.13.0 - with: - context: . - file: deployments/images/papyrus/Dockerfile - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - no-cache: true diff --git a/deployments/images/papyrus/Dockerfile b/deployments/images/papyrus/Dockerfile deleted file mode 100644 index 6fc0e21636a..00000000000 --- a/deployments/images/papyrus/Dockerfile +++ /dev/null @@ -1,34 +0,0 @@ -# syntax = devthefuture/dockerfile-x - -INCLUDE deployments/images/base/Dockerfile - - -# Compile the papyrus_node crate in release mode, ensuring dependencies are locked. -FROM base AS builder -COPY . . -RUN rustup toolchain install -RUN cargo build --release --package papyrus_node - -FROM ubuntu:24.04 as final_stage - -ENV ID=1001 -WORKDIR /app -COPY --from=builder /target/release/papyrus_node /app/target/release/papyrus_node -COPY --from=builder /usr/bin/tini /usr/bin/tini - -COPY config/papyrus config/papyrus - -# Create a new user "papyrus". -RUN set -ex; \ - groupadd --gid ${ID} papyrus; \ - useradd --gid ${ID} --uid ${ID} --comment "" --create-home --home-dir /app papyrus; \ - chown -R papyrus:papyrus /app - -# Expose RPC and monitoring ports. -EXPOSE 8080 8081 - -# Switch to the new user. -USER ${ID} - -# Set the entrypoint to use tini to manage the process. -ENTRYPOINT ["tini", "--", "/app/target/release/papyrus_node"] diff --git a/deployments/papyrus/helm/CI/values.yaml b/deployments/papyrus/helm/CI/values.yaml deleted file mode 100644 index d60202e9501..00000000000 --- a/deployments/papyrus/helm/CI/values.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Default values for a papyrus ci deployment. - -rustLogLevel: "debug" - -deployment: - image: - tag: dev - -pvc: - size: 1Gi - storageClass: standard-rwo -# Configure Ingress. -# ingress: -# enabled: true -# type: gce -# name: ssl-proxy -# pathType: ImplementationSpecific -# annotations: | -# kubernetes.io/ingress.class: nginx -# kubernetes.io/tls-acme: "true" -# nginx.ingress.kubernetes.io/force-ssl-redirect: "true" - -grafanadashboard: - enabled: true diff --git a/deployments/papyrus/helm/Chart.yaml b/deployments/papyrus/helm/Chart.yaml deleted file mode 100644 index 73891673d6b..00000000000 --- a/deployments/papyrus/helm/Chart.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v2 -name: papyrus -description: A Helm chart for Kubernetes - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 diff --git a/deployments/papyrus/helm/Monitoring/.gitignore b/deployments/papyrus/helm/Monitoring/.gitignore deleted file mode 100644 index 5e7d2734cfc..00000000000 --- a/deployments/papyrus/helm/Monitoring/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/deployments/papyrus/helm/README.md b/deployments/papyrus/helm/README.md deleted file mode 100644 index aa73e518a1b..00000000000 --- a/deployments/papyrus/helm/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Papyrus helm chart installation - -## Usage - -```bash -helm upgrade --install `release_name` deployments/helm/ \ ---namespace `namespace_name` --create-namespace \ ---set ingress.host=`ingress_hostname` -``` diff --git a/deployments/papyrus/helm/backup-values.yaml b/deployments/papyrus/helm/backup-values.yaml deleted file mode 100644 index 6c94c11a46f..00000000000 --- a/deployments/papyrus/helm/backup-values.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Default values for a papyrus-backup deployment. - -# The verbosity level of logs ("debug", "info", "error", etc.) -rustLogLevel: "papyrus=DEBUG" - -# The Docker image (including any tag and repository name) -deployment: - image: - repository: us.gcr.io/starkware-dev/papyrus-backup - tag: 0.2.0 -services: [] -# Persistent volume claim variables for a papyrus pod. -pvc: - size: 1000Gi - storageClass: premium-rwo - -backup: - enabled: true - aws: - s3BucketName: papyrus-backup - s3BucketRegion: us-east-2 diff --git a/deployments/papyrus/helm/config/example.json b/deployments/papyrus/helm/config/example.json deleted file mode 100644 index 71460ee199d..00000000000 --- a/deployments/papyrus/helm/config/example.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "base_layer_url": "", - "network.port": 10000, - "storage.db_config.path_prefix": "./data", - "network.#is_none": false, - "storage.scope": "FullArchive", - "collect_metrics": true -} diff --git a/deployments/papyrus/helm/files/backup.sh b/deployments/papyrus/helm/files/backup.sh deleted file mode 100644 index 4a016b98111..00000000000 --- a/deployments/papyrus/helm/files/backup.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env sh -set -x -if [ -z "${ADDITIONAL_HEADER}" ]; then - ADDITIONAL_ARGS="" -else - ADDITIONAL_ARGS="--http_headers=${ADDITIONAL_HEADER}" -fi - -if [ -n "${CONCURRENT_REQUESTS}" ]; then - # temporary workaround for an internal papyrus memory issue - sed -i "s/concurrent_requests: 10/concurrent_requests: $CONCURRENT_REQUESTS/g" /app/config/config.yaml -fi - -RUN_CMD="/app/target/release/papyrus_node --config_file=/app/config/presets/${PRESET} ${ADDITIONAL_ARGS}" - -while true; do - # start papyrus and save the pid - sh -c "$RUN_CMD" & - PAPYRUS_PID="$!" - - sleep "$SLEEP_INTERVAL" - - # stop papyrus - kill -15 "$PAPYRUS_PID" - sleep 5s - - TS=$(date +%s) - if [ "$COMPRESS_BACKUP" = true ]; then - # compress file, upload compressed file and delete the compressed file - cd "/app/data/$CHAIN_ID" || exit 1 - TAR_FILE_NAME="$TS.tar.gz" - tar -czvf "$TAR_FILE_NAME" mdbx.dat - aws s3 cp "$TAR_FILE_NAME" "s3://$S3_BUCKET_NAME/$CHAIN_ID/$PAPYRUS_VERSION/$TAR_FILE_NAME" - rm "$TAR_FILE_NAME" - cd /app || exit 1 - else - # upload db file to s3 - aws s3 cp "/app/data/$CHAIN_ID/mdbx.dat" "s3://$S3_BUCKET_NAME/$CHAIN_ID/$PAPYRUS_VERSION/$TS.dat" - fi -done diff --git a/deployments/papyrus/helm/reference/template.yaml b/deployments/papyrus/helm/reference/template.yaml deleted file mode 100644 index 8390b2f2946..00000000000 --- a/deployments/papyrus/helm/reference/template.yaml +++ /dev/null @@ -1,164 +0,0 @@ ---- -# Source: papyrus/templates/configmap-env.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: papyrus-env - labels: - helm.sh/chart: papyrus-0.1.0 - app: papyrus - app.kubernetes.io/name: papyrus - app.kubernetes.io/managed-by: Helm -data: - RUST_LOG: info - PRESET: mainnet.json - CONCURRENT_REQUESTS: "50" ---- -# Source: papyrus/templates/configmap.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: papyrus-config - labels: - helm.sh/chart: papyrus-0.1.0 - app: papyrus - app.kubernetes.io/name: papyrus - app.kubernetes.io/managed-by: Helm -data: - config.json: |- - {} ---- -# Source: papyrus/templates/pvc.yaml -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: papyrus-data - labels: - helm.sh/chart: papyrus-0.1.0 - app: papyrus - app.kubernetes.io/name: papyrus - app.kubernetes.io/managed-by: Helm -spec: - storageClassName: - accessModes: - - ReadWriteOnce - volumeMode: Filesystem - resources: - requests: - storage: "512Gi" ---- -# Source: papyrus/templates/service-p2p.yaml -apiVersion: v1 -kind: Service -metadata: - name: papyrus-p2p - labels: - helm.sh/chart: papyrus-0.1.0 - app: papyrus - app.kubernetes.io/name: papyrus - app.kubernetes.io/managed-by: Helm -spec: - selector: - app.kubernetes.io/name: papyrus - type: ClusterIP - ports: - - name: p2p - port: 10000 - protocol: TCP - targetPort: p2p ---- -# Source: papyrus/templates/service.yaml -apiVersion: v1 -kind: Service -metadata: - name: papyrus - labels: - helm.sh/chart: papyrus-0.1.0 - app: papyrus - app.kubernetes.io/name: papyrus - app.kubernetes.io/managed-by: Helm -spec: - selector: - app.kubernetes.io/name: papyrus - type: ClusterIP - ports: - - name: rpc - port: 8080 - protocol: TCP - targetPort: rpc - - name: monitoring - port: 8081 - protocol: TCP - targetPort: monitoring ---- -# Source: papyrus/templates/deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: papyrus - namespace: idan-papyrus-p2p-dnsaddr-test - labels: - helm.sh/chart: papyrus-0.1.0 - app: papyrus - app.kubernetes.io/name: papyrus - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: papyrus - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - maxSurge: 1 - template: - metadata: - annotations: - prometheus.io/scrape: "true" - prometheus.io/path: "/monitoring/metrics" - prometheus.io/port: "8081" - labels: - app: papyrus - app.kubernetes.io/name: papyrus - spec: - securityContext: - fsGroup: 1000 - volumes: - - name: data - persistentVolumeClaim: - claimName: papyrus-data - - name: config-volume - configMap: - name: papyrus-config - containers: - - name: papyrus - image: "ghcr.io/starkware-libs/sequencer/papyrus:0.4.0" - imagePullPolicy: Always - resources: - limits: - cpu: "1" - memory: 1Gi - requests: - cpu: "500m" - memory: 1Gi - args: - - --config_file - - /app/config/papyrus/presets/mainnet.json,/app/config/papyrus/custom/config.json - - ports: - - containerPort: 8080 - name: rpc - - containerPort: 8081 - name: monitoring - - containerPort: 10000 - name: p2p - volumeMounts: - - name: data - mountPath: /app/data - - name: config-volume - mountPath: /app/config/papyrus/custom/config.json - subPath: config.json - envFrom: - - configMapRef: - name: papyrus-config diff --git a/deployments/papyrus/helm/templates/_helpers.tpl b/deployments/papyrus/helm/templates/_helpers.tpl deleted file mode 100644 index 9b6c5636481..00000000000 --- a/deployments/papyrus/helm/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "papyrus.name" -}} -{{- default .Release.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "papyrus.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "papyrus.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "papyrus.labels" -}} -helm.sh/chart: {{ include "papyrus.chart" . }} -app: {{ include "papyrus.name" . }} -{{ include "papyrus.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "papyrus.selectorLabels" -}} -app.kubernetes.io/name: {{ include "papyrus.name" . }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "papyrus.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "papyrus.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/deployments/papyrus/helm/templates/aws-creds-secret.yaml b/deployments/papyrus/helm/templates/aws-creds-secret.yaml deleted file mode 100644 index 328f3e0354f..00000000000 --- a/deployments/papyrus/helm/templates/aws-creds-secret.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.backup.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ template "papyrus.name" . }}-aws-creds - labels: - {{- include "papyrus.labels" . | nindent 4 }} -data: - AWS_ACCESS_KEY_ID: {{ .Values.backup.aws.accessKeyId | b64enc }} - AWS_SECRET_ACCESS_KEY: {{ .Values.backup.aws.secretAccessKey | b64enc }} - AWS_DEFAULT_REGION: {{ .Values.backup.aws.s3BucketRegion | b64enc }} -{{- end }} diff --git a/deployments/papyrus/helm/templates/configmap-env.yaml b/deployments/papyrus/helm/templates/configmap-env.yaml deleted file mode 100644 index 5e5da60528a..00000000000 --- a/deployments/papyrus/helm/templates/configmap-env.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "papyrus.name" . }}-env - labels: - {{- include "papyrus.labels" . | nindent 4 }} -data: - RUST_LOG: {{ .Values.rustLogLevel }} - PRESET: {{ .Values.starknet.preset }} - CONCURRENT_REQUESTS: {{ .Values.node.concurrentFgRequests | quote }} - {{- if .Values.starknet.additionalHeaders }} - ADDITIONAL_HEADER: {{ .Values.starknet.additionalHeaders }} - {{- end }} - {{- if .Values.backup.enabled }} - SLEEP_INTERVAL: {{ .Values.backup.sleepInterval }} - S3_BUCKET_NAME: {{ .Values.backup.aws.s3BucketName }} - PAPYRUS_VERSION: {{ .Values.image.tag | quote }} - COMPRESS_BACKUP: {{ .Values.backup.compress | quote }} - {{- end }} diff --git a/deployments/papyrus/helm/templates/configmap-run.yaml b/deployments/papyrus/helm/templates/configmap-run.yaml deleted file mode 100644 index ffbe00b7f67..00000000000 --- a/deployments/papyrus/helm/templates/configmap-run.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.backup.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "papyrus.name" . }}-run - labels: - {{- include "papyrus.labels" . | nindent 4 }} -data: - backup.sh: | - {{- tpl (.Files.Get "files/backup.sh") . | nindent 4 }} -{{- end }} - diff --git a/deployments/papyrus/helm/templates/configmap.yaml b/deployments/papyrus/helm/templates/configmap.yaml deleted file mode 100644 index bff1f5b8c38..00000000000 --- a/deployments/papyrus/helm/templates/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ - -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "papyrus.name" . }}-config - labels: - {{- include "papyrus.labels" . | nindent 4 }} -data: - config.json: |- - {{- if .Values.deployment.configFile }} - {{- $filePath := printf "config/%s" .Values.deployment.configFile -}} - {{- if not (.Files.Get $filePath) -}} - {{- fail (printf "Error: The file %s does not exist in the chart." $filePath) -}} - {{- else }} - {{ .Files.Get $filePath | nindent 4 }} - {{- end }} - {{- else }} - {} - {{- end }} diff --git a/deployments/papyrus/helm/templates/deployment.yaml b/deployments/papyrus/helm/templates/deployment.yaml deleted file mode 100644 index 24ff73688fa..00000000000 --- a/deployments/papyrus/helm/templates/deployment.yaml +++ /dev/null @@ -1,152 +0,0 @@ -{{- if eq .Values.deployment.type "deployment" }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ template "papyrus.name" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "papyrus.labels" . | nindent 4 }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "papyrus.selectorLabels" . | nindent 6 }} - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - maxSurge: 1 - template: - metadata: - annotations: - {{- if .Values.deployment.annotations }} - {{ toYaml .Values.deployment.annotations | nindent 8 }} - {{- end}} - {{- if .Values.service.ports.monitoring.enabled }} - prometheus.io/scrape: "true" - prometheus.io/path: "/monitoring/metrics" - prometheus.io/port: {{ .Values.service.ports.monitoring.port | quote }} - {{- end }} - labels: - app: papyrus - {{- include "papyrus.selectorLabels" . | nindent 8 }} - spec: - securityContext: - fsGroup: 1000 - volumes: - - name: data - persistentVolumeClaim: - claimName: {{ template "papyrus.name" . }}-data - - name: config-volume - configMap: - name: {{ template "papyrus.name" . }}-config - {{- if .Values.backup.enabled }} - - name: run - configMap: - name: {{ template "papyrus.name" . }}-run - defaultMode: 0777 - {{- end }} - {{- with .Values.deployment.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.deployment.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - containers: - - name: {{ template "papyrus.name" . }} - image: "{{ .Values.deployment.image.repository }}:{{ .Values.deployment.image.tag }}" - imagePullPolicy: {{ .Values.deployment.pullPolicy }} - resources: - limits: - cpu: {{ .Values.deployment.resources.limits.cpu | quote }} - memory: {{ .Values.deployment.resources.limits.memory }} - requests: - cpu: {{ .Values.deployment.resources.requests.cpu | quote}} - memory: {{ .Values.deployment.resources.requests.memory }} - {{- if not .Values.backup.enabled }} - {{- with .Values.deployment.env }} - env: - {{- toYaml . | nindent 10 }} - {{- end }} - args: - - --config_file - - /app/config/papyrus/presets/{{ .Values.starknet.preset }},/app/config/papyrus/custom/config.json - {{ range $key, $value := .Values.deployment.extraArgs }} - {{- if $value }} - - --{{ $key }} - - {{ $value | quote }} - {{- else }} - - --{{ $key }} - {{- end }} - {{ end }} - ports: - {{- if .Values.service.ports.rpc.enabled }} - - containerPort: {{ .Values.service.ports.rpc.port }} - name: rpc - {{- end }} - {{- if .Values.service.ports.monitoring.enabled }} - - containerPort: {{ .Values.service.ports.monitoring.port }} - name: monitoring - {{- end }} - {{- if .Values.p2pService.enabled }} - - containerPort: {{ .Values.p2pService.port }} - name: p2p - {{- end }} - volumeMounts: - - name: data - mountPath: /app/data - - name: config-volume - mountPath: /app/config/papyrus/custom/config.json - subPath: config.json - envFrom: - - configMapRef: - name: {{ template "papyrus.name" . }}-config - {{- else }} - command: - - sh - - -c - - /app/run/backup.sh - volumeMounts: - - name: data - mountPath: /app/data - - name: config-volume - mountPath: /app/config/papyrus/custom/config.json - subPath: config.json - - name: run - mountPath: /app/run - envFrom: - - configMapRef: - name: {{ template "papyrus.name" . }}-env - - secretRef: - name: {{ template "papyrus.name" . }}-aws-creds - {{- end }} -{{- if or .Values.deployment.affinity .Values.deployment.podAntiAffinity }} - affinity: - {{- end }} - {{- with .Values.deployment.affinity }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- if eq .Values.deployment.podAntiAffinity "hard" }} - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - topologyKey: {{ .Values.deployment.podAntiAffinityTopologyKey }} - labelSelector: - matchExpressions: - - {key: app.kubernetes.io/name, operator: In, values: [{{ template "papyrus.name" . }}]} - {{- else if eq .Values.deployment.podAntiAffinity "soft" }} - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - topologyKey: {{ .Values.deployment.podAntiAffinityTopologyKey }} - labelSelector: - matchExpressions: - - {key: app.kubernetes.io/name, operator: In, values: [{{ template "papyrus.name" . }}]} - {{- end }} - {{- with .Values.deployment.topologySpreadConstraints }} - topologySpreadConstraints: - {{- toYaml . | nindent 8 }} - {{- end }} -{{- end }} diff --git a/deployments/papyrus/helm/templates/grafana-alerts.yaml b/deployments/papyrus/helm/templates/grafana-alerts.yaml deleted file mode 100644 index e9234a53516..00000000000 --- a/deployments/papyrus/helm/templates/grafana-alerts.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.grafanaAlerts.enabled }} -apiVersion: integreatly.org/v1alpha1 -kind: GrafanaDashboard -metadata: - name: {{ template "papyrus.name" . }}-alerts - namespace: {{ .Release.Namespace | quote }} - labels: - app: grafana-dashboard -spec: - json: | - {{- (.Files.Get "Monitoring/grafana_alerts.json") | nindent 4 }} -{{- end }} diff --git a/deployments/papyrus/helm/templates/grafana-dashboard.yaml b/deployments/papyrus/helm/templates/grafana-dashboard.yaml deleted file mode 100644 index 0b3c6d70df2..00000000000 --- a/deployments/papyrus/helm/templates/grafana-dashboard.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.grafanaDashboard.enabled }} -apiVersion: integreatly.org/v1alpha1 -kind: GrafanaDashboard -metadata: - name: {{ template "papyrus.name" . }}-dashboard - namespace: {{ .Release.Namespace | quote }} - labels: - app: grafana-dashboard -spec: - json: | - {{- (.Files.Get "Monitoring/grafana_dashboard.json") | nindent 4 }} -{{- end }} diff --git a/deployments/papyrus/helm/templates/ingress.yaml b/deployments/papyrus/helm/templates/ingress.yaml deleted file mode 100644 index d0bf9935cc1..00000000000 --- a/deployments/papyrus/helm/templates/ingress.yaml +++ /dev/null @@ -1,36 +0,0 @@ -{{- if .Values.ingress.enabled }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: "{{ .Values.ingress.name }}-{{ template "papyrus.name" . }}" - namespace: {{ .Release.Namespace }} - labels: - {{- include "papyrus.labels" . | nindent 4 }} -{{- with .Values.ingress.annotations }} - annotations: - {{ toYaml . | nindent 4 }} -{{- end }} -spec: - rules: - - host: {{ .Values.ingress.host }} - http: - paths: - - backend: - service: - name: {{ template "papyrus.name" . }}-rpc - port: - number: {{ .Values.services.rpc.port }} - path: /rpc - pathType: {{ .Values.ingress.pathType }} - - backend: - service: - name: {{ template "papyrus.name" . }}-monitoring - port: - number: {{ .Values.services.monitoring.port }} - path: /monitoring - pathType: {{ .Values.ingress.pathType }} - tls: - - hosts: - - {{ .Values.ingress.host }} - secretName: {{ .Values.ingress.host }}-ssl-secret -{{- end }} diff --git a/deployments/papyrus/helm/templates/pdb.yaml b/deployments/papyrus/helm/templates/pdb.yaml deleted file mode 100644 index 517b5939bd1..00000000000 --- a/deployments/papyrus/helm/templates/pdb.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- if .Values.deployment.podDisruptionBudget.enabled }} -{{- $pdbSpec := omit .Values.deployment.podDisruptionBudget "enabled" }} -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: {{ template "papyrus.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "papyrus.labels" . | nindent 4 }} -spec: - selector: - matchLabels: - {{- include "papyrus.matchLabels" . | nindent 6 }} - {{- toYaml $pdbSpec | nindent 2 }} -{{- end }} diff --git a/deployments/papyrus/helm/templates/pvc.yaml b/deployments/papyrus/helm/templates/pvc.yaml deleted file mode 100644 index c8223b4f7de..00000000000 --- a/deployments/papyrus/helm/templates/pvc.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- if eq .Values.deployment.type "deployment" }} -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ template "papyrus.name" . }}-data - labels: - {{- include "papyrus.labels" . | nindent 4 }} -spec: - storageClassName: {{ .Values.pvc.storageClass }} - accessModes: - - ReadWriteOnce - volumeMode: Filesystem - resources: - requests: - storage: {{ .Values.pvc.size | quote }} - {{- if .Values.pvc.restoreFromSnapshot.enabled }} - dataSource: - name: {{ .Values.pvc.restoreFromSnapshot.snapshotName }} - kind: VolumeSnapshot - apiGroup: snapshot.storage.k8s.io - {{- end }} -{{- end }} diff --git a/deployments/papyrus/helm/templates/service-p2p.yaml b/deployments/papyrus/helm/templates/service-p2p.yaml deleted file mode 100644 index 15c7e692715..00000000000 --- a/deployments/papyrus/helm/templates/service-p2p.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- if and ( not .Values.backup.enabled ) .Values.p2pService.enabled }} ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ template "papyrus.name" . }}-p2p - labels: - {{- include "papyrus.labels" . | nindent 4 }} - annotations: - {{- if .Values.p2pService.annotations }} - {{ toYaml .Values.p2pService.annotations | nindent 4 }} - {{- end}} -spec: - selector: - {{- include "papyrus.selectorLabels" . | nindent 6 }} - type: {{ .Values.p2pService.type }} - {{- if and (eq .Values.p2pService.type "ClusterIP") .Values.p2pService.clusterIP }} - clusterIP: {{ .Values.p2pService.clusterIP }} - {{- end }} - {{- if and (eq .Values.p2pService.type "LoadBalancer") .Values.p2pService.loadBalancerIP }} - loadBalancerIP: {{ .Values.p2pService.loadBalancerIP }} - {{- end }} - ports: - - name: p2p - port: {{ .Values.p2pService.port }} - protocol: {{ .Values.p2pService.protocol }} - targetPort: p2p -{{- end }} diff --git a/deployments/papyrus/helm/templates/service.yaml b/deployments/papyrus/helm/templates/service.yaml deleted file mode 100644 index 1b073cf3f0f..00000000000 --- a/deployments/papyrus/helm/templates/service.yaml +++ /dev/null @@ -1,26 +0,0 @@ -{{- if not .Values.backup.enabled }} ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ template "papyrus.name" . }} - labels: - {{- include "papyrus.labels" . | nindent 4 }} -spec: - selector: - {{- include "papyrus.selectorLabels" . | nindent 6 }} - type: {{ .Values.service.type }} - ports: - {{- if and .Values.service.ports.rpc .Values.service.ports.rpc.enabled }} - - name: rpc - port: {{ .Values.service.ports.rpc.port }} - protocol: {{ .Values.service.ports.rpc.protocol }} - targetPort: rpc - {{- end }} - {{- if and .Values.service.ports.monitoring .Values.service.ports.monitoring.enabled }} - - name: monitoring - port: {{ .Values.service.ports.monitoring.port }} - protocol: {{ .Values.service.ports.monitoring.protocol }} - targetPort: monitoring - {{- end }} -{{- end }} \ No newline at end of file diff --git a/deployments/papyrus/helm/templates/statefulset.yaml b/deployments/papyrus/helm/templates/statefulset.yaml deleted file mode 100644 index e5ed6e5bcb0..00000000000 --- a/deployments/papyrus/helm/templates/statefulset.yaml +++ /dev/null @@ -1,161 +0,0 @@ -{{- if eq .Values.deployment.type "statefulset" }} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ template "papyrus.name" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "papyrus.labels" . | nindent 4 }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "papyrus.selectorLabels" . | nindent 6 }} - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - annotations: - {{- if .Values.deployment.annotations }} - {{ toYaml .Values.deployment.annotations | nindent 8 }} - {{- end}} - {{- if .Values.service.ports.monitoring.enabled }} - prometheus.io/scrape: "true" - prometheus.io/path: "/monitoring/metrics" - prometheus.io/port: {{ .Values.service.ports.monitoring.port | quote }} - {{- end }} - labels: - app: papyrus - {{- include "papyrus.selectorLabels" . | nindent 8 }} - spec: - securityContext: - fsGroup: 1000 - volumes: - - name: config-volume - configMap: - name: {{ template "papyrus.name" . }}-config - {{- if .Values.backup.enabled }} - - name: run - configMap: - name: {{ template "papyrus.name" . }}-run - defaultMode: 0777 - {{- end }} - {{- with .Values.deployment.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.deployment.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - containers: - - name: {{ template "papyrus.name" . }} - image: "{{ .Values.deployment.image.repository }}:{{ .Values.deployment.image.tag }}" - imagePullPolicy: {{ .Values.deployment.pullPolicy }} - resources: - limits: - cpu: {{ .Values.deployment.resources.limits.cpu | quote }} - memory: {{ .Values.deployment.resources.limits.memory }} - requests: - cpu: {{ .Values.deployment.resources.requests.cpu | quote}} - memory: {{ .Values.deployment.resources.requests.memory }} - {{- if not .Values.backup.enabled }} - {{- with .Values.deployment.env }} - env: - {{- toYaml . | nindent 10 }} - {{- end }} - args: - - --config_file - - /app/config/papyrus/presets/{{ .Values.starknet.preset }},/app/config/papyrus/custom/config.json - {{ range $key, $value := .Values.deployment.extraArgs }} - {{- if $value }} - - --{{ $key }} - - {{ $value | quote }} - {{- else }} - - --{{ $key }} - {{- end }} - {{ end }} - ports: - {{- if .Values.service.ports.rpc.enabled }} - - containerPort: {{ .Values.service.ports.rpc.port }} - name: rpc - {{- end }} - {{- if .Values.service.ports.monitoring.enabled }} - - containerPort: {{ .Values.service.ports.monitoring.port }} - name: monitoring - {{- end }} - {{- if .Values.p2pService.enabled }} - - containerPort: {{ .Values.p2pService.port }} - name: p2p - {{- end }} - volumeMounts: - - name: {{ template "papyrus.name" . }}-data - mountPath: /app/data - - name: config-volume - mountPath: /app/config/papyrus/custom/config.json - subPath: config.json - envFrom: - - configMapRef: - name: {{ template "papyrus.name" . }}-env - {{- else }} - command: - - sh - - -c - - /app/run/backup.sh - volumeMounts: - - name: {{ template "papyrus.name" . }}-data - mountPath: /app/data - - name: config-volume - mountPath: /app/config/papyrus/custom/config.json - subPath: config.json - - name: run - mountPath: /app/run - envFrom: - - configMapRef: - name: {{ template "papyrus.name" . }}-env - - secretRef: - name: {{ template "papyrus.name" . }}-aws-creds - {{- end }} - {{- if or .Values.deployment.affinity .Values.deployment.podAntiAffinity }} - affinity: - {{- end }} - {{- with .Values.deployment.affinity }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- if eq .Values.deployment.podAntiAffinity "hard" }} - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - topologyKey: {{ .Values.deployment.podAntiAffinityTopologyKey }} - labelSelector: - matchExpressions: - - {key: app.kubernetes.io/name, operator: In, values: [{{ template "papyrus.name" . }}]} - {{- else if eq .Values.deployment.podAntiAffinity "soft" }} - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - topologyKey: {{ .Values.deployment.podAntiAffinityTopologyKey }} - labelSelector: - matchExpressions: - - {key: app.kubernetes.io/name, operator: In, values: [{{ template "papyrus.name" . }}]} - {{- end }} - {{- with .Values.deployment.topologySpreadConstraints }} - topologySpreadConstraints: - {{- toYaml . | nindent 8 }} - {{- end }} - volumeClaimTemplates: - - metadata: - name: {{ template "papyrus.name" . }}-data - labels: - {{- include "papyrus.labels" . | nindent 8 }} - spec: - storageClassName: {{ .Values.pvc.storageClass }} - accessModes: - - "ReadWriteOnce" - volumeMode: Filesystem - resources: - requests: - storage: {{ .Values.pvc.size | quote }} -{{- end }} diff --git a/deployments/papyrus/helm/values.yaml b/deployments/papyrus/helm/values.yaml deleted file mode 100644 index 4fba11c68e7..00000000000 --- a/deployments/papyrus/helm/values.yaml +++ /dev/null @@ -1,171 +0,0 @@ -# Default values for a papyrus deployment. - -# The verbosity level of logs ("debug", "info", "error", etc.) -rustLogLevel: "info" - -node: - # Number of concurrent requests to the SN feeder gateway - concurrentFgRequests: 50 - -# Ethereum node URL. A value for this variable is mandatory. -base_layer_node_url: - -starknet: - # possible values: "mainnet.json, sepolia_testnet" and "sepolia_integration". - preset: mainnet.json - -deployment: - # Supported values: deployment, statefulset - type: deployment - - # The container image - image: - repository: ghcr.io/starkware-libs/sequencer/papyrus - tag: 0.4.0 - - # The name of the papyrus config file. For example: my-config.json - # The config file must be placed under "config" folder in the chart root folder. - # ./ - # templates/ - # ---> config/ - # Chart.yaml - # values.yaml - configFile: - - # The container's pullPolicy - pullPolicy: Always - - # Set pod annotations - annotations: {} - - # Set deployment nodeSelector - nodeSelector: {} - - # Set deployment tolerations - tolerations: [] - # - key: "key1" - # operator: "Equal" - # value: "value1" - # effect: "NoSchedule" - - affinity: {} - - ## Pod anti-affinity can prevent the scheduler from placing papyrus server replicas on the same node. - ## The value "soft" means that the scheduler should *prefer* to not schedule two replica pods onto the same node but no guarantee is provided. - ## The value "hard" means that the scheduler is *required* to not schedule two replica pods onto the same node. - ## The default value "" will disable pod anti-affinity so that no anti-affinity rules will be configured (unless set in `deployment.affinity`). - ## - podAntiAffinity: "" - - ## If anti-affinity is enabled sets the topologyKey to use for anti-affinity. - ## This can be changed to, for example, failure-domain.beta.kubernetes.io/zone - ## - podAntiAffinityTopologyKey: failure-domain.beta.kubernetes.io/zone - - ## Pod topology spread constraints - ## ref. https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/ - topologySpreadConstraints: [] - - ## PodDisruptionBudget settings - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ - ## - podDisruptionBudget: - enabled: false - maxUnavailable: 1 - # minAvailable: 1 - ## unhealthyPodEvictionPolicy is available since 1.27.0 (beta) - ## https://kubernetes.io/docs/tasks/run-application/configure-pdb/#unhealthy-pod-eviction-policy - # unhealthyPodEvictionPolicy: IfHealthyBudget - - # The default resources for a pod. - resources: - limits: - cpu: "1" - memory: 1Gi - requests: - cpu: 500m - memory: 1Gi - - ## Optionally specify extra environment variables to add to papyrus container - env: [] - # - name: FOO - # value: BAR - - extraArgs: {} # Optional additional deployment args - # foo: "bar" - -# Service variables for a papyrus pod. -service: - # Specify service type, supported options are ClusterIP, LoadBalancer - type: ClusterIP - ports: - rpc: - enabled: true - port: 8080 - protocol: TCP - monitoring: - enabled: true - port: 8081 - protocol: TCP - -p2pService: - enabled: true - # supported options are ClusterIP, LoadBalancer - type: ClusterIP - port: 10000 - protocol: TCP - # If service type is ClusterIP, - # Set static ip for the kubernetes service. Note that the ip address is not reserved and there might be a chance for ip collision. - # See https://kubernetes.io/docs/concepts/services-networking/cluster-ip-allocation/ to understand how to avoid such case. - clusterIP: - # If service type is LoadBalancer, - # Set static ip for the loadbalancer. Note that a static IP needs to be reserved first in a cloud environment in order to use it. - loadBalancerIP: - annotations: {} - -# Persistent volume claim variables for a papyrus pod. -pvc: - # Recommended size is at least 512Gi. - size: 512Gi - # Is is recommended to use an SSD volume (such as GKE premium-rwo). - storageClass: "" - # Use an existing snapshot for the node's data. The kubernetes volumesnapshot object should - # exist in the same namespace as the rest of the resources. - restoreFromSnapshot: - enabled: false - snapshotName: my-snapshot - -# Configure Ingress. -ingress: - # Should an ingress object be created - enabled: false - # Ingress class type. - type: - # Ingress object name in Kubernetes. - name: - # Host name to create Ingress rules. - host: - # Ingress path type. - pathType: - # Annotations to apply to the node ingress. - annotations: {} - -# GrafanaDashboad CRD configuration -# This is relevant for Grafana Operator users https://grafana.github.io/grafana-operator/docs/ -grafanaDashboard: - # Should the GrafanaDashboard object be installed - enabled: false - -grafanaAlerts: - enabled: false - -# Backup mode -backup: - enabled: false - sleepInterval: 6h - compress: false - aws: - s3BucketName: my-backup-bucket-name - s3BucketRegion: my-backup-bucket-region - accessKeyId: my aws_access_key_id - secretAccessKey: my aws_secret_access_key diff --git a/deployments/papyrus/install_papyrus.py b/deployments/papyrus/install_papyrus.py deleted file mode 100644 index 13a8a1a7240..00000000000 --- a/deployments/papyrus/install_papyrus.py +++ /dev/null @@ -1,121 +0,0 @@ -import argparse -import subprocess -import sys - -GRAFANA_DASHBOARD_TEMPLATE_FILE_PATH = "monitoring/templates/grafana_dashboard.json" -GRAFANA_ALERTS_TEMPLATE_FILE_PATH = "monitoring/templates/grafana_alerts.json" -GRAFANA_DASHBOARD_DESTINATION_FILE_PATH = "helm/Monitoring/grafana_dashboard.json" -GRAFANA_ALERTS_DESTINATION_FILE_PATH = "helm/Monitoring/grafana_alerts.json" - - -# TODO(AlonDo): Add function to deploy monitoring dashboard. -def parse_command_line_args(): - parser = argparse.ArgumentParser(description="Install Papyrus node.") - parser.add_argument( - "--release_name", type=str, required=True, help="Name for the helm release." - ) - parser.add_argument( - "--namespace", type=str, required=True, help="Target namespace for the Papyrus node." - ) - parser.add_argument( - "--create_namespace", - action="store_true", - default=False, - help="Enabling this option will install a new namespace with the given name.", - ) - parser.add_argument( - "--values_file", action="store", default=None, help="Add additional values file." - ) - parser.add_argument( - "--with_alerts", - action="store_true", - default=False, - help="Enabling this option will also deploy a grafana alerts deashboard with the pod.", - ) - parser.add_argument( - "--prometheus_uid", - type=str, - required=False, - help="UID for prometheus (to use with Grafana).", - ) - parser.add_argument( - "--old_version", - type=str, - required=False, - help="Represents previous RPC version for the desired env (e.g. v0_3).", - ) - parser.add_argument( - "--new_version", - type=str, - required=False, - help="Represents current RPC version for the desired env (e.g. v0_4).", - ) - parser.add_argument( - "--dry_run", - action="store_true", - default=False, - help="Enabling this option will dry run the helm upgrade.", - ) - parser.add_argument( - "--helm_deployment_dir", - type=str, - required=False, - default="./deployments/helm/", - help="Relative path to the helm deployment directory (default is ./deployments/helm/.", - ) - - return parser.parse_args() - - -def generate_grafana_tokens( - grafana_namespace: str, prometheus_uid: str, template_path: str, destination_path: str -): - grafana_template_lines = open(template_path).readlines() - grafana_dashboard_lines = list() - for line in grafana_template_lines: - grafana_dashboard_lines.append( - line.replace("NAMESPACE", grafana_namespace).replace("${DS_PROMETHEUS}", prometheus_uid) - ) - grafana_dashboard = "".join(line for line in grafana_dashboard_lines) - grafana_deployment_file = open(destination_path, "a") - # Delete previous file contents. - grafana_deployment_file.truncate(0) - grafana_deployment_file.write(grafana_dashboard) - grafana_deployment_file.flush() - - -def main(): - args = parse_command_line_args() - print(args) - # The CMD assumes this script is being run from the root directory. - cmd = f"helm upgrade --install {args.release_name} {args.helm_deployment_dir} --namespace {args.namespace}" - if args.create_namespace: - cmd += " --create-namespace" - if args.values_file: - cmd += f" -f {args.values_file}" - if args.with_alerts: - assert ( - args.prometheus_uid is not None - ), "Must provide Prometheus UID when deploying with Grafana." - generate_grafana_tokens( - grafana_namespace=args.namespace, - prometheus_uid=args.prometheus_uid, - template_path=GRAFANA_DASHBOARD_TEMPLATE_FILE_PATH, - destination_path=GRAFANA_DASHBOARD_DESTINATION_FILE_PATH, - ) - generate_grafana_tokens( - grafana_namespace=args.namespace, - prometheus_uid=args.prometheus_uid, - template_path=GRAFANA_ALERTS_TEMPLATE_FILE_PATH, - destination_path=GRAFANA_ALERTS_DESTINATION_FILE_PATH, - ) - - if args.dry_run: - cmd += " --dry-run" - - print(f"running {cmd}...") - subprocess.Popen(cmd, shell=True) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/deployments/papyrus/monitoring/templates/grafana_alerts.json b/deployments/papyrus/monitoring/templates/grafana_alerts.json deleted file mode 100644 index 5c45b36d7b6..00000000000 --- a/deployments/papyrus/monitoring/templates/grafana_alerts.json +++ /dev/null @@ -1,7768 +0,0 @@ -{ - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__elements": [], - "__requires": [ - { - "type": "panel", - "id": "alertlist", - "name": "Alert list", - "version": "" - }, - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "8.5.5" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph (old)", - "version": "" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "timeseries", - "name": "Time series", - "version": "" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": null, - "links": [], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 64, - "panels": [], - "title": "Main Alerts", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "gridPos": { - "h": 27, - "w": 6, - "x": 0, - "y": 1 - }, - "id": 4, - "options": { - "alertName": "(Papyrus)", - "dashboardAlerts": false, - "dashboardTitle": "", - "maxItems": 90, - "showOptions": "current", - "sortOrder": 3, - "stateFilter": { - "alerting": false, - "execution_error": false, - "no_data": false, - "ok": false, - "paused": false, - "pending": false - }, - "tags": [] - }, - "pluginVersion": "8.5.5", - "title": "Alerts Panel", - "type": "alertlist" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 2 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "10m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "min" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "10m", - "frequency": "1m", - "handler": 1, - "name": "Unsynced headers alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 6, - "x": 6, - "y": 1 - }, - "hiddenSeries": false, - "id": 67, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.5.5", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"NAMESPACE\"} - papyrus_header_marker{kubernetes_namespace=\"NAMESPACE\"}", - "legendFormat": "{{pod}}", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 2, - "visible": true - } - ], - "timeRegions": [], - "title": "Unsynced headers", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 2 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "10m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "min" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "10m", - "frequency": "1m", - "handler": 1, - "name": "Unsynced bodies alert", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 6, - "x": 12, - "y": 1 - }, - "hiddenSeries": false, - "id": 68, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.5.5", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"NAMESPACE\"} - papyrus_body_marker{kubernetes_namespace=\"NAMESPACE\"}", - "legendFormat": "{{pod}}", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 2, - "visible": true - } - ], - "timeRegions": [], - "title": "Unsynced bodies", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 2 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "10m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "min" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "10m", - "frequency": "1m", - "handler": 1, - "name": "Unsynced state diffs alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 6, - "x": 18, - "y": 1 - }, - "hiddenSeries": false, - "id": 69, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.5.5", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"NAMESPACE\"} - papyrus_state_marker{kubernetes_namespace=\"NAMESPACE\"}", - "legendFormat": "{{pod}}", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 2, - "visible": true - } - ], - "timeRegions": [], - "title": "Unsynced state diffs", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 2 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "10m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "min" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "10m", - "frequency": "1m", - "handler": 1, - "name": "Unsynced compiled classes alert", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 6, - "x": 6, - "y": 10 - }, - "hiddenSeries": false, - "id": 70, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.5.5", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"NAMESPACE\"} - papyrus_compiled_class_marker{kubernetes_namespace=\"NAMESPACE\"}", - "legendFormat": "{{pod}}", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 2, - "visible": true - } - ], - "timeRegions": [], - "title": "Unsynced compiled classes", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 100 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Execution Request Load Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Rate of requests for methods that change Starknet", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 9, - "w": 6, - "x": 12, - "y": 10 - }, - "id": 10, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rate(sum(rpc_incoming_requests{kubernetes_namespace=\"NAMESPACE\", method=~\"addDeclareTransaction|addDeployAccountTransaction|addInvokeTransaction\"})[10m:])", - "legendFormat": "Incoming requests rate (in 10 mins)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 100, - "visible": true - } - ], - "title": "Requests Rate - Execute Functions", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 100 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Call Request Load Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Rate of requests for methods that query Starknet", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 9, - "w": 6, - "x": 18, - "y": 10 - }, - "id": 6, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rate(sum(rpc_incoming_requests{kubernetes_namespace=\"NAMESPACE\", method!~\"addDeclareTransaction|addDeployAccountTransaction|addInvokeTransaction\"})[10m:])", - "legendFormat": "Incoming requests rate (in 10 mins)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 100, - "visible": true - } - ], - "title": "Requests Rate - Call Functions", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 0.00001 - ], - "type": "lt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "No New Block Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 6, - "x": 6, - "y": 19 - }, - "hiddenSeries": false, - "id": 2, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.5.5", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "max(rate(papyrus_central_block_marker{kubernetes_namespace=\"NAMESPACE\"}[4m])*225)", - "legendFormat": "Number of Blocks", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "lt", - "value": 0.00001, - "visible": true - } - ], - "timeRegions": [], - "title": "Starknet Block Creation Rate", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 28 - }, - "id": 52, - "panels": [], - "title": "Latency Alert - Execute Functions", - "type": "row" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet addDeclareTransaction OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 29 - }, - "id": 55, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"addDeclareTransaction\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "addDeclareTransaction OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet addDeclareTransaction NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 29 - }, - "id": 54, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"addDeclareTransaction\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "addDeclareTransaction NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet addDeployAccountTransaction OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 29 - }, - "id": 57, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"addDeployAccountTransaction\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "addDeployAccountTransaction OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet addDeployAccountTransaction NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 29 - }, - "id": 56, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"addDeployAccountTransaction\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "addDeployAccountTransaction NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet addInvokeTransaction OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 36 - }, - "id": 53, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"addInvokeTransaction\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "addInvokeTransaction OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet addInvokeTransaction NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 36 - }, - "id": 58, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"addInvokeTransaction\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "addInvokeTransaction NEW_VERSION Latency", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 43 - }, - "id": 60, - "panels": [], - "title": "Latency Alert - Call Functions - Blocks", - "type": "row" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet blockHashAndNumber OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 44 - }, - "id": 13, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"blockHashAndNumber\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "blockHashAndNumber OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet blockHashAndNumber NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 44 - }, - "id": 14, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"blockHashAndNumber\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "blockHashAndNumber NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet blockNumber OLD_VERSION Latency Alert(Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 44 - }, - "id": 8, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"blockNumber\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "blockNumber OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet blockNumber NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 44 - }, - "id": 9, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"blockNumber\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "blockNumber NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getBlockTransactionCount OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 51 - }, - "id": 18, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getBlockTransactionCount\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getBlockTransactionCount OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getBlockTransactionCount NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 51 - }, - "id": 22, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getBlockTransactionCount\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getBlockTransactionCount NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getBlockWithTxHashes OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 51 - }, - "id": 25, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getBlockWithTxHashes\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getBlockWithTxHashes OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getBlockWithTxHashes NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 51 - }, - "id": 24, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getBlockWithTxHashes\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getBlockWithTxHashes NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getBlockWithTxs OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 58 - }, - "id": 28, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getBlockWithTxs\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getBlockWithTxs OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getBlockWithTxs NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 58 - }, - "id": 26, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getBlockWithTxs\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getBlockWithTxs NEW_VERSION Latency", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 65 - }, - "id": 62, - "panels": [], - "title": "Latency Alert - Call Functions - Transactions", - "type": "row" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getTransactionByBlockIdAndIndex OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-yellow", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 66 - }, - "id": 43, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getTransactionByBlockIdAndIndex\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getTransactionByBlockIdAndIndex OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getTransactionByBlockIdAndIndex NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-yellow", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 66 - }, - "id": 42, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getTransactionByBlockIdAndIndex\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getTransactionByBlockIdAndIndex NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getTransactionByHash OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-yellow", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 66 - }, - "id": 45, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getTransactionByHash\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getTransactionByHash OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getTransactionByHash NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-yellow", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 66 - }, - "id": 44, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getTransactionByHash\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getTransactionByHash NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getTransactionReceipt OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-yellow", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 73 - }, - "id": 47, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getTransactionReceipt\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getTransactionReceipt OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getTransactionReceipt NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-yellow", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 73 - }, - "id": 46, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getTransactionReceipt\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getTransactionReceipt NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet pendingTransactions OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 73 - }, - "id": 49, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"pendingTransactions\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "pendingTransactions OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet pendingTransactions NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 73 - }, - "id": 48, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"pendingTransactions\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "pendingTransactions NEW_VERSION Latency", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 80 - }, - "id": 66, - "panels": [], - "title": "Latency Alert - Call Functions - Classes", - "type": "row" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getClass OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "super-light-blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 81 - }, - "id": 30, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getClass\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getClass OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getClass NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "super-light-blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 81 - }, - "id": 27, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getClass\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getClass NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getClassAt OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "super-light-blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 81 - }, - "id": 31, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getClassAt\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getClassAt OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getClassAt NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "super-light-blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 81 - }, - "id": 29, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getClassAt\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getClassAt NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getClassHashAt OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "super-light-blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 88 - }, - "id": 23, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getClassHashAt\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getClassHashAt OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getClassHashAt NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "super-light-blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 88 - }, - "id": 32, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getClassHashAt\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getClassHashAt NEW_VERSION Latency", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 95 - }, - "id": 12, - "panels": [], - "title": "Latency Alert - Call Functions - Others", - "type": "row" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet call OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 96 - }, - "id": 15, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"call\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "call OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet call NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 96 - }, - "id": 16, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"call\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "call NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet chainId OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 96 - }, - "id": 19, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"chainId\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "chainId OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet chainId NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 96 - }, - "id": 17, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"chainId\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "chainId NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet estimateFee OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 103 - }, - "id": 21, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"estimateFee\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "estimateFee OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet estimateFee NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 103 - }, - "id": 20, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"estimateFee\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "estimateFee NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getNonce OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 103 - }, - "id": 37, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getNonce\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getNonce OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getNonce NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 103 - }, - "id": 36, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getNonce\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getNonce NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getEvents OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 110 - }, - "id": 35, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getEvents\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getEvents OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getEvents NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 110 - }, - "id": 34, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getEvents\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getEvents NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getStorageAt OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 110 - }, - "id": 41, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getStorageAt\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getStorageAt OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getStorageAt NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 110 - }, - "id": 40, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getStorageAt\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getStorageAt NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getStateUpdate OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 117 - }, - "id": 39, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getStateUpdate\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getStateUpdate OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet getStateUpdate NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 117 - }, - "id": 38, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"getStateUpdate\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "getStateUpdate NEW_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet syncing OLD_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 117 - }, - "id": 33, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"syncing\",version=\"OLD_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "syncing OLD_VERSION Latency", - "type": "timeseries" - }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Starknet syncing NEW_VERSION Latency Alert (Papyrus)", - "noDataState": "no_data", - "notifications": [] - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Latency (seconds)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 117 - }, - "id": 50, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"NAMESPACE\", method=\"syncing\",version=\"NEW_VERSION\",quantile=\"0.95\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "op": "gt", - "value": 1, - "visible": true - } - ], - "title": "syncing NEW_VERSION Latency", - "type": "timeseries" - } - ], - "refresh": false, - "schemaVersion": 36, - "style": "dark", - "tags": [], - "templating": { - "list": [] - }, - "time": { - "from": "now-15m", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "Papyrus-alerts", - "uid": null, - "version": 58, - "weekStart": "" -} diff --git a/deployments/papyrus/monitoring/templates/grafana_dashboard.json b/deployments/papyrus/monitoring/templates/grafana_dashboard.json deleted file mode 100644 index 3cfdc1d2da0..00000000000 --- a/deployments/papyrus/monitoring/templates/grafana_dashboard.json +++ /dev/null @@ -1,9286 +0,0 @@ -{ - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__elements": [], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "8.5.5" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "stat", - "name": "Stat", - "version": "" - }, - { - "type": "panel", - "id": "timeseries", - "name": "Time series", - "version": "" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": null, - "iteration": 1697099323886, - "links": [], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 30, - "panels": [], - "title": "Sync", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The difference, in seconds, between the time the node received the batch and the batch creation timestamp.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisGridShow": true, - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "opacity", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 4, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 1 - }, - "id": 20, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "papyrus_header_latency{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "legendFormat": "Latency (seconds)", - "range": true, - "refId": "A" - } - ], - "title": "Header Latency", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The Current Starknet block number.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "max": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "blue", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 8 - }, - "id": 16, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "format": "table", - "hide": false, - "instant": true, - "range": false, - "refId": "A" - } - ], - "title": "Starknet Block Number", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The block number of the last Starknet block that was finalized on L1.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "max": 0, - "noValue": "0", - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "blue", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 15, - "x": 0, - "y": 14 - }, - "id": 15, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "papyrus_base_layer_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "format": "table", - "hide": false, - "instant": true, - "range": false, - "refId": "A" - } - ], - "title": "L1 Block Number", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The difference between Starknet Block Number and L1 Block Number.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "blue", - "value": null - }, - { - "color": "light-blue", - "value": 100 - }, - { - "color": "super-light-orange", - "value": 1000 - }, - { - "color": "orange", - "value": 10000 - }, - { - "color": "red", - "value": 100000 - } - ] - }, - "unit": "locale" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 9, - "x": 15, - "y": 14 - }, - "id": 69, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} - papyrus_base_layer_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "L1 Block Number Diff", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The current block header marker.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "max": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 0, - "y": 19 - }, - "id": 21, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "papyrus_header_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "format": "table", - "hide": false, - "instant": true, - "range": false, - "refId": "A" - } - ], - "title": "Block Header", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The current block body marker.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "max": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 6, - "y": 19 - }, - "id": 18, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "papyrus_body_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "format": "table", - "hide": false, - "instant": true, - "range": false, - "refId": "A" - } - ], - "title": "Block Body", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The current state update marker.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "max": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 12, - "y": 19 - }, - "id": 14, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "papyrus_state_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "format": "table", - "hide": false, - "instant": true, - "range": false, - "refId": "A" - } - ], - "title": "State Update", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The current compiled class marker.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "max": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 18, - "y": 19 - }, - "id": 10, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "papyrus_compiled_class_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "format": "table", - "hide": false, - "instant": true, - "range": false, - "refId": "A" - } - ], - "title": "Compiled Class (CASM)", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The difference between the current Starknet block number and the current block header marker.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "super-light-green", - "value": 1 - }, - { - "color": "super-light-orange", - "value": 5 - }, - { - "color": "orange", - "value": 10 - }, - { - "color": "red", - "value": 20 - } - ] - }, - "unit": "locale" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 0, - "y": 24 - }, - "id": 11, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} - papyrus_header_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "Block Header Diff", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The difference between the current Starknet block number and the current block body marker.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "super-light-green", - "value": 1 - }, - { - "color": "super-light-orange", - "value": 5 - }, - { - "color": "orange", - "value": 10 - }, - { - "color": "red", - "value": 20 - } - ] - }, - "unit": "locale" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 6, - "y": 24 - }, - "id": 66, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} - papyrus_body_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "Block Body Diff", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The difference between the current Starknet block number and the current state update marker.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "super-light-green", - "value": 1 - }, - { - "color": "super-light-orange", - "value": 5 - }, - { - "color": "orange", - "value": 10 - }, - { - "color": "red", - "value": 20 - } - ] - }, - "unit": "locale" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 12, - "y": 24 - }, - "id": 67, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} - papyrus_state_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "State Update Diff", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The difference between the current Starknet block number and the current compiled class marker.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "super-light-green", - "value": 1 - }, - { - "color": "super-light-orange", - "value": 5 - }, - { - "color": "orange", - "value": 10 - }, - { - "color": "red", - "value": 20 - } - ] - }, - "unit": "locale" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 18, - "y": 24 - }, - "id": 68, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} - papyrus_compiled_class_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"}", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "Compiled Class (CASM) Diff", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The percentage of the current block header marker from the current Starknet block number.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "mappings": [], - "max": 100, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 0.5 - }, - { - "color": "super-light-orange", - "value": 0.75 - }, - { - "color": "super-light-green", - "value": 0.9 - }, - { - "color": "green", - "value": 1 - } - ] - }, - "unit": "percentunit" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 0, - "y": 29 - }, - "id": 65, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "floor(papyrus_header_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} / papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} * 10^4) / 10^4", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "Block Header %", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The percentage of the current block body marker from the current Starknet block number.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "mappings": [], - "max": 100, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 0.5 - }, - { - "color": "super-light-orange", - "value": 0.75 - }, - { - "color": "super-light-green", - "value": 0.9 - }, - { - "color": "green", - "value": 1 - } - ] - }, - "unit": "percentunit" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 6, - "y": 29 - }, - "id": 17, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "floor(papyrus_body_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} / papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} * 10^4) / 10^4", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "Block Body %", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The percentage of the current state update marker from the current Starknet block number.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "mappings": [], - "max": 100, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 0.5 - }, - { - "color": "super-light-orange", - "value": 0.75 - }, - { - "color": "super-light-green", - "value": 0.9 - }, - { - "color": "green", - "value": 1 - } - ] - }, - "unit": "percentunit" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 12, - "y": 29 - }, - "id": 9, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "floor(papyrus_state_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} / papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} * 10^4) / 10^4", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "State Update %", - "transformations": [], - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The percentage of the current compiled class marker from the current Starknet block number.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "mappings": [], - "max": 100, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 0.5 - }, - { - "color": "super-light-orange", - "value": 0.75 - }, - { - "color": "super-light-green", - "value": 0.9 - }, - { - "color": "green", - "value": 1 - } - ] - }, - "unit": "percentunit" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Central" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 18, - "y": 29 - }, - "id": 13, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "floor(papyrus_compiled_class_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} / papyrus_central_block_marker{kubernetes_namespace=\"$namespace\", pod=~\"$pod\"} * 10^4) / 10^4", - "hide": false, - "refId": "Head / Central" - } - ], - "title": "Compiled Class (CASM) %", - "transformations": [], - "type": "stat" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 34 - }, - "id": 34, - "panels": [], - "title": "Resources usage", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "CPU usage percentage.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "Percentage", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "opacity", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "percent" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Value" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 12, - "x": 0, - "y": 35 - }, - "id": 36, - "options": { - "legend": { - "calcs": [ - "min", - "max", - "mean" - ], - "displayMode": "table", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "exemplar": false, - "expr": "rate(container_cpu_usage_seconds_total{namespace=\"$namespace\", pod=~\"$pod\", container!=\"\"}[1m])", - "interval": "", - "legendFormat": "{{container}}", - "range": true, - "refId": "A" - } - ], - "title": "CPU usage", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Memory usage in bytes.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "Bytes", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "opacity", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 4, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "bytes" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Value" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 12, - "x": 12, - "y": 35 - }, - "id": 38, - "options": { - "legend": { - "calcs": [ - "min", - "max", - "mean" - ], - "displayMode": "table", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "sum(container_memory_working_set_bytes{namespace=\"$namespace\", pod=~\"$pod\", container!=\"\"}) by (container, pod)", - "legendFormat": "{{container}}", - "range": true, - "refId": "A" - } - ], - "title": "Memory usage", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Storage usage in bytes.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "Bytes", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "opacity", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 3, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Value" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 45 - }, - "id": 40, - "options": { - "legend": { - "calcs": [ - "min", - "max", - "mean" - ], - "displayMode": "table", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "kubelet_volume_stats_capacity_bytes{namespace=\"$namespace\"} - kubelet_volume_stats_available_bytes{namespace=\"$namespace\"}", - "legendFormat": "{{namespace}}", - "range": true, - "refId": "A" - } - ], - "title": "Storage usage", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Networking usage.\nTx - Transmitting.\nRx - Receiving.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "Bytes / Minute", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "opacity", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "Bps" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Tx" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Rx" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 45 - }, - "id": 44, - "options": { - "legend": { - "calcs": [ - "min", - "max", - "mean" - ], - "displayMode": "table", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "- sum(rate(container_network_transmit_bytes_total{image!=\"\", namespace=\"$namespace\", pod=~\"$pod\"}[1m])) by (container, pod)", - "hide": false, - "legendFormat": "Tx", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "sum(rate(container_network_receive_bytes_total{image!=\"\", namespace=\"$namespace\", pod=~\"$pod\"}[1m])) by (container, pod)", - "hide": false, - "legendFormat": "Rx", - "range": true, - "refId": "B" - } - ], - "title": "Networking usage", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 53 - }, - "id": 32, - "panels": [], - "title": "Requests and latencies", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 54 - }, - "id": 62, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"blockNumber\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "blockNumber Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 54 - }, - "id": 70, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"blockNumber\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "blockNumber Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 54 - }, - "id": 71, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"blockNumber\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "blockNumber Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 54 - }, - "id": 72, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"blockNumber\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "blockNumber Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 61 - }, - "id": 73, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getNonce\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getNonce Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 61 - }, - "id": 74, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getNonce\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getNonce Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 61 - }, - "id": 75, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getNonce\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getNonce Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 61 - }, - "id": 76, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getNonce\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getNonce Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 68 - }, - "id": 84, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getStateUpdate\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getStateUpdate Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 68 - }, - "id": 83, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getStateUpdate\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getStateUpdate Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 68 - }, - "id": 82, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getStateUpdate\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getStateUpdate Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 68 - }, - "id": 80, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getStateUpdate\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getStateUpdate Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 75 - }, - "id": 77, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionByHash\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getTransactionByHash Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 75 - }, - "id": 101, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionByHash\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getTransactionByHash Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 75 - }, - "id": 79, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionByHash\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getTransactionByHash Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 75 - }, - "id": 85, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionByHash\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getTransactionByHash Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 82 - }, - "id": 103, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClass\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getClass Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 82 - }, - "id": 104, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClass\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getClass Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 82 - }, - "id": 105, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClass\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getClass Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 82 - }, - "id": 81, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClass\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getClass Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 89 - }, - "id": 106, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getEvents\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getEvents Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 89 - }, - "id": 107, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getEvents\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getEvents Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 89 - }, - "id": 108, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getEvents\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getEvents Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 89 - }, - "id": 86, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getNonce\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getEvents Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 96 - }, - "id": 109, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClassAt\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getClassAt Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 96 - }, - "id": 110, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClassAt\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getClassAt Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 96 - }, - "id": 102, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClassAt\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getClassAt Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 96 - }, - "id": 87, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClassAt\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getClassAt Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 103 - }, - "id": 112, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClassHashAt\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getClassHashAt Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 103 - }, - "id": 113, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClassHashAt\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getClassHashAt Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 103 - }, - "id": 114, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClassHashAt\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getClassHashAt Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 103 - }, - "id": 88, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getClassHashAt\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getClassHashAt Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 110 - }, - "id": 115, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockWithTxs\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getBlockWithTxs Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 110 - }, - "id": 116, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockWithTxs\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getBlockWithTxs Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 110 - }, - "id": 117, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockWithTxs\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getBlockWithTxs Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 110 - }, - "id": 89, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockWithTxs\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getBlockWithTxs Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 117 - }, - "id": 118, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getStorageAt\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getStorageAt Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 117 - }, - "id": 78, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getStorageAt\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getStorageAt Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 117 - }, - "id": 111, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getStorageAt\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getStorageAt Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 117 - }, - "id": 90, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getStorageAt\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getStorageAt Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 124 - }, - "id": 121, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockTransactionCount\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getBlockTransactionCount Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 124 - }, - "id": 122, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockTransactionCount\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getBlockTransactionCount Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 124 - }, - "id": 123, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockTransactionCount\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getBlockTransactionCount Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 124 - }, - "id": 91, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockTransactionCount\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getBlockTransactionCount Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 131 - }, - "id": 124, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionReceipt\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getTransactionReceipt Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 131 - }, - "id": 125, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionReceipt\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getTransactionReceipt Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 131 - }, - "id": 126, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionReceipt\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getTransactionReceipt Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 131 - }, - "id": 92, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionReceipt\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getTransactionReceipt Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 138 - }, - "id": 127, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockWithTxHashes\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getBlockWithTxHashes Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 138 - }, - "id": 128, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockWithTxHashes\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getBlockWithTxHashes Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 138 - }, - "id": 129, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockWithTxHashes\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getBlockWithTxHashes Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 138 - }, - "id": 93, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getBlockWithTxHashes\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getBlockWithTxHashes Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 145 - }, - "id": 130, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionByBlockIdAndIndex\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "getTransactionByBlockIdAndIndex Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 145 - }, - "id": 131, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionByBlockIdAndIndex\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "getTransactionByBlockIdAndIndex Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 145 - }, - "id": 132, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionByBlockIdAndIndex\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "getTransactionByBlockIdAndIndex Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 145 - }, - "id": 94, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"getTransactionByBlockIdAndIndex\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "getTransactionByBlockIdAndIndex Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 152 - }, - "id": 133, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addInvokeTransaction\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "addInvokeTransaction Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 152 - }, - "id": 134, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addInvokeTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "addInvokeTransaction Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 152 - }, - "id": 135, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addInvokeTransaction\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "addInvokeTransaction Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 152 - }, - "id": 95, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addInvokeTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "addInvokeTransaction Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 159 - }, - "id": 136, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"blockHashAndNumber\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "blockHashAndNumber Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 159 - }, - "id": 137, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"blockHashAndNumber\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "blockHashAndNumber Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 159 - }, - "id": 138, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"blockHashAndNumber\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "blockHashAndNumber Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 159 - }, - "id": 96, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"blockHashAndNumber\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "blockHashAndNumber Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 166 - }, - "id": 139, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"chainId\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "chainId Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 166 - }, - "id": 140, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"chainId\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "chainId Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 166 - }, - "id": 141, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"chainId\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "chainId Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 166 - }, - "id": 97, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"chainId\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "chainId Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 173 - }, - "id": 142, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"syncing\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "syncing Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 173 - }, - "id": 143, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"syncing\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "syncing Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 173 - }, - "id": 144, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"syncing\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "syncing Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 173 - }, - "id": 98, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"syncing\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "syncing Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 180 - }, - "id": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"call\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "call Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 180 - }, - "id": 119, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"call\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "call Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 180 - }, - "id": 120, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"call\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "call Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 180 - }, - "id": 99, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"call\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "call Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 169 - }, - "id": 153, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"simulateTransactions\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "simulateTransactions Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 169 - }, - "id": 154, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"simulateTransactions\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "simulateTransactions Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 169 - }, - "id": 155, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"simulateTransactions\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "simulateTransactions Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 169 - }, - "id": 156, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"simulateTransactions\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "simulateTransactions Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 176 - }, - "id": 157, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"estimateFee\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "estimateFee Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 176 - }, - "id": 158, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"estimateFee\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "estimateFee Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 176 - }, - "id": 159, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"estimateFee\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "estimateFee Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 176 - }, - "id": 160, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"estimateFee\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "estimateFee Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 183 - }, - "id": 145, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"traceTransaction\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "traceTransaction Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 183 - }, - "id": 146, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"traceTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "traceTransaction Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 183 - }, - "id": 147, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"traceTransaction\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "traceTransaction Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 183 - }, - "id": 148, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"traceTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "traceTransaction Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 190 - }, - "id": 149, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"traceBlockTransactions\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "traceBlockTransactions Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 190 - }, - "id": 150, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"traceBlockTransactions\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "traceBlockTransactions Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 190 - }, - "id": 151, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"traceBlockTransactions\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "traceBlockTransactions Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 190 - }, - "id": 152, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"traceBlockTransactions\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "traceBlockTransactions Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 197 - }, - "id": 164, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addInvokeTransaction\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "addInvokeTransaction Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 197 - }, - "id": 163, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addInvokeTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "addInvokeTransaction Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 197 - }, - "id": 162, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addInvokeTransaction\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "addInvokeTransaction Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 197 - }, - "id": 161, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addInvokeTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "addInvokeTransaction Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 204 - }, - "id": 172, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addDeployAccountTransaction\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "addDeployAccountTransaction Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 204 - }, - "id": 170, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addDeployAccountTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "addDeployAccountTransaction Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 204 - }, - "id": 167, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addDeployAccountTransaction\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "addDeployAccountTransaction Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 204 - }, - "id": 166, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addDeployAccountTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "addDeployAccountTransaction Latencies", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of incoming requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 211 - }, - "id": 171, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_incoming_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addDeclareTransaction\",version=\"$version\"}", - "legendFormat": "Incoming requests", - "range": true, - "refId": "A" - } - ], - "title": "addDeclareTransaction Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "Number of failed requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 211 - }, - "id": 169, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_failed_requests{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addDeclareTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "Failed requests", - "range": true, - "refId": "C" - } - ], - "title": "addDeclareTransaction Failed Requests", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latency of the quickest 95% of the requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 211 - }, - "id": 168, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addDeclareTransaction\",version=\"$version\",quantile=\"0.95\"}", - "hide": false, - "legendFormat": "Latency", - "range": true, - "refId": "B" - } - ], - "title": "addDeclareTransaction Latency (0.95)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "description": "The maximal latencies of different percentages of the quickest requests.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "decimals": 10, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 211 - }, - "id": 165, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rpc_request_latency_seconds{kubernetes_namespace=\"$namespace\", pod=~\"$pod\", method=\"addDeclareTransaction\",version=\"$version\"}", - "hide": false, - "legendFormat": "{{quantile}}", - "range": true, - "refId": "B" - } - ], - "title": "addDeclareTransaction Latencies", - "type": "timeseries" - } - ], - "refresh": false, - "schemaVersion": 36, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "current": {}, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "definition": "label_values(papyrus_header_marker, kubernetes_namespace)", - "hide": 0, - "includeAll": false, - "multi": false, - "name": "namespace", - "options": [], - "query": { - "query": "label_values(papyrus_header_marker, kubernetes_namespace)", - "refId": "StandardVariableQuery" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "type": "query" - }, - { - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "definition": "label_values(papyrus_header_marker{kubernetes_namespace=\"$namespace\"}, pod)", - "hide": 0, - "includeAll": true, - "multi": true, - "name": "pod", - "options": [], - "query": { - "query": "label_values(papyrus_header_marker{kubernetes_namespace=\"$namespace\"}, pod)", - "refId": "StandardVariableQuery" - }, - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "type": "query" - }, - { - "current": { - "selected": true, - "text": "V0_5", - "value": "V0_5" - }, - "hide": 0, - "includeAll": false, - "multi": false, - "name": "version", - "options": [ - { - "selected": false, - "text": "V0_4", - "value": "V0_4" - }, - { - "selected": false, - "text": "V0_5", - "value": "V0_5" - } - ], - "query": "V0_4,V0_5", - "queryValue": "None", - "skipUrlSync": false, - "type": "custom" - } - ] - }, - "time": { - "from": "now-30m", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "Papyrus-node-data", - "uid": null, - "version": 60, - "weekStart": "" -} \ No newline at end of file From 8078c4d81541a5d74b5cf5454bee00a6c8d0514a Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Mon, 20 Oct 2025 10:53:02 +0300 Subject: [PATCH 080/313] apollo_consensus_orchestrator: fix conflicts Signed-off-by: Dori Medini --- .../src/build_proposal_test.rs | 8 ----- .../src/config.rs | 29 ++----------------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs b/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs index fa95ac77375..e1c864768a5 100644 --- a/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs +++ b/crates/apollo_consensus_orchestrator/src/build_proposal_test.rs @@ -21,15 +21,7 @@ use apollo_state_sync_types::errors::StateSyncError; use assert_matches::assert_matches; use blockifier::abi::constants::STORED_BLOCK_HASH_BUFFER; use futures::channel::mpsc; -<<<<<<< HEAD -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; -||||||| 9552005d0 -use num_rational::Ratio; -use starknet_api::block::{BlockHash, BlockNumber, GasPrice}; -======= -use num_rational::Ratio; use starknet_api::block::{BlockNumber, GasPrice}; ->>>>>>> origin/main-v0.14.1 use starknet_api::core::{ClassHash, ContractAddress}; use starknet_api::data_availability::L1DataAvailabilityMode; use tokio_util::sync::CancellationToken; diff --git a/crates/apollo_consensus_orchestrator_config/src/config.rs b/crates/apollo_consensus_orchestrator_config/src/config.rs index 4c045692032..7ec971327c7 100644 --- a/crates/apollo_consensus_orchestrator_config/src/config.rs +++ b/crates/apollo_consensus_orchestrator_config/src/config.rs @@ -141,13 +141,7 @@ pub struct ContextConfig { impl SerializeConfig for ContextConfig { fn dump(&self) -> BTreeMap { -<<<<<<< HEAD let mut dump = BTreeMap::from_iter([ -||||||| 9552005d0 - BTreeMap::from_iter([ -======= - let mut config = BTreeMap::from_iter([ ->>>>>>> origin/main-v0.14.1 ser_param( "proposal_buffer_size", &self.proposal_buffer_size, @@ -236,7 +230,6 @@ impl SerializeConfig for ContextConfig { "This additional gas is added to the L1 gas price.", ParamPrivacyInput::Public, ), -<<<<<<< HEAD ]); dump.extend(ser_optional_param( &self.override_l2_gas_price, @@ -259,24 +252,7 @@ impl SerializeConfig for ContextConfig { "Replace the L1 data gas price with this value.", ParamPrivacyInput::Public, )); - dump -||||||| 9552005d0 - ser_param( - "constant_l2_gas_price", - &self.constant_l2_gas_price, - "If true, sets STRK gas price to its minimum price from the versioned constants.", - ParamPrivacyInput::Public, - ), - ]) -======= - ser_param( - "constant_l2_gas_price", - &self.constant_l2_gas_price, - "If true, sets STRK gas price to its minimum price from the versioned constants.", - ParamPrivacyInput::Public, - ), - ]); - config.extend(ser_optional_param( + dump.extend(ser_optional_param( &self.validator_ids.as_ref().map(|accounts| { accounts.iter().map(|addr| addr.0.to_string()).collect::>().join(",") }), @@ -285,8 +261,7 @@ impl SerializeConfig for ContextConfig { "Optional explicit set of validator IDs (comma separated).", ParamPrivacyInput::Public, )); - config ->>>>>>> origin/main-v0.14.1 + dump } } From 4baa5dad4142080fb488e50a724dd66d91dc9674 Mon Sep 17 00:00:00 2001 From: Meshi Peled <141231558+meship-starkware@users.noreply.github.com> Date: Mon, 20 Oct 2025 11:19:58 +0300 Subject: [PATCH 081/313] blockifier: small fixes in block casm hash v1 error (#9283) --- crates/apollo_gateway/src/errors.rs | 6 +++++ .../src/transaction/account_transaction.rs | 12 +--------- crates/blockifier/src/transaction/errors.rs | 17 +------------ .../src/transaction/transactions_test.rs | 24 ++++++++++++++----- .../src/executable_transaction.rs | 16 +++++++------ crates/starknet_api/src/lib.rs | 24 +++++++++++++++++++ 6 files changed, 59 insertions(+), 40 deletions(-) diff --git a/crates/apollo_gateway/src/errors.rs b/crates/apollo_gateway/src/errors.rs index a7044f2221a..986b77c9d68 100644 --- a/crates/apollo_gateway/src/errors.rs +++ b/crates/apollo_gateway/src/errors.rs @@ -431,5 +431,11 @@ fn convert_sn_api_error(err: StarknetApiError) -> StarknetError { code: StarknetErrorCode::KnownErrorCode(KnownStarknetErrorCode::MalformedRequest), message: err.to_string(), }, + StarknetApiError::DeclareTransactionCasmHashMissMatch(err) => StarknetError { + code: StarknetErrorCode::KnownErrorCode( + KnownStarknetErrorCode::InvalidCompiledClassHash, + ), + message: err.to_string(), + }, } } diff --git a/crates/blockifier/src/transaction/account_transaction.rs b/crates/blockifier/src/transaction/account_transaction.rs index f688d5ecace..5133541feb0 100644 --- a/crates/blockifier/src/transaction/account_transaction.rs +++ b/crates/blockifier/src/transaction/account_transaction.rs @@ -566,17 +566,7 @@ impl AccountTransaction { && self.tx.version() >= TransactionVersion::THREE { if let Transaction::Declare(declare_tx) = &self.tx { - if let Err((class_hash, compiled_class_hash, compiled_class_hash_v2)) = - declare_tx.check_compile_class_hash_v2_declaration() - { - return Err( - TransactionExecutionError::DeclareTransactionCasmHashMissMatch { - class_hash, - compiled_class_hash, - compiled_class_hash_v2, - }, - ); - } + declare_tx.check_compile_class_hash_v2_declaration()?; } } validate_call_info = self.validate_tx(state, tx_context.clone(), remaining_gas)?; diff --git a/crates/blockifier/src/transaction/errors.rs b/crates/blockifier/src/transaction/errors.rs index 0296ce98180..6aec11f35ab 100644 --- a/crates/blockifier/src/transaction/errors.rs +++ b/crates/blockifier/src/transaction/errors.rs @@ -1,13 +1,7 @@ use cairo_vm::types::errors::program_errors::ProgramError; use num_bigint::BigUint; use starknet_api::block::GasPrice; -use starknet_api::core::{ - ClassHash, - CompiledClassHash, - ContractAddress, - EntryPointSelector, - Nonce, -}; +use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce}; use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::{AllResourceBounds, Fee, Resource}; use starknet_api::transaction::TransactionVersion; @@ -86,15 +80,6 @@ pub enum TransactionExecutionError { ContractConstructorExecutionFailed(#[from] ConstructorEntryPointExecutionError), #[error("Class with hash {:#066x} is already declared.", **class_hash)] DeclareTransactionError { class_hash: ClassHash }, - #[error( - "Mismatch compiled class hash for class with hash {:#064x}. Actual: {:#064x}, Expected: {:#064x}", - class_hash.0, compiled_class_hash.0, compiled_class_hash_v2.0 - )] - DeclareTransactionCasmHashMissMatch { - class_hash: ClassHash, - compiled_class_hash: CompiledClassHash, - compiled_class_hash_v2: CompiledClassHash, - }, #[error("{}", gen_tx_execution_error_trace(self))] ExecutionError { error: Box, diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index bbf4195ce08..65c6d765183 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -1787,12 +1787,20 @@ fn test_declare_redeposit_amount_regression() { } #[apply(cairo_version)] -#[case(TransactionVersion::ZERO, CairoVersion::Cairo0, HashVersion::V2)] -#[case(TransactionVersion::ONE, CairoVersion::Cairo0, HashVersion::V2)] -#[case(TransactionVersion::TWO, CairoVersion::Cairo1(RunnableCairo1::Casm), HashVersion::V2)] -#[case(TransactionVersion::THREE, CairoVersion::Cairo1(RunnableCairo1::Casm), HashVersion::V2)] +#[case(TransactionVersion::ZERO, CairoVersion::Cairo0, None)] +#[case(TransactionVersion::ONE, CairoVersion::Cairo0, None)] +#[case(TransactionVersion::TWO, CairoVersion::Cairo1(RunnableCairo1::Casm), None)] +#[case( + TransactionVersion::THREE, + CairoVersion::Cairo1(RunnableCairo1::Casm), + Some(HashVersion::V2) +)] #[should_panic(expected = "DeclareTransactionCasmHashMissMatch")] -#[case(TransactionVersion::THREE, CairoVersion::Cairo1(RunnableCairo1::Casm), HashVersion::V1)] +#[case( + TransactionVersion::THREE, + CairoVersion::Cairo1(RunnableCairo1::Casm), + Some(HashVersion::V1) +)] fn test_declare_tx( default_all_resource_bounds: ValidResourceBounds, cairo_version: CairoVersion, @@ -1800,7 +1808,7 @@ fn test_declare_tx( #[case] empty_contract_version: CairoVersion, // Used only for V3+ transactions to check that we are blocking declare txs with V1 casm // hashes. - #[case] hash_version: HashVersion, + #[case] hash_version: Option, #[values(false, true)] use_kzg_da: bool, ) { let account_cairo_version = cairo_version; @@ -1811,6 +1819,10 @@ fn test_declare_tx( let chain_info = &block_context.chain_info; let state = &mut test_state(chain_info, BALANCE, &[(account, 1)]); let class_hash = empty_contract.get_class_hash(); + let hash_version = match hash_version { + Some(hash_version) => hash_version, + None => HashVersion::V2, + }; let compiled_class_hash = empty_contract.get_compiled_class_hash(&hash_version); let class_info = calculate_class_info_for_testing(empty_contract.get_class()); let sender_address = account.get_instance_address(0); diff --git a/crates/starknet_api/src/executable_transaction.rs b/crates/starknet_api/src/executable_transaction.rs index 2fe599a98da..dc9c7e4180a 100644 --- a/crates/starknet_api/src/executable_transaction.rs +++ b/crates/starknet_api/src/executable_transaction.rs @@ -30,7 +30,7 @@ use crate::transaction::{ TransactionHasher, TransactionVersion, }; -use crate::StarknetApiError; +use crate::{CasmHashMismatch, StarknetApiError}; macro_rules! implement_inner_tx_getter_calls { ($(($field:ident, $field_type:ty)),*) => { @@ -203,9 +203,7 @@ impl DeclareTransaction { /// Verifies that the compiled class hash field in the declare tx, /// is compiled_class_hash_v2 of the compiled contract. - pub fn check_compile_class_hash_v2_declaration( - &self, - ) -> Result<(), (ClassHash, CompiledClassHash, CompiledClassHash)> { + pub fn check_compile_class_hash_v2_declaration(&self) -> Result<(), StarknetApiError> { let compiled_class = &self.class_info.contract_class; let compiled_class_hash_v2 = match &compiled_class { ContractClass::V0(_) => return Ok(()), @@ -213,10 +211,14 @@ impl DeclareTransaction { }; let compiled_class_hash = self.compiled_class_hash(); if compiled_class_hash_v2 != compiled_class_hash { - Err((self.class_hash(), compiled_class_hash, compiled_class_hash_v2)) - } else { - Ok(()) + let err_var = CasmHashMismatch { + hash: self.class_hash(), + actual: compiled_class_hash, + expected: compiled_class_hash_v2, + }; + return Err(StarknetApiError::DeclareTransactionCasmHashMissMatch(Box::new(err_var))); } + Ok(()) } // Returns whether the declare transaction is for bootstrapping. diff --git a/crates/starknet_api/src/lib.rs b/crates/starknet_api/src/lib.rs index 1b731f18bdb..5278a727e80 100644 --- a/crates/starknet_api/src/lib.rs +++ b/crates/starknet_api/src/lib.rs @@ -30,8 +30,27 @@ pub mod versioned_constants_logic; use std::num::ParseIntError; +use crate::core::{ClassHash, CompiledClassHash}; use crate::transaction::TransactionVersion; +#[derive(Clone, Debug, PartialEq)] +pub struct CasmHashMismatch { + hash: ClassHash, + actual: CompiledClassHash, + expected: CompiledClassHash, +} + +impl std::fmt::Display for CasmHashMismatch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Mismatch compiled class hash for class with hash {:#064x}. Actual: {:#064x}, \ + Expected: {:#064x}", + self.hash.0, self.actual.0, self.expected.0 + ) + } +} + /// The error type returned by StarknetApi. // Note: if you need `Eq` see InnerDeserializationError's docstring. #[derive(thiserror::Error, Clone, Debug, PartialEq)] @@ -73,6 +92,11 @@ pub enum StarknetApiError { ParseSierraVersionError(String), #[error("Unsupported transaction type: {0}")] UnknownTransactionType(String), + #[error( + "Mismatch compiled class hash for class with hash {:#064x}. Actual: {:#064x}, Expected: {:#064x}", + .0.hash.0, .0.actual.0, .0.expected.0 + )] + DeclareTransactionCasmHashMissMatch(Box), } pub type StarknetApiResult = Result; From 58b1a373135b06f1efe81654b603562308d304e0 Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Mon, 20 Oct 2025 11:49:49 +0300 Subject: [PATCH 082/313] starknet_committer_and_os_cli: support cell blobs (#9639) --- .../src/kzg_cli/run_kzg_cli.rs | 17 +++++- .../hints/hint_implementation/kzg/utils.rs | 55 +++++++++++++++++-- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs b/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs index d73ae6fe271..1dfc1013009 100644 --- a/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs +++ b/crates/starknet_committer_and_os_cli/src/kzg_cli/run_kzg_cli.rs @@ -1,5 +1,8 @@ use clap::{Parser, Subcommand}; -use starknet_os::hints::hint_implementation::kzg::utils::compute_blob_commitments; +use starknet_os::hints::hint_implementation::kzg::utils::{ + compute_blob_commitments, + compute_legacy_blob_commitments, +}; use tracing::info; use crate::shared_utils::read::{load_input, write_to_file}; @@ -17,6 +20,10 @@ enum Command { #[clap(flatten)] io_args: IoArgs, }, + ComputeLegacyBlobCommitments { + #[clap(flatten)] + io_args: IoArgs, + }, } pub fn run_kzg_cli(kzg_command: KzgCliCommand) { @@ -28,5 +35,13 @@ pub fn run_kzg_cli(kzg_command: KzgCliCommand) { .unwrap_or_else(|error| panic!("Failed to calculate blob commitments: {error}")); write_to_file(&output_path, &blobs); } + // TODO(Yoni): remove this command once python migrates to the new blob commitments. + Command::ComputeLegacyBlobCommitments { io_args: IoArgs { input_path, output_path } } => { + let raw_blobs: Vec> = load_input(input_path); + let blobs = compute_legacy_blob_commitments(raw_blobs).unwrap_or_else(|error| { + panic!("Failed to calculate legacy blob commitments: {error}") + }); + write_to_file(&output_path, &blobs); + } }; } diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs index 2ac1aeefd3c..832d6bec479 100644 --- a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs @@ -164,7 +164,7 @@ pub fn split_bigint3(num: BigInt) -> Result<[Felt; 3], OsHintError> { /// Structure to hold blob artifacts: commitments, proofs, and versioned hashes. #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct BlobArtifacts { +pub struct LegacyBlobArtifacts { #[serde_as(as = "Vec")] pub commitments: Vec<[u8; 48]>, #[serde_as(as = "Vec")] @@ -189,11 +189,13 @@ fn kzg_to_versioned_hash(commitment: &KzgCommitment) -> [u8; 32] { hash.into() } -/// Computes KZG commitments, proofs, and versioned hashes for a list of raw blobs. +/// Computes KZG commitments, legacy proofs, and versioned hashes for a list of raw blobs. /// /// For each blob, computes the KZG commitment and the corresponding KZG proof that is used -/// to verify the commitment. Returns `BlobArtifacts` structure. -pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result { +/// to verify the commitment. Returns `LegacyBlobArtifacts` structure. +pub fn compute_legacy_blob_commitments( + raw_blobs: Vec>, +) -> Result { let mut commitments = Vec::new(); let mut proofs = Vec::new(); let mut versioned_hashes = Vec::new(); @@ -216,5 +218,48 @@ pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result, + #[serde_as(as = "Vec")] + pub cell_proofs: Vec<[u8; 48]>, + #[serde_as(as = "Vec")] + pub versioned_hashes: Vec<[u8; 32]>, +} + +/// Computes KZG commitments, cell proofs, and versioned hashes for a list of raw blobs. +/// +/// For each blob, computes the KZG commitment and the corresponding KZG cell proofs that is used +/// to verify the commitment. Returns the internal `CellBlobs` structure with native KZG types. +pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result { + let mut commitments = Vec::new(); + let mut cell_proofs = Vec::new(); + let mut versioned_hashes = Vec::new(); + + for raw_blob in raw_blobs.iter() { + // Convert raw blob bytes to Blob. + let blob = Blob::from_bytes(raw_blob)?; + + // Compute KZG commitment. + let commitment = blob_to_kzg_commitment(&blob)?; + + // Compute KZG cell proofs. + let (_, blob_cell_proofs) = KZG_SETTINGS.compute_cells_and_kzg_proofs(&blob)?; + + // Compute versioned hash. + let versioned_hash = kzg_to_versioned_hash(&commitment); + + commitments.push(*commitment); + cell_proofs.extend(blob_cell_proofs.into_iter().map(|proof| *proof)); + versioned_hashes.push(versioned_hash); + } + + Ok(BlobArtifacts { commitments, cell_proofs, versioned_hashes }) } From 5c30c11c3026aaf5cd566799c5a9b823f2613d68 Mon Sep 17 00:00:00 2001 From: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> Date: Mon, 20 Oct 2025 14:40:19 +0300 Subject: [PATCH 083/313] apollo_consensus_manager: Refactor run function of the ConsensusManager (#9574) --- .../src/consensus_manager.rs | 183 +++++++++++------- 1 file changed, 115 insertions(+), 68 deletions(-) diff --git a/crates/apollo_consensus_manager/src/consensus_manager.rs b/crates/apollo_consensus_manager/src/consensus_manager.rs index 2943c43bb2c..11c729b2693 100644 --- a/crates/apollo_consensus_manager/src/consensus_manager.rs +++ b/crates/apollo_consensus_manager/src/consensus_manager.rs @@ -11,7 +11,6 @@ use apollo_class_manager_types::transaction_converter::TransactionConverter; use apollo_class_manager_types::SharedClassManagerClient; use apollo_config_manager_types::communication::SharedConfigManagerClient; use apollo_consensus::stream_handler::StreamHandler; -use apollo_consensus::types::ConsensusError; use apollo_consensus::votes_threshold::QuorumType; use apollo_consensus_manager_config::config::ConsensusManagerConfig; use apollo_consensus_orchestrator::cende::CendeAmbassador; @@ -28,7 +27,12 @@ use apollo_network::network_manager::metrics::{ EventMetrics, NetworkMetrics, }; -use apollo_network::network_manager::{BroadcastTopicChannels, NetworkManager}; +use apollo_network::network_manager::{ + BroadcastTopicChannels, + BroadcastTopicClient, + BroadcastTopicServer, + NetworkManager, +}; use apollo_protobuf::consensus::{HeightAndRound, ProposalPart, StreamMessage, Vote}; use apollo_reverts::revert_blocks_and_eternal_pending; use apollo_signature_manager_types::SharedSignatureManagerClient; @@ -51,6 +55,14 @@ use crate::metrics::{ CONSENSUS_VOTES_NUM_SENT_MESSAGES, }; +type ProposalStreamMessage = StreamMessage; +type ProposalStreamHandler = StreamHandler< + ProposalPart, + HeightAndRound, + BroadcastTopicServer, + BroadcastTopicClient, +>; + #[derive(Clone)] pub struct ConsensusManager { pub config: ConsensusManagerConfig, @@ -83,11 +95,57 @@ impl ConsensusManager { } } - pub async fn run(&self) -> Result<(), ConsensusError> { + pub async fn run(&self) { if self.config.revert_config.should_revert { self.revert_batcher_blocks(self.config.revert_config.revert_up_to_and_including).await; } + let mut network_manager = self.create_network_manager(); + let (proposals_broadcast_channels, votes_broadcast_channels) = + self.register_broadcast_topics(&mut network_manager); + + let (inbound_internal_sender, inbound_internal_receiver) = + mpsc::channel(self.config.stream_handler_config.channel_buffer_capacity); + let (outbound_internal_sender, outbound_internal_receiver) = + mpsc::channel(self.config.stream_handler_config.channel_buffer_capacity); + + let stream_handler = self.create_stream_handler( + proposals_broadcast_channels, + inbound_internal_sender, + outbound_internal_receiver, + ); + + let consensus_context = self.create_sequencer_consensus_context( + &votes_broadcast_channels, + outbound_internal_sender, + ); + + let current_height = + self.batcher_client.get_height().await.expect("Failed to get height from batcher"); + let run_consensus_args = self.create_run_consensus_args(current_height.height); + + let network_task = + tokio::spawn(network_manager.run().instrument(info_span!("[Consensus network]"))); + let stream_handler_task = tokio::spawn(stream_handler.run()); + + let consensus_fut = apollo_consensus::run_consensus( + run_consensus_args, + consensus_context, + votes_broadcast_channels.into(), + inbound_internal_receiver, + ); + + tokio::select! { + consensus_result = consensus_fut => + panic!("Consensus task finished unexpectedly: {:?}", consensus_result), + network_result = network_task => + panic!("Consensus' network task finished unexpectedly: {:?}", network_result), + stream_handler_result = stream_handler_task => + panic!("Consensus' stream handler task finished unexpectedly: {:?}", stream_handler_result) + } + } + + fn create_network_manager(&self) -> NetworkManager { let mut broadcast_metrics_by_topic = HashMap::new(); broadcast_metrics_by_topic.insert( Topic::new(self.config.votes_topic.clone()).hash(), @@ -112,11 +170,36 @@ impl ConsensusManager { sqmr_metrics: None, event_metrics: Some(EventMetrics { event_counter: CONSENSUS_NETWORK_EVENTS }), }); - let mut network_manager = - NetworkManager::new(self.config.network_config.clone(), None, network_manager_metrics); + NetworkManager::new(self.config.network_config.clone(), None, network_manager_metrics) + } + + fn create_stream_handler( + &self, + proposals_broadcast_channels: BroadcastTopicChannels, + inbound_internal_sender: mpsc::Sender>, + outbound_internal_receiver: mpsc::Receiver<(HeightAndRound, mpsc::Receiver)>, + ) -> ProposalStreamHandler { + let BroadcastTopicChannels { + broadcasted_messages_receiver: inbound_network_receiver, + broadcast_topic_client: outbound_network_sender, + } = proposals_broadcast_channels; + + StreamHandler::new( + self.config.stream_handler_config.clone(), + inbound_internal_sender, + inbound_network_receiver, + outbound_internal_receiver, + outbound_network_sender, + ) + } + + fn register_broadcast_topics( + &self, + network_manager: &mut NetworkManager, + ) -> (BroadcastTopicChannels, BroadcastTopicChannels) { let proposals_broadcast_channels = network_manager - .register_broadcast_topic::>( + .register_broadcast_topic::( Topic::new(self.config.proposals_topic.clone()), self.config.broadcast_buffer_size, ) @@ -129,40 +212,15 @@ impl ConsensusManager { ) .expect("Failed to register broadcast topic"); - let BroadcastTopicChannels { - broadcasted_messages_receiver: inbound_network_receiver, - broadcast_topic_client: outbound_network_sender, - } = proposals_broadcast_channels; - - let (inbound_internal_sender, inbound_internal_receiver) = - mpsc::channel(self.config.stream_handler_config.channel_buffer_capacity); - let (outbound_internal_sender, outbound_internal_receiver) = - mpsc::channel(self.config.stream_handler_config.channel_buffer_capacity); - let stream_handler = StreamHandler::new( - self.config.stream_handler_config.clone(), - inbound_internal_sender, - inbound_network_receiver, - outbound_internal_receiver, - outbound_network_sender, - ); - - let observer_height = self - .batcher_client - .get_height() - .await - .expect("Failed to get observer_height from batcher") - .height; - let active_height = if self.config.immediate_active_height == observer_height { - // Setting `start_height` is only used to enable consensus starting immediately without - // observing the first height. This means consensus may return to a height - // it has already voted on, risking equivocation. This is only safe to do if we - // restart all nodes at this height. - observer_height - } else { - BlockNumber(observer_height.0 + 1) - }; + (proposals_broadcast_channels, votes_broadcast_channels) + } - let context = SequencerConsensusContext::new( + fn create_sequencer_consensus_context( + &self, + votes_broadcast_channels: &BroadcastTopicChannels, + outbound_internal_sender: mpsc::Sender<(HeightAndRound, mpsc::Receiver)>, + ) -> SequencerConsensusContext { + SequencerConsensusContext::new( self.config.context_config.clone(), SequencerConsensusContextDeps { transaction_converter: Arc::new(TransactionConverter::new( @@ -180,17 +238,29 @@ impl ConsensusManager { outbound_proposal_sender: outbound_internal_sender, vote_broadcast_client: votes_broadcast_channels.broadcast_topic_client.clone(), }, - ); + ) + } - let network_task = - tokio::spawn(network_manager.run().instrument(info_span!("[Consensus network]"))); - let stream_handler_task = tokio::spawn(stream_handler.run()); + fn create_run_consensus_args( + &self, + current_height: BlockNumber, + ) -> apollo_consensus::RunConsensusArguments { + let observer_height = current_height; + let active_height = if self.config.immediate_active_height == observer_height { + // Setting `start_height` is only used to enable consensus starting immediately without + // observing the first height. This means consensus may return to a height + // it has already voted on, risking equivocation. This is only safe to do if we + // restart all nodes at this height. + observer_height + } else { + BlockNumber(observer_height.0 + 1) + }; let quorum_type = if self.config.assume_no_malicious_validators { QuorumType::Honest } else { QuorumType::Byzantine }; - let run_consensus_args = apollo_consensus::RunConsensusArguments { + apollo_consensus::RunConsensusArguments { start_active_height: active_height, start_observe_height: observer_height, validator_id: self.config.consensus_manager_config.dynamic_config.validator_id, @@ -202,27 +272,6 @@ impl ConsensusManager { .static_config .sync_retry_interval, quorum_type, - }; - let consensus_fut = apollo_consensus::run_consensus( - run_consensus_args, - context, - votes_broadcast_channels.into(), - inbound_internal_receiver, - ); - - tokio::select! { - consensus_result = consensus_fut => { - match consensus_result { - Ok(_) => panic!("Consensus task finished unexpectedly"), - Err(e) => Err(e), - } - }, - network_result = network_task => { - panic!("Consensus' network task finished unexpectedly: {network_result:?}"); - } - stream_handler_result = stream_handler_task => { - panic!("Consensus' stream handler task finished unexpectedly: {stream_handler_result:?}"); - } } } @@ -278,8 +327,6 @@ pub fn create_consensus_manager( impl ComponentStarter for ConsensusManager { async fn start(&mut self) { info!("Starting component {}.", short_type_name::()); - self.run() - .await - .unwrap_or_else(|e| panic!("Failed to start ConsensusManager component: {e:?}")) + self.run().await; } } From d8ccee05a0f01f5e72e28e6aaa31363932b046ec Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:32:31 +0300 Subject: [PATCH 084/313] apollo_protobuf: rename protobuf::Vote.block_hash to proposal_commitment (#9435) --- crates/apollo_protobuf/src/converters/consensus.rs | 6 +++--- .../src/proto/p2p/proto/consensus/consensus.proto | 2 +- crates/apollo_protobuf/src/protobuf/protoc_output.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/apollo_protobuf/src/converters/consensus.rs b/crates/apollo_protobuf/src/converters/consensus.rs index 0133997e6a4..e9d6f4cca72 100644 --- a/crates/apollo_protobuf/src/converters/consensus.rs +++ b/crates/apollo_protobuf/src/converters/consensus.rs @@ -74,8 +74,8 @@ impl TryFrom for Vote { let height = value.height; let round = value.round; let proposal_commitment: Option = value - .block_hash - .map(|block_hash| block_hash.try_into()) + .proposal_commitment + .map(|proposal_commitment| proposal_commitment.try_into()) .transpose()? .map(ProposalCommitment); let voter = value.voter.ok_or(missing("voter"))?.try_into()?; @@ -95,7 +95,7 @@ impl From for protobuf::Vote { vote_type: i32::from(vote_type), height: value.height, round: value.round, - block_hash: value.proposal_commitment.map(|hash| hash.0.into()), + proposal_commitment: value.proposal_commitment.map(|commitment| commitment.0.into()), voter: Some(value.voter.into()), } } diff --git a/crates/apollo_protobuf/src/proto/p2p/proto/consensus/consensus.proto b/crates/apollo_protobuf/src/proto/p2p/proto/consensus/consensus.proto index 6e7a55b4e97..467ba4948cb 100644 --- a/crates/apollo_protobuf/src/proto/p2p/proto/consensus/consensus.proto +++ b/crates/apollo_protobuf/src/proto/p2p/proto/consensus/consensus.proto @@ -29,7 +29,7 @@ message Vote { uint64 height = 3; uint32 round = 4; // This is optional since a vote can be NIL. - optional Hash block_hash = 5; + optional Hash proposal_commitment = 5; Address voter = 6; } diff --git a/crates/apollo_protobuf/src/protobuf/protoc_output.rs b/crates/apollo_protobuf/src/protobuf/protoc_output.rs index 1694a0a9680..9351a5104ff 100644 --- a/crates/apollo_protobuf/src/protobuf/protoc_output.rs +++ b/crates/apollo_protobuf/src/protobuf/protoc_output.rs @@ -368,7 +368,7 @@ pub struct Vote { pub round: u32, /// This is optional since a vote can be NIL. #[prost(message, optional, tag = "5")] - pub block_hash: ::core::option::Option, + pub proposal_commitment: ::core::option::Option, #[prost(message, optional, tag = "6")] pub voter: ::core::option::Option
, } From e2a24d39b0368a457672ef10c9b3e35f5d38cafd Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:28:48 +0300 Subject: [PATCH 085/313] apollo_config_manager: remove logging of request handling (#9641) --- crates/apollo_config_manager/src/config_manager.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/apollo_config_manager/src/config_manager.rs b/crates/apollo_config_manager/src/config_manager.rs index d5344eac543..1752b5419c8 100644 --- a/crates/apollo_config_manager/src/config_manager.rs +++ b/crates/apollo_config_manager/src/config_manager.rs @@ -6,7 +6,7 @@ use apollo_infra::component_definitions::{ComponentRequestHandler, ComponentStar use apollo_mempool_config::config::MempoolDynamicConfig; use apollo_node_config::node_config::NodeDynamicConfig; use async_trait::async_trait; -use tracing::{info, instrument}; +use tracing::info; #[cfg(test)] #[path = "config_manager_tests.rs"] @@ -45,7 +45,6 @@ impl ConfigManager { #[async_trait] impl ComponentRequestHandler for ConfigManager { - #[instrument(skip(self), ret)] async fn handle_request(&mut self, request: ConfigManagerRequest) -> ConfigManagerResponse { match request { // TODO(Nadin/Tsabary): consider using a macro to generate the responses for each type From 869bb86e46923216c43d18cdc01f92a85f61b741 Mon Sep 17 00:00:00 2001 From: Meshi Peled <141231558+meship-starkware@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:29:09 +0300 Subject: [PATCH 086/313] starknet_os: fix compress hint (#9663) --- .../hint_implementation/stateless_compression/implementation.rs | 2 +- crates/starknet_os/src/hints/vars.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs index ddc71b922b0..7c1e9b742e5 100644 --- a/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs +++ b/crates/starknet_os/src/hints/hint_implementation/stateless_compression/implementation.rs @@ -45,7 +45,7 @@ pub(crate) fn compression_hint( let data_size = (data_end - data_start)?; let compressed_dst = - get_ptr_from_var_name(Ids::CompressedEnd.into(), vm, ids_data, ap_tracking)?; + get_ptr_from_var_name(Ids::CompressedDst.into(), vm, ids_data, ap_tracking)?; let data = vm.get_integer_range(data_start, data_size)?.into_iter().map(|f| *f).collect::>(); let compress_result = diff --git a/crates/starknet_os/src/hints/vars.rs b/crates/starknet_os/src/hints/vars.rs index c5dc907b231..43cac45a399 100644 --- a/crates/starknet_os/src/hints/vars.rs +++ b/crates/starknet_os/src/hints/vars.rs @@ -147,6 +147,7 @@ define_string_enum! { (CompiledClassFact), (CompiledClassFacts), (CompiledClassHash), + (CompressedDst), (CompressedEnd), (CompressedStart), (CompressStateUpdates), From 5dd37f548d8842ae96d3bd3d4ca216a1cd16ffdb Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Tue, 21 Oct 2025 09:45:23 +0300 Subject: [PATCH 087/313] apollo_config: generic comma-separated deserializer (#9643) --- Cargo.lock | 2 - crates/apollo_config/Cargo.toml | 2 - crates/apollo_config/src/converters.rs | 48 +++++++------------ .../src/config.rs | 4 +- crates/apollo_gateway_config/src/config.rs | 4 +- crates/apollo_network/src/lib.rs | 36 ++------------ crates/starknet_api/src/core.rs | 10 ++++ 7 files changed, 35 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e46a932e217..03cadef4b72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1079,8 +1079,6 @@ dependencies = [ "lazy_static", "serde", "serde_json", - "starknet-types-core", - "starknet_api", "strum_macros 0.25.3", "tempfile", "thiserror 1.0.69", diff --git a/crates/apollo_config/Cargo.toml b/crates/apollo_config/Cargo.toml index 9c24efd715e..2471cd4846c 100644 --- a/crates/apollo_config/Cargo.toml +++ b/crates/apollo_config/Cargo.toml @@ -14,8 +14,6 @@ const_format.workspace = true itertools.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } -starknet-types-core.workspace = true -starknet_api.workspace = true strum_macros.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/apollo_config/src/converters.rs b/crates/apollo_config/src/converters.rs index e5da6500624..ed2e213256e 100644 --- a/crates/apollo_config/src/converters.rs +++ b/crates/apollo_config/src/converters.rs @@ -31,8 +31,6 @@ use std::time::Duration; use serde::de::Error; use serde::{Deserialize, Deserializer, Serialize}; -use starknet_api::core::ContractAddress; -use starknet_types_core::felt::Felt; use url::Url; /// Deserializes milliseconds to duration object. @@ -264,7 +262,7 @@ where T: FromStr, T::Err: std::fmt::Display, { - let raw: String = ::deserialize(de)?; + let raw = String::deserialize(de)?; if raw.trim().is_empty() { return Ok(Vec::new()); @@ -275,38 +273,28 @@ where .collect() } -// TODO(Asmaa): refactor this to `deserialize_comma_separated_str` where -// T: TryFrom<&str>, to support deserializing comma-separated lists of any type. -/// Deserializes an optional comma-separated list of contract addresses into -/// `Option>`. An empty string is invalid if the `#is_none` flag is false. -pub fn deserialize_optional_contract_addresses<'de, D>( - de: D, -) -> Result>, D::Error> +/// Deserializes an optional comma-separated list of values implementing `FromStr` into +/// `Option>`. Returns `None` for empty or missing strings. +pub fn deserialize_comma_separated_str<'de, D, T>(de: D) -> Result>, D::Error> where D: Deserializer<'de>, + T: FromStr, + ::Err: std::fmt::Display, { - let raw: String = match Option::::deserialize(de)? { - Some(addresses) => addresses, - None => return Ok(None), - }; - - if raw.is_empty() { - return Err(D::Error::custom( - "Empty string is not a valid input for contract addresses. The config field is marked \ - as not none.", - )); + let raw = String::deserialize(de).unwrap_or_default(); + if raw.trim().is_empty() { + return Ok(None); } - let mut result = Vec::new(); - for addresses_str in raw.split(',') { - let felt = Felt::from_str(addresses_str).map_err(|err| { - D::Error::custom(format!("Failed to parse Felt from '{addresses_str}': {err}")) - })?; - let addr = ContractAddress::try_from(felt).map_err(|err| { - D::Error::custom(format!("Invalid contract address '{addresses_str}': {err}")) - })?; - result.push(addr); + let mut output: Vec = Vec::new(); + for part in raw.split(',').filter(|s| !s.is_empty()) { + let value = T::from_str(part) + .map_err(|e| D::Error::custom(format!("Invalid value '{part}': {e}")))?; + output.push(value); } - Ok(Some(result)) + if output.is_empty() { + return Ok(None); + } + Ok(Some(output)) } diff --git a/crates/apollo_consensus_orchestrator_config/src/config.rs b/crates/apollo_consensus_orchestrator_config/src/config.rs index 7ec971327c7..b95dfa09eab 100644 --- a/crates/apollo_consensus_orchestrator_config/src/config.rs +++ b/crates/apollo_consensus_orchestrator_config/src/config.rs @@ -3,8 +3,8 @@ use std::fmt::Debug; use std::time::Duration; use apollo_config::converters::{ + deserialize_comma_separated_str, deserialize_milliseconds_to_duration, - deserialize_optional_contract_addresses, deserialize_seconds_to_duration, }; use apollo_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; @@ -96,7 +96,7 @@ pub struct ContextConfig { pub num_validators: u64, /// Optional explicit set of validator IDs (contract addresses) to use. /// If provided, this overrides `num_validators`. - #[serde(default, deserialize_with = "deserialize_optional_contract_addresses")] + #[serde(default, deserialize_with = "deserialize_comma_separated_str")] pub validator_ids: Option>, /// The chain id of the Starknet chain. pub chain_id: ChainId, diff --git a/crates/apollo_gateway_config/src/config.rs b/crates/apollo_gateway_config/src/config.rs index 1dec9f069c7..06c548c2ca4 100644 --- a/crates/apollo_gateway_config/src/config.rs +++ b/crates/apollo_gateway_config/src/config.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use apollo_config::converters::deserialize_optional_contract_addresses; +use apollo_config::converters::deserialize_comma_separated_str; use apollo_config::dumping::{ prepend_sub_config_name, ser_optional_param, @@ -25,7 +25,7 @@ pub struct GatewayConfig { pub stateful_tx_validator_config: StatefulTransactionValidatorConfig, pub chain_info: ChainInfo, pub block_declare: bool, - #[serde(default, deserialize_with = "deserialize_optional_contract_addresses")] + #[serde(default, deserialize_with = "deserialize_comma_separated_str")] pub authorized_declarer_accounts: Option>, } diff --git a/crates/apollo_network/src/lib.rs b/crates/apollo_network/src/lib.rs index 08b79067cda..7de4e7a6c90 100644 --- a/crates/apollo_network/src/lib.rs +++ b/crates/apollo_network/src/lib.rs @@ -19,10 +19,10 @@ mod test_utils; pub mod utils; use std::collections::{BTreeMap, HashSet}; -use std::str::FromStr; use std::time::Duration; use apollo_config::converters::{ + deserialize_comma_separated_str, deserialize_optional_vec_u8, deserialize_seconds_to_duration, serialize_optional_vec_u8, @@ -39,42 +39,12 @@ use discovery::DiscoveryConfig; use libp2p::swarm::dial_opts::DialOpts; use libp2p::Multiaddr; use peer_manager::PeerManagerConfig; -use serde::de::Error; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use starknet_api::core::ChainId; use validator::{Validate, ValidationError}; pub(crate) type Bytes = Vec; -// TODO(AndrewL): Fix this -/// This function considers `""` to be `None` and -/// `"multiaddr1,multiaddr2"` to be `Some(vec![multiaddr1, multiaddr2])`. -/// It was purposefully designed this way to be compatible with the old config where only one -/// bootstrap peer was supported. Hence there is no way to express an empty vector in the config. -fn deserialize_multi_addrs<'de, D>(de: D) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - let raw_str: String = Deserialize::deserialize(de).unwrap_or_default(); - if raw_str.is_empty() { - return Ok(None); - } - - let mut vector = Vec::new(); - for i in raw_str.split(',').filter(|s| !s.is_empty()) { - let value = Multiaddr::from_str(i).map_err(|_| { - D::Error::custom(format!("Couldn't deserialize vector. Failed to parse value: {i}")) - })?; - vector.push(value); - } - - if vector.is_empty() { - return Ok(None); - } - - Ok(Some(vector)) -} - // TODO(Tsabary): move to the config converter module. pub fn serialize_multi_addrs(multi_addrs: &Option>) -> String { match multi_addrs { @@ -95,7 +65,7 @@ pub struct NetworkConfig { pub session_timeout: Duration, #[serde(deserialize_with = "deserialize_seconds_to_duration")] pub idle_connection_timeout: Duration, - #[serde(deserialize_with = "deserialize_multi_addrs")] + #[serde(deserialize_with = "deserialize_comma_separated_str")] #[validate(custom(function = "validate_bootstrap_peer_multiaddr_list"))] pub bootstrap_peer_multiaddr: Option>, #[validate(custom = "validate_vec_u256")] diff --git a/crates/starknet_api/src/core.rs b/crates/starknet_api/src/core.rs index 79cd461d423..9e216775067 100644 --- a/crates/starknet_api/src/core.rs +++ b/crates/starknet_api/src/core.rs @@ -3,6 +3,7 @@ mod core_test; use std::fmt::Debug; +use std::str::FromStr; use std::sync::LazyLock; use num_traits::ToPrimitive; @@ -154,6 +155,15 @@ impl From for ContractAddress { impl_from_through_intermediate!(u128, ContractAddress, u8, u16, u32, u64); +impl FromStr for ContractAddress { + type Err = StarknetApiError; + fn from_str(s: &str) -> Result { + let felt = Felt::from_str(s) + .map_err(|e| StarknetApiError::OutOfRange { string: format!("{e}") })?; + Ok(ContractAddress(PatriciaKey::try_from(felt)?)) + } +} + /// The maximal size of storage var. pub const MAX_STORAGE_ITEM_SIZE: u16 = 256; /// The prefix used in the calculation of a contract address. From 912efc99a38c01713c57c99c3a787ce197ed17a4 Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:10:56 +0300 Subject: [PATCH 088/313] apollo_config: add serialize_optional_comma_separated fn (#9646) --- Cargo.lock | 1 - crates/apollo_config/src/converters.rs | 12 ++++++++++ .../src/config.rs | 5 ++-- crates/apollo_deployments/Cargo.toml | 1 - .../apollo_deployments/src/config_override.rs | 23 +++++++++---------- crates/apollo_gateway_config/src/config.rs | 9 ++++---- crates/apollo_network/src/lib.rs | 19 ++------------- 7 files changed, 32 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03cadef4b72..9d971d4524d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1333,7 +1333,6 @@ dependencies = [ "apollo_infra", "apollo_infra_utils", "apollo_monitoring_endpoint_config", - "apollo_network", "apollo_node", "apollo_node_config", "indexmap 2.11.0", diff --git a/crates/apollo_config/src/converters.rs b/crates/apollo_config/src/converters.rs index ed2e213256e..687b2fada32 100644 --- a/crates/apollo_config/src/converters.rs +++ b/crates/apollo_config/src/converters.rs @@ -273,6 +273,18 @@ where .collect() } +/// Serializes an optional list into a comma-separated string. +/// Returns `None` if the input is `None`. +pub fn serialize_optional_comma_separated(list: &Option>) -> Option +where + T: ToString, +{ + match list { + None => None, + Some(list) => Some(list.iter().map(|item| item.to_string()).collect::>().join(",")), + } +} + /// Deserializes an optional comma-separated list of values implementing `FromStr` into /// `Option>`. Returns `None` for empty or missing strings. pub fn deserialize_comma_separated_str<'de, D, T>(de: D) -> Result>, D::Error> diff --git a/crates/apollo_consensus_orchestrator_config/src/config.rs b/crates/apollo_consensus_orchestrator_config/src/config.rs index b95dfa09eab..21f304bed0d 100644 --- a/crates/apollo_consensus_orchestrator_config/src/config.rs +++ b/crates/apollo_consensus_orchestrator_config/src/config.rs @@ -6,6 +6,7 @@ use apollo_config::converters::{ deserialize_comma_separated_str, deserialize_milliseconds_to_duration, deserialize_seconds_to_duration, + serialize_optional_comma_separated, }; use apollo_config::dumping::{ser_optional_param, ser_param, SerializeConfig}; use apollo_config::{ParamPath, ParamPrivacyInput, SerializedParam}; @@ -253,9 +254,7 @@ impl SerializeConfig for ContextConfig { ParamPrivacyInput::Public, )); dump.extend(ser_optional_param( - &self.validator_ids.as_ref().map(|accounts| { - accounts.iter().map(|addr| addr.0.to_string()).collect::>().join(",") - }), + &serialize_optional_comma_separated(&self.validator_ids), "".to_string(), "validator_ids", "Optional explicit set of validator IDs (comma separated).", diff --git a/crates/apollo_deployments/Cargo.toml b/crates/apollo_deployments/Cargo.toml index 37a2764b7d8..30365785c7a 100644 --- a/crates/apollo_deployments/Cargo.toml +++ b/crates/apollo_deployments/Cargo.toml @@ -15,7 +15,6 @@ apollo_http_server_config.workspace = true apollo_infra.workspace = true apollo_infra_utils.workspace = true apollo_monitoring_endpoint_config.workspace = true -apollo_network.workspace = true apollo_node_config.workspace = true indexmap.workspace = true libp2p.workspace = true diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index 95a6ac42f15..bb0a24b40d3 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -1,9 +1,9 @@ use std::path::Path; +use apollo_config::converters::serialize_optional_comma_separated; use apollo_infra_utils::dumping::serialize_to_file; #[cfg(test)] use apollo_infra_utils::dumping::serialize_to_file_test; -use apollo_network::serialize_multi_addrs; use libp2p::Multiaddr; use serde::{Serialize, Serializer}; use serde_json::to_value; @@ -185,7 +185,10 @@ impl DeploymentConfigOverride { #[derive(Clone, Debug, Serialize, PartialEq)] pub struct PeerToPeerBootstrapConfig { // Bootstrap peer address. - #[serde(rename = "bootstrap_peer_multiaddr", serialize_with = "serialize_multi_addrs_wrapper")] + #[serde( + rename = "bootstrap_peer_multiaddr", + serialize_with = "serialize_optional_comma_separated_wrapper" + )] bootstrap_peers_multiaddrs: Option>, #[serde(rename = "bootstrap_peer_multiaddr.#is_none")] bootstrap_peer_multiaddr_is_none: bool, @@ -244,23 +247,19 @@ impl InstanceConfigOverride { } } -// Wrapper function for the custom `serialize_multi_addrs` function, to be +// Wrapper function for the generic `serialize_optional_comma_separated` function, to be // compatible with serde's `serialize_with` attribute. It first applies the custom serialization // logic to convert the optional list into a `String`, and then serializes that string. -fn serialize_multi_addrs_wrapper( - optional_multi_addrs: &Option>, +fn serialize_optional_comma_separated_wrapper( + optional_list: &Option>, serializer: S, ) -> Result where S: Serializer, + T: ToString, { - match optional_multi_addrs { + match serialize_optional_comma_separated(optional_list) { None => serializer.serialize_none(), - Some(multi_addrs) => { - // Call the implemented custom serialization function - let s = serialize_multi_addrs(&Some(multi_addrs.clone())); - // Serialize the returned String - serializer.serialize_some(&s) - } + Some(s) => serializer.serialize_some(&s), } } diff --git a/crates/apollo_gateway_config/src/config.rs b/crates/apollo_gateway_config/src/config.rs index 06c548c2ca4..af4b57b881a 100644 --- a/crates/apollo_gateway_config/src/config.rs +++ b/crates/apollo_gateway_config/src/config.rs @@ -1,6 +1,9 @@ use std::collections::BTreeMap; -use apollo_config::converters::deserialize_comma_separated_str; +use apollo_config::converters::{ + deserialize_comma_separated_str, + serialize_optional_comma_separated, +}; use apollo_config::dumping::{ prepend_sub_config_name, ser_optional_param, @@ -47,9 +50,7 @@ impl SerializeConfig for GatewayConfig { )); dump.extend(prepend_sub_config_name(self.chain_info.dump(), "chain_info")); dump.extend(ser_optional_param( - &self.authorized_declarer_accounts.as_ref().map(|accounts| { - accounts.iter().map(|addr| addr.0.to_string()).collect::>().join(",") - }), + &serialize_optional_comma_separated(&self.authorized_declarer_accounts), "".to_string(), "authorized_declarer_accounts", "Authorized declarer accounts. If set, only these accounts can declare new contracts. \ diff --git a/crates/apollo_network/src/lib.rs b/crates/apollo_network/src/lib.rs index 7de4e7a6c90..359c1f12b67 100644 --- a/crates/apollo_network/src/lib.rs +++ b/crates/apollo_network/src/lib.rs @@ -25,6 +25,7 @@ use apollo_config::converters::{ deserialize_comma_separated_str, deserialize_optional_vec_u8, deserialize_seconds_to_duration, + serialize_optional_comma_separated, serialize_optional_vec_u8, }; use apollo_config::dumping::{ @@ -45,18 +46,6 @@ use validator::{Validate, ValidationError}; pub(crate) type Bytes = Vec; -// TODO(Tsabary): move to the config converter module. -pub fn serialize_multi_addrs(multi_addrs: &Option>) -> String { - match multi_addrs { - None => "".to_owned(), - Some(multi_addrs) => multi_addrs - .iter() - .map(|multiaddr| multiaddr.to_string()) - .collect::>() - .join(","), - } -} - // TODO(Shahak): add peer manager config to the network config #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Validate)] pub struct NetworkConfig { @@ -123,11 +112,7 @@ impl SerializeConfig for NetworkConfig { // TODO(Tsabary): this is not the proper way to dump a config. Needs fixing, and // specifically, need to move the condition to be part of the serialization fn. config.extend(ser_optional_param( - &if self.bootstrap_peer_multiaddr.is_some(){ - Some(serialize_multi_addrs(&self.bootstrap_peer_multiaddr)) - } else { - None - }, + &serialize_optional_comma_separated(&self.bootstrap_peer_multiaddr), String::from(""), "bootstrap_peer_multiaddr", "The multiaddress of the peer node. It should include the peer's id. For more info: https://docs.libp2p.io/concepts/fundamentals/peers/", From da0daaec60c9761d8e96f2aa320c20e5ee9d2707 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Tue, 21 Oct 2025 14:33:55 +0300 Subject: [PATCH 089/313] apollo_l1_provider: inline scraper test util (#7616) (#9652) Will soon convert this test into an integration test, which has no access to test_utils, and to `FakeL1ProviderClient` in particular, so next we'll replace it with the mockall one, which requires asserting before initializing the scraper. Note: The reason why we'll convert the test to an integration test is to prevent multiple Anvil instances running at once, which isn't possible in unit tests which are parallelized. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- Cargo.lock | 1 - crates/apollo_l1_provider/Cargo.toml | 1 - .../src/l1_scraper_tests.rs | 43 ++++++------------- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d971d4524d..bf44c0f7803 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1728,7 +1728,6 @@ dependencies = [ "thiserror 1.0.69", "tokio", "tracing", - "url", ] [[package]] diff --git a/crates/apollo_l1_provider/Cargo.toml b/crates/apollo_l1_provider/Cargo.toml index 3ba6b6c1e8b..7a12a4f389b 100644 --- a/crates/apollo_l1_provider/Cargo.toml +++ b/crates/apollo_l1_provider/Cargo.toml @@ -33,7 +33,6 @@ starknet_api.workspace = true thiserror.workspace = true tokio.workspace = true tracing.workspace = true -url.workspace = true [dev-dependencies] alloy.workspace = true diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 1b1a3f72c7e..6595fa90943 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -15,11 +15,7 @@ use apollo_state_sync_types::state_sync_types::SyncBlock; use assert_matches::assert_matches; use indexmap::IndexSet; use itertools::Itertools; -use papyrus_base_layer::ethereum_base_layer_contract::{ - EthereumBaseLayerConfig, - EthereumBaseLayerContract, - Starknet, -}; +use papyrus_base_layer::ethereum_base_layer_contract::{EthereumBaseLayerContract, Starknet}; use papyrus_base_layer::test_utils::{ anvil_instance_from_url, ethereum_base_layer_config_for_anvil, @@ -38,7 +34,6 @@ use starknet_api::transaction::{ TransactionHasher, TransactionVersion, }; -use url::Url; use crate::bootstrapper::Bootstrapper; use crate::l1_provider::{L1Provider, L1ProviderBuilder}; @@ -75,21 +70,25 @@ fn receive_commit_block( l1_provider.commit_block(committed.iter().copied().collect(), [].into(), height).unwrap(); } -// TODO(Gilad): Replace EthereumBaseLayerContract with a mock that has a provider initialized with -// `with_recommended_fillers`, in order to be able to create txs from non-default users. -async fn scraper( - base_layer_config: EthereumBaseLayerConfig, - base_layer_url: Url, -) -> (L1Scraper, Arc) { +#[tokio::test] +// TODO(Gilad): extract setup stuff into test helpers once more tests are added and patterns emerge. +async fn txs_happy_flow() { + if !in_ci() { + return; + } + + // Setup. + let (base_layer_config, base_layer_url) = ethereum_base_layer_config_for_anvil(None); + let anvil = anvil_instance_from_url(&base_layer_url); let fake_client = Arc::new(FakeL1ProviderClient::default()); let base_layer = EthereumBaseLayerContract::new(base_layer_config, base_layer_url); let l1_scraper_config = L1ScraperConfig::default(); - let l1_start_block = fetch_start_block(&base_layer, &l1_scraper_config).await.unwrap(); + // Deploy a fresh Starknet contract on Anvil from the bytecode in the JSON file. Starknet::deploy(base_layer.contract.provider().clone()).await.unwrap(); - let scraper = L1Scraper::new( + let mut scraper = L1Scraper::new( l1_scraper_config, fake_client.clone(), base_layer, @@ -98,22 +97,6 @@ async fn scraper( ) .await .unwrap(); - - (scraper, fake_client) -} - -#[tokio::test] -// TODO(Gilad): extract setup stuff into test helpers once more tests are added and patterns emerge. -async fn txs_happy_flow() { - if !in_ci() { - return; - } - - let (base_layer_config, base_layer_url) = ethereum_base_layer_config_for_anvil(None); - let anvil = anvil_instance_from_url(&base_layer_url); - // Setup. - let (mut scraper, fake_client) = scraper(base_layer_config, base_layer_url).await; - // Test. // Scrape multiple events. let l2_contract_address = "0x12"; From 2b191e83369e89f978649a118c120ce551e17261 Mon Sep 17 00:00:00 2001 From: Meshi Peled <141231558+meship-starkware@users.noreply.github.com> Date: Tue, 21 Oct 2025 14:47:31 +0300 Subject: [PATCH 090/313] apollo_integration_tests: add migration to integration tets (#9386) --- .../apollo_class_manager/src/class_storage.rs | 4 +-- .../src/state_reader.rs | 26 ++++++++++++++----- .../tests/end_to_end_flow_test.rs | 1 + .../src/blockifier/transaction_executor.rs | 12 ++++++--- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/crates/apollo_class_manager/src/class_storage.rs b/crates/apollo_class_manager/src/class_storage.rs index c3832a9b2c1..5cb5c5ac872 100644 --- a/crates/apollo_class_manager/src/class_storage.rs +++ b/crates/apollo_class_manager/src/class_storage.rs @@ -473,7 +473,7 @@ impl ClassStorage for FsClassStorage { &mut self, class_id: ClassId, class: RawClass, - executable_class_hash: ExecutableClassHash, + executable_class_hash_v2: ExecutableClassHash, executable_class: RawExecutableClass, ) -> Result<(), Self::Error> { if self.contains_class(class_id)? { @@ -481,7 +481,7 @@ impl ClassStorage for FsClassStorage { } self.write_class_atomically(class_id, class, executable_class)?; - self.mark_class_id_as_existent(class_id, executable_class_hash)?; + self.mark_class_id_as_existent(class_id, executable_class_hash_v2)?; Ok(()) } diff --git a/crates/apollo_integration_tests/src/state_reader.rs b/crates/apollo_integration_tests/src/state_reader.rs index 7ee4c0a6aea..4fa0d4267a2 100644 --- a/crates/apollo_integration_tests/src/state_reader.rs +++ b/crates/apollo_integration_tests/src/state_reader.rs @@ -32,6 +32,7 @@ use starknet_api::block::{ FeeType, GasPricePerToken, }; +use starknet_api::contract_class::compiled_class_hash::HashVersion; use starknet_api::contract_class::{ContractClass, SierraVersion}; use starknet_api::core::{ClassHash, ContractAddress, Nonce, SequencerContractAddress}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; @@ -278,10 +279,13 @@ fn prepare_state_diff( // Setup the common test contracts that are used by default in all test invokes. // TODO(batcher): this does nothing until we actually start excuting stuff in the batcher. - state_diff_builder.set_contracts(default_test_contracts).declare().deploy(); + state_diff_builder.set_contracts(default_test_contracts).declare(&HashVersion::V2).deploy(); // Declare and deploy and the ERC20 contract, so that transfers from it can be made. - state_diff_builder.set_contracts(std::slice::from_ref(erc20_contract)).declare().deploy(); + state_diff_builder + .set_contracts(std::slice::from_ref(erc20_contract)) + .declare(&HashVersion::V2) + .deploy(); // TODO(deploy_account_support): once we have batcher with execution, replace with: // ``` @@ -425,7 +429,7 @@ impl<'a> ThinStateDiffBuilder<'a> { self } - fn declare(&mut self) -> &mut Self { + fn declare(&mut self, hash_version: &HashVersion) -> &mut Self { for contract in self.contracts { match contract.cairo_version() { CairoVersion::Cairo0 => { @@ -434,7 +438,10 @@ impl<'a> ThinStateDiffBuilder<'a> { // todo(rdr): including both Cairo1 and Native versions for now. Temporal solution // to avoid compilation errors when using the "cairo_native" feature _ => { - self.declared_classes.insert(contract.class_hash(), Default::default()); + self.declared_classes.insert( + contract.class_hash(), + contract.contract.get_compiled_class_hash(hash_version), + ); } } } @@ -475,7 +482,10 @@ impl<'a> ThinStateDiffBuilder<'a> { &mut self, deployed_accounts_defined_in_the_test: &'a [Contract], ) { - self.set_contracts(deployed_accounts_defined_in_the_test).declare().deploy().fund(); + self.set_contracts(deployed_accounts_defined_in_the_test) + .declare(&HashVersion::V2) + .deploy() + .fund(); // Set nonces as 1 in the state so that subsequent invokes can pass validation. self.nonces = self @@ -489,7 +499,11 @@ impl<'a> ThinStateDiffBuilder<'a> { &mut self, undeployed_accounts_defined_in_the_test: &'a [Contract], ) { - self.set_contracts(undeployed_accounts_defined_in_the_test).declare().fund(); + // Imitate the behavior of a class that was declared before the migration + // with casm v1 (poseidon) to trigger migration in the integration tests. + self.set_contracts(undeployed_accounts_defined_in_the_test) + .declare(&HashVersion::V1) + .fund(); } fn build(self) -> ThinStateDiff { diff --git a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs index 45759d86571..f647278716f 100644 --- a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs +++ b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs @@ -16,6 +16,7 @@ use crate::common::{end_to_end_flow, test_single_tx, TestScenario}; mod common; +// TODO(Meshi): Fail the test if no class have migrated. /// Number of threads is 3 = Num of sequencer + 1 for the test thread. #[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn test_end_to_end_flow() { diff --git a/crates/blockifier/src/blockifier/transaction_executor.rs b/crates/blockifier/src/blockifier/transaction_executor.rs index 7d383753228..3e8978b9573 100644 --- a/crates/blockifier/src/blockifier/transaction_executor.rs +++ b/crates/blockifier/src/blockifier/transaction_executor.rs @@ -252,10 +252,14 @@ pub(crate) fn finalize_block( let mut bouncer = bouncer; let class_hashes_to_migrate = mem::take(bouncer.get_mut_class_hashes_to_migrate()); - log::trace!( - "Class hashes to migrate (key = class_hash, value = (compiled_class_hash_v2, \ - compiled_class_hash_v1)): {class_hashes_to_migrate:#?}" - ); + #[cfg(any(test, feature = "testing"))] + if !class_hashes_to_migrate.is_empty() { + log::info!( + "Class hashes to migrate (key = class_hash, value = (compiled_class_hash_v2, \ + compiled_class_hash_v1)): {class_hashes_to_migrate:#?}" + ); + } + if !block_context.versioned_constants.enable_casm_hash_migration { assert!( class_hashes_to_migrate.is_empty(), From 43df3d297128cc9d44e527804dcf2ff8f1f7762c Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Tue, 21 Oct 2025 15:51:01 +0300 Subject: [PATCH 091/313] papyrus_base_layer: fix consuming messages on L2 (instead of L1 typo) (#9684) --- crates/apollo_l1_provider/src/lib.rs | 6 ++++-- crates/papyrus_base_layer/src/constants.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/apollo_l1_provider/src/lib.rs b/crates/apollo_l1_provider/src/lib.rs index a6fa5a40b02..b782baa9583 100644 --- a/crates/apollo_l1_provider/src/lib.rs +++ b/crates/apollo_l1_provider/src/lib.rs @@ -20,8 +20,9 @@ use apollo_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use apollo_l1_provider_types::SessionState; use papyrus_base_layer::constants::{ EventIdentifier, - CONSUMED_MESSAGE_TO_L1_EVENT_IDENTIFIER, + CONSUMED_MESSAGE_TO_L2_EVENT_IDENTIFIER, LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER, + MESSAGE_TO_L2_CANCELED_EVENT_IDENTIFIER, MESSAGE_TO_L2_CANCELLATION_STARTED_EVENT_IDENTIFIER, }; use serde::{Deserialize, Serialize}; @@ -205,6 +206,7 @@ pub const fn event_identifiers_to_track() -> &'static [EventIdentifier] { &[ LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER, MESSAGE_TO_L2_CANCELLATION_STARTED_EVENT_IDENTIFIER, - CONSUMED_MESSAGE_TO_L1_EVENT_IDENTIFIER, + MESSAGE_TO_L2_CANCELED_EVENT_IDENTIFIER, + CONSUMED_MESSAGE_TO_L2_EVENT_IDENTIFIER, ] } diff --git a/crates/papyrus_base_layer/src/constants.rs b/crates/papyrus_base_layer/src/constants.rs index f3551406bbe..274ea53eea0 100644 --- a/crates/papyrus_base_layer/src/constants.rs +++ b/crates/papyrus_base_layer/src/constants.rs @@ -5,7 +5,7 @@ use crate::ethereum_base_layer_contract::Starknet; pub type EventIdentifier = &'static str; pub const LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER: &str = Starknet::LogMessageToL2::SIGNATURE; -pub const CONSUMED_MESSAGE_TO_L1_EVENT_IDENTIFIER: &str = Starknet::ConsumedMessageToL1::SIGNATURE; +pub const CONSUMED_MESSAGE_TO_L2_EVENT_IDENTIFIER: &str = Starknet::ConsumedMessageToL2::SIGNATURE; pub const MESSAGE_TO_L2_CANCELLATION_STARTED_EVENT_IDENTIFIER: &str = Starknet::MessageToL2CancellationStarted::SIGNATURE; pub const MESSAGE_TO_L2_CANCELED_EVENT_IDENTIFIER: &str = Starknet::MessageToL2Canceled::SIGNATURE; From 118cf62af6db001cd294e4d3683e7638afbd90fc Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Tue, 21 Oct 2025 15:59:50 +0300 Subject: [PATCH 092/313] apollo_l1_provider: remove duplicated calculation in test (#7617) (#9653) * l1: inline scraper test util Will soon convert this test into an integration test, which has no access to test_utils, and to `FakeL1ProviderClient` in particular, so next we'll replace it with the mockall one, which requires asserting before initializing the scraper. Note: The reason why we'll convert the test to an integration test is to prevent multiple Anvil instances running at once, which isn't possible in unit tests which are parallelized. * l1: remove duplicated calculation in test --------- Co-authored-by: giladchase Co-authored-by: Gilad Chase --- crates/apollo_l1_provider/src/l1_scraper_tests.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 6595fa90943..119b72bbd01 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -161,9 +161,7 @@ async fn txs_happy_flow() { .calculate_transaction_hash(&scraper.config.chain_id, &EXPECTED_VERSION) .unwrap(); let tx = ExecutableL1HandlerTransaction { - tx_hash: expected_internal_l1_tx - .calculate_transaction_hash(&scraper.config.chain_id, &EXPECTED_VERSION) - .unwrap(), + tx_hash: tx_hash_first_tx, tx: expected_internal_l1_tx, paid_fee_on_l1: Fee(0), }; From 5f8fbb33dde43dc10cd7ada03cb9bd0f8682d128 Mon Sep 17 00:00:00 2001 From: Meshi Peled <141231558+meship-starkware@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:08:56 +0300 Subject: [PATCH 093/313] starknet_os: small refactors in the OS (#9680) --- .../cairo/starkware/starknet/core/os/naive_blake.cairo | 8 +++----- .../src/cairo/starkware/starknet/core/os/os.cairo | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/naive_blake.cairo b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/naive_blake.cairo index d78e95868c4..42108a29258 100644 --- a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/naive_blake.cairo +++ b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/naive_blake.cairo @@ -1,8 +1,8 @@ from starkware.cairo.common.alloc import alloc from starkware.cairo.common.cairo_blake2s.blake2s import blake_with_opcode -// Gets a felt that represent a 256-bit unsigned integer stored as an array of eight 32-bit unsigned integers -// represented in little-endian notation. Return the felt representation of the integer modulo prime. +// Gets a felt that represents a 256-bit unsigned integer stored as an array of eight 32-bit unsigned integers +// represented in little-endian notation. Returns the felt representation of the integer modulo prime. func felt_from_le_u32s(u32s: felt*) -> felt { let value = u32s[7] * 2 ** 224 + u32s[6] * 2 ** 192 + u32s[5] * 2 ** 160 + u32s[4] * 2 ** 128 + u32s[3] * 2 ** 96 + u32s[2] * 2 ** 64 + u32s[1] * 2 ** 32 + u32s[0]; @@ -61,11 +61,9 @@ func create_initial_state_for_blake2s() -> (initial_state: felt*) { // Encodes one felt252 into eight u32s represented in little-endian order. func naive_encode_felt252_to_u32s(packed_value: felt, unpacked_u32s: felt*) { %{ NaiveUnpackFelt252ToU32s %} - tempvar out = unpacked_u32s; - // TODO(Noa): Assert that the limbs represent a number in the range [0, PRIME-1]. // Assert that the limbs represent the number. - let actual_value = felt_from_le_u32s(u32s=out); + let actual_value = felt_from_le_u32s(u32s=unpacked_u32s); assert packed_value = actual_value; return (); diff --git a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/os.cairo b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/os.cairo index eb8373a7e28..c04f4aeb5ed 100644 --- a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/os.cairo +++ b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/os.cairo @@ -490,7 +490,7 @@ func migrate_classes_to_v2_casm_hash{ let (casm_hash_v1) = poseidon_compiled_class_hash(compiled_class, full_contract=TRUE); let (casm_hash_v2) = blake_compiled_class_hash(compiled_class, full_contract=TRUE); %{ vm_exit_scope() %} - // Verify the guessed v2 hash. + // Sanity check: verify the guessed v2 hash. assert compiled_class_fact.hash = casm_hash_v2; // Update the casm hash from v1 to v2. dict_update{dict_ptr=contract_class_changes}( From 215c0e7d8b25ac051c1e6a1d89a26e75c5618240 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:22:21 +0300 Subject: [PATCH 094/313] papyrus_node: Papyrus cleanup - apollo config README (#9650) --- crates/apollo_config/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/apollo_config/README.md b/crates/apollo_config/README.md index a5a0f8a97e2..97e08ce8511 100644 --- a/crates/apollo_config/README.md +++ b/crates/apollo_config/README.md @@ -1,8 +1,8 @@ -# papyrus-config +# apollo-config ## Description -papyrus-config is a flexible and powerful layered configuration system designed specifically for Papyrus, a Starknet node. This system allows you to easily manage configurations for your Papyrus node by leveraging various sources and providing additional helpful features. +apollo-config is a flexible and powerful layered configuration system designed specifically for Apollo, a Starknet node. This system allows you to easily manage configurations for your Apollo sequencer by leveraging various sources and providing additional helpful features. ## Configuration sources @@ -27,8 +27,8 @@ Supports multiple configuration sources in ascending order of overriding priorit Developer reference documentation is available at https://docs.rs/apollo_config/. The documentation on this site is updated periodically. -To view the most up-to-date documentation, enter the following command at the root directory of the `papyrus` project: +To view the most up-to-date documentation, enter the following command at the root directory of the project: ```shell cargo doc --open -p apollo_config -``` \ No newline at end of file +``` From 7ac05fa7a6332e78184a79ebc820de25536e5850 Mon Sep 17 00:00:00 2001 From: lev-starkware <155880815+lev-starkware@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:45:28 +0300 Subject: [PATCH 095/313] apollo_mempool: adding bechmark tests (#9436) --- Cargo.lock | 3 + crates/apollo_mempool/Cargo.toml | 12 ++ crates/apollo_mempool/benches/main.rs | 44 ++++ crates/apollo_mempool/benches/utils.rs | 278 +++++++++++++++++++++++++ 4 files changed, 337 insertions(+) create mode 100644 crates/apollo_mempool/benches/main.rs create mode 100644 crates/apollo_mempool/benches/utils.rs diff --git a/Cargo.lock b/Cargo.lock index c0e394d4c19..57a794f22c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1659,6 +1659,9 @@ dependencies = [ "apollo_time", "assert_matches", "async-trait", + "blockifier", + "blockifier_test_utils", + "criterion", "derive_more 0.99.18", "indexmap 2.9.0", "itertools 0.12.1", diff --git a/crates/apollo_mempool/Cargo.toml b/crates/apollo_mempool/Cargo.toml index 2fa327f3998..1110e35edb2 100644 --- a/crates/apollo_mempool/Cargo.toml +++ b/crates/apollo_mempool/Cargo.toml @@ -12,6 +12,8 @@ testing = [ "apollo_network/testing", "apollo_network_types/testing", "apollo_time/testing", + "blockifier/testing", + "blockifier_test_utils", "starknet_api/testing", ] @@ -27,6 +29,7 @@ apollo_metrics.workspace = true apollo_network_types.workspace = true apollo_time = { workspace = true } async-trait.workspace = true +blockifier_test_utils = { workspace = true, optional = true } derive_more.workspace = true indexmap.workspace = true rand.workspace = true @@ -45,6 +48,9 @@ apollo_network_types = { workspace = true, features = ["testing"] } apollo_test_utils.workspace = true apollo_time = { workspace = true, features = ["testing"] } assert_matches.workspace = true +blockifier = { workspace = true, features = ["mocks", "testing"] } +blockifier_test_utils.workspace = true +criterion = { workspace = true, features = ["async_tokio"] } itertools.workspace = true mempool_test_utils.workspace = true metrics.workspace = true @@ -55,3 +61,9 @@ rstest.workspace = true starknet-types-core.workspace = true starknet_api = { workspace = true, features = ["testing"] } tokio.workspace = true + +[[bench]] +harness = false +name = "apollo_mempool" +path = "benches/main.rs" +required-features = ["testing"] diff --git a/crates/apollo_mempool/benches/main.rs b/crates/apollo_mempool/benches/main.rs new file mode 100644 index 00000000000..431d12eeb5f --- /dev/null +++ b/crates/apollo_mempool/benches/main.rs @@ -0,0 +1,44 @@ +//! Benchmark suite for the Apollo mempool crate. +//! +//! This module provides tools to measure the performance of the mempool service under various +//! transaction loads and configurations. +//! +//! The main benchmark, `invoke_benchmark`, evaluates how efficiently the mempool processes randomly +//! generated invoke transactions across different scenarios. +//! +//! To run the benchmarks, use: `cargo bench --bench apollo_mempool`. +/// import the Mempool test utilities. +mod utils; + +use apollo_mempool::config::MempoolConfig; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use utils::{BenchTestSetup, BenchTestSetupConfig}; + +fn run_invoke_benchmark(criterion: &mut Criterion, config: &BenchTestSetupConfig) { + let test_setup = BenchTestSetup::new(config); + let id_param = format!("{} txs with chunk size {}", config.n_txs, config.chunk_size); + criterion.bench_with_input( + BenchmarkId::new("invoke", id_param), + &test_setup, + |bencher, test_setup| { + bencher + .to_async(tokio::runtime::Runtime::new().unwrap()) + .iter(|| test_setup.mempool_add_get_txs()); + }, + ); +} + +fn invoke_benchmarks(criterion: &mut Criterion) { + let configs = [BenchTestSetupConfig { + n_txs: 10000, + chunk_size: 100, + mempool_config: MempoolConfig::default(), + }]; + + for config in configs.iter() { + run_invoke_benchmark(criterion, config); + } +} + +criterion_group!(benches, invoke_benchmarks); +criterion_main!(benches); diff --git a/crates/apollo_mempool/benches/utils.rs b/crates/apollo_mempool/benches/utils.rs new file mode 100644 index 00000000000..eb6b18c1745 --- /dev/null +++ b/crates/apollo_mempool/benches/utils.rs @@ -0,0 +1,278 @@ +use std::sync::Arc; + +use apollo_infra::component_server::{ComponentServerStarter, LocalServerConfig}; +use apollo_infra::metrics::{LocalClientMetrics, LocalServerMetrics}; +use apollo_mempool::communication::{create_mempool, LocalMempoolServer}; +use apollo_mempool::config::MempoolConfig; +use apollo_mempool_p2p_types::communication::{ + MempoolP2pPropagatorClient, + MempoolP2pPropagatorClientResult, +}; +use apollo_mempool_types::communication::{ + AddTransactionArgsWrapper, + LocalMempoolClient, + SharedMempoolClient, +}; +use apollo_mempool_types::mempool_types::{AccountState, AddTransactionArgs}; +use apollo_metrics::metrics::{LabeledMetricHistogram, MetricCounter, MetricGauge, MetricScope}; +use apollo_network_types::network_types::BroadcastedMessageMetadata; +use async_trait::async_trait; +use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::contracts::FeatureContract; +use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; +use starknet_api::core::ContractAddress; +use starknet_api::rpc_transaction::{ + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, + RpcTransaction, +}; +use starknet_api::{nonce, tx_hash}; +use tokio::sync::mpsc; + +/// Minimal overhead P2P propagator for benchmarking +/// All methods return Ok(()) immediately without any processing +pub struct BenchMempoolP2pPropagator; + +#[async_trait] +impl MempoolP2pPropagatorClient for BenchMempoolP2pPropagator { + async fn add_transaction( + &self, + _transaction: InternalRpcTransaction, + ) -> MempoolP2pPropagatorClientResult<()> { + Ok(()) + } + + async fn continue_propagation( + &self, + _propagation_metadata: BroadcastedMessageMetadata, + ) -> MempoolP2pPropagatorClientResult<()> { + Ok(()) + } + + async fn broadcast_queued_transactions(&self) -> MempoolP2pPropagatorClientResult<()> { + Ok(()) + } +} + +// Dummy metrics for benchmarking (we don't need real metrics collection) +const BENCH_MSGS_RECEIVED: MetricCounter = MetricCounter::new( + MetricScope::Infra, + "bench_msgs_received", + "Benchmark messages received", + 0, // initial_value +); + +const BENCH_MSGS_PROCESSED: MetricCounter = MetricCounter::new( + MetricScope::Infra, + "bench_msgs_processed", + "Benchmark messages processed", + 0, // initial_value +); + +const BENCH_HIGH_PRIORITY_QUEUE_DEPTH: MetricGauge = MetricGauge::new( + MetricScope::Infra, + "bench_high_priority_queue_depth", + "Benchmark high priority queue depth", +); + +const BENCH_NORMAL_PRIORITY_QUEUE_DEPTH: MetricGauge = MetricGauge::new( + MetricScope::Infra, + "bench_normal_priority_queue_depth", + "Benchmark normal priority queue depth", +); + +// Label permutations for histograms +const BENCH_LABEL_PERMUTATIONS: &[&[(&str, &str)]] = + &[&[("request_type", "add_tx")], &[("request_type", "get_txs")]]; + +const BENCH_PROCESSING_TIMES: LabeledMetricHistogram = LabeledMetricHistogram::new( + MetricScope::Infra, + "bench_processing_times", + "Benchmark processing times", + BENCH_LABEL_PERMUTATIONS, +); + +const BENCH_QUEUEING_TIMES: LabeledMetricHistogram = LabeledMetricHistogram::new( + MetricScope::Infra, + "bench_queueing_times", + "Benchmark queueing times", + BENCH_LABEL_PERMUTATIONS, +); + +const BENCH_RESPONSE_TIMES: LabeledMetricHistogram = LabeledMetricHistogram::new( + MetricScope::Infra, + "bench_response_times", + "Benchmark response times", + BENCH_LABEL_PERMUTATIONS, +); + +// Static metrics instances for benchmark +const BENCH_LOCAL_SERVER_METRICS: LocalServerMetrics = LocalServerMetrics::new( + &BENCH_MSGS_RECEIVED, + &BENCH_MSGS_PROCESSED, + &BENCH_HIGH_PRIORITY_QUEUE_DEPTH, + &BENCH_NORMAL_PRIORITY_QUEUE_DEPTH, + &BENCH_PROCESSING_TIMES, + &BENCH_QUEUEING_TIMES, +); + +const BENCH_LOCAL_CLIENT_METRICS: LocalClientMetrics = + LocalClientMetrics::new(&BENCH_RESPONSE_TIMES); + +struct TransactionGenerator { + multi_tx_generator: MultiAccountTransactionGenerator, + sender_address: ContractAddress, +} + +impl TransactionGenerator { + fn new(cairo_version: CairoVersion) -> Self { + let mut multi_tx_generator = MultiAccountTransactionGenerator::new(); + let account_type = FeatureContract::AccountWithoutValidations(cairo_version); + multi_tx_generator.register_deployed_account(account_type); + let sender_address = multi_tx_generator.account_with_id(0).sender_address(); + Self { multi_tx_generator, sender_address } + } + + fn generate_invoke(&mut self, index: usize) -> AddTransactionArgs { + let RpcTransaction::Invoke(invoke_tx) = + self.multi_tx_generator.account_with_id_mut(0).generate_invoke_with_tip(0) + else { + panic!("Expected RpcTransaction::Invoke") + }; + + AddTransactionArgs { + tx: InternalRpcTransaction { + tx: InternalRpcTransactionWithoutTxHash::Invoke(invoke_tx), + tx_hash: tx_hash!(index + 100), // Use index to create a unique hash + }, + // Since generate_invoke_with_tip() creates first transaction with nonce 1 (first + // invoke after deploy), the AccountState must also have nonce 1 to initialize the + // mempool nonce management to 1. + account_state: AccountState { address: self.sender_address, nonce: nonce!(1) }, + } + } +} + +#[derive(Clone)] +pub struct BenchTestSetupConfig { + pub n_txs: usize, + pub mempool_config: MempoolConfig, + pub chunk_size: usize, // Number of "add_tx" requests per one "get_tx" request. +} + +pub struct BenchTestSetup { + config: BenchTestSetupConfig, + txs: Vec, +} + +/// Server-Client setup for realistic benchmarking +pub struct MempoolServerClientSetup { + pub client: SharedMempoolClient, + _server_handle: tokio::task::JoinHandle<()>, +} + +impl BenchTestSetup { + pub fn new(config: &BenchTestSetupConfig) -> Self { + let cairo_version = CairoVersion::Cairo1(RunnableCairo1::Casm); + let mut tx_generator = TransactionGenerator::new(cairo_version); + + let txs = (0..config.n_txs).map(|i| tx_generator.generate_invoke(i)).collect(); + + Self { config: config.clone(), txs } + } + + /// Creates a server-client setup for realistic benchmarking + /// This simulates how mempool is accessed in the real application + pub async fn create_server_client_setup(&self) -> MempoolServerClientSetup { + // Create server configuration + let server_config = LocalServerConfig::default(); + + // Create communication channels + let (tx, rx) = mpsc::channel(server_config.inbound_requests_channel_capacity); + + // Create minimal overhead P2P client for benchmark + let bench_p2p_client = Arc::new(BenchMempoolP2pPropagator); + + // Create the mempool component + let mempool_component = + create_mempool(self.config.mempool_config.clone(), bench_p2p_client); + + // Use static metrics for benchmark + let server_metrics = &BENCH_LOCAL_SERVER_METRICS; + let client_metrics = &BENCH_LOCAL_CLIENT_METRICS; + + // Create the server + let server = LocalMempoolServer::new(mempool_component, &server_config, rx, server_metrics); + + // Start the server in a background task + // Note: LocalComponentServer::start() will panic when it finishes processing + // all requests. This is the expected behavior and not an error. + let server_handle = tokio::spawn(async move { + let mut server = server; + let _ = server.start().await; // Expected panic when server finishes + }); + + // Create the client + let client = LocalMempoolClient::new(tx, client_metrics); + let shared_client: SharedMempoolClient = Arc::new(client); + + // Give the server a moment to fully start + tokio::task::yield_now().await; + + MempoolServerClientSetup { client: shared_client, _server_handle: server_handle } + } + + /// Task that continuously adds transactions to the mempool via client. + /// Simulates concurrent producers in a real system + async fn add_tx_task(client: SharedMempoolClient, txs: Vec) { + for tx in txs.into_iter() { + let wrapped_args = AddTransactionArgsWrapper { args: tx, p2p_message_metadata: None }; + + client + .add_tx(wrapped_args) + .await + .unwrap_or_else(|e| panic!("Failed to add tx to mempool: {e:?}")); + } + } + + /// Task that continuously retrieves transactions from the mempool via client. + /// Simulates concurrent consumers in a real system + async fn get_txs_task(client: SharedMempoolClient, n_txs: usize, chunk_size: usize) { + let mut txs_received = 0; + + while txs_received < n_txs { + let retrieved_txs = client + .get_txs(chunk_size) + .await + .unwrap_or_else(|e| panic!("Failed to get txs from mempool: {e:?}")); + + txs_received += retrieved_txs.len(); + + // If no txs retrieved, wait a bit for add_tx_task to add more + if retrieved_txs.is_empty() { + tokio::time::sleep(tokio::time::Duration::from_micros(100)).await; + } + } + } + + /// Concurrent benchmark using server-client architecture + /// This simulates realistic concurrent access patterns to the mempool + pub async fn mempool_add_get_txs(&self) { + // Create server-client setup for realistic benchmarking + let server_client_setup = self.create_server_client_setup().await; + let client = Arc::clone(&server_client_setup.client); + + // Create tasks for concurrent execution + let add_task = tokio::spawn(Self::add_tx_task(Arc::clone(&client), self.txs.clone())); + let get_task = tokio::spawn(Self::get_txs_task( + Arc::clone(&client), + self.config.n_txs, + self.config.chunk_size, + )); + + // Wait for both tasks to complete + // Using try_join! for better error propagation in benchmarks + tokio::try_join!(add_task, get_task) + .expect("One or both tasks failed during benchmark execution"); + } +} From 12854cae6a500552ec750396896708bc54ccb721 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Tue, 21 Oct 2025 17:25:17 +0300 Subject: [PATCH 096/313] apollo_mempool: log expired txs upon removal (#9640) --- crates/apollo_mempool/src/mempool.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index bf16b9fb019..514f1c1f787 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -638,13 +638,24 @@ impl Mempool { incoming_value >= escalation_qualified_value } + #[instrument(skip_all, parent = None)] + fn log_and_count_expired_txs(&self, expired_txs: &[TransactionReference]) { + if !expired_txs.is_empty() { + metric_count_expired_txs(expired_txs.len()); + info!( + "Removed expired transactions: {:?}", + expired_txs.iter().map(|tx| tx.tx_hash).collect::>() + ); + } + } + fn remove_expired_txs(&mut self) -> AddressToNonce { let removed_txs = self .tx_pool .remove_txs_older_than(self.config.dynamic_config.transaction_ttl, &self.state.staged); let queued_txs = self.tx_queue.remove_txs(&removed_txs); - metric_count_expired_txs(removed_txs.len()); + self.log_and_count_expired_txs(&removed_txs); self.update_state_metrics(); queued_txs .into_iter() @@ -671,7 +682,7 @@ impl Mempool { }); // Remove old transactions from the pool. - metric_count_expired_txs(old_txs.len()); + self.log_and_count_expired_txs(&old_txs); let account_nonce_updates: AddressToNonce = old_txs .into_iter() .map(|tx| { From 0c433e7193bcde9c281c8de75e0d82a8a7d594ea Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Tue, 21 Oct 2025 17:28:32 +0300 Subject: [PATCH 097/313] apollo_http_server: log GW error (#9672) --- crates/apollo_http_server/src/http_server.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/apollo_http_server/src/http_server.rs b/crates/apollo_http_server/src/http_server.rs index d30dd911521..30ae23035ed 100644 --- a/crates/apollo_http_server/src/http_server.rs +++ b/crates/apollo_http_server/src/http_server.rs @@ -27,7 +27,7 @@ use serde::de::Error; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::serde_utils::bytes_from_hex_str; use starknet_api::transaction::fields::ValidResourceBounds; -use tracing::{debug, info, instrument}; +use tracing::{debug, info, instrument, warn}; use crate::deprecated_gateway_transaction::DeprecatedGatewayTransactionV3; use crate::errors::{HttpServerError, HttpServerRunError}; @@ -239,7 +239,13 @@ fn record_added_transactions(add_tx_result: &HttpServerResult, re ); ADDED_TRANSACTIONS_SUCCESS.increment(1); } - Err(err) => increment_failure_metrics(err), + Err(err) => { + warn!( + error = %err, + "Failed to record transaction" + ); + increment_failure_metrics(err); + } } } From 14a474bdcf9824f67455e5faeae696382e0b5439 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Tue, 21 Oct 2025 17:47:30 +0300 Subject: [PATCH 098/313] papyrus_node: Papyrus cleanup - starknet client agent (#9651) --- crates/apollo_starknet_client/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/apollo_starknet_client/src/lib.rs b/crates/apollo_starknet_client/src/lib.rs index c2e67313075..d67dca5ebc4 100644 --- a/crates/apollo_starknet_client/src/lib.rs +++ b/crates/apollo_starknet_client/src/lib.rs @@ -103,7 +103,7 @@ impl StarknetClient { format!("{}; {}; {}", info.os_type(), info.version(), info.bitness()); let app_user_agent = format!( "{product_name}/{product_version} ({system_information})", - product_name = "papyrus", + product_name = "apollo", product_version = node_version, system_information = system_information ); From 632fb0e432a63241770ff1bbd34b312d2d786529 Mon Sep 17 00:00:00 2001 From: Noa Oved <104720318+noaov1@users.noreply.github.com> Date: Tue, 21 Oct 2025 18:10:12 +0300 Subject: [PATCH 099/313] starknet_os: validate that the selector in cairo0 call contract is different from __execute__ (#9679) --- .../core/os/execution/deprecated_execute_syscalls.cairo | 4 ++++ crates/apollo_starknet_os_program/src/program_hash.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/execution/deprecated_execute_syscalls.cairo b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/execution/deprecated_execute_syscalls.cairo index 70c0daadda7..7916033c07f 100644 --- a/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/execution/deprecated_execute_syscalls.cairo +++ b/crates/apollo_starknet_os_program/src/cairo/starkware/starknet/core/os/execution/deprecated_execute_syscalls.cairo @@ -9,6 +9,8 @@ from starkware.cairo.common.memcpy import memcpy from starkware.cairo.common.segments import relocate_segment from starkware.starknet.common.constants import ORIGIN_ADDRESS from starkware.starknet.common.new_syscalls import ExecutionInfo +from starkware.cairo.common.math import assert_not_equal +from starkware.starknet.core.os.constants import EXECUTE_ENTRY_POINT_SELECTOR from starkware.starknet.common.syscalls import ( CALL_CONTRACT_SELECTOR, DELEGATE_CALL_SELECTOR, @@ -530,6 +532,8 @@ func execute_deprecated_syscalls{ // entries before this point belong to the caller. assert [revert_log] = RevertLogEntry(selector=CHANGE_CONTRACT_ENTRY, value=caller_address); let revert_log = &revert_log[1]; + // It is forbidded to call the `__execute__` function. + assert_not_equal(call_contract_syscall.request.selector, EXECUTE_ENTRY_POINT_SELECTOR); execute_contract_call_syscall( block_context=block_context, contract_address=callee_address, diff --git a/crates/apollo_starknet_os_program/src/program_hash.json b/crates/apollo_starknet_os_program/src/program_hash.json index 9190428b819..25c49182363 100644 --- a/crates/apollo_starknet_os_program/src/program_hash.json +++ b/crates/apollo_starknet_os_program/src/program_hash.json @@ -1,5 +1,5 @@ { - "os": "0xe4be3f413aec9b9f867ef2f5bf29e92d4c2849487c96317a4fb0e3eb38db13", + "os": "0x1c8437ab86fa4d9154bacb3fdbf3e5d7a63dba228748dd7d71f1d4986c2dc18", "aggregator": "0x78b933fe424c0c000b1da7f414cfb6362af87b694b9dd7a6a42aa500f3a6891", "aggregator_with_prefix": "0x3c2bf03c21bd2794125c481d7e224fbd8793ac675d24cdc9d476761d0d4ccab" } \ No newline at end of file From 9a9921918f65585b722d1cb66a237da5ca820144 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Tue, 21 Oct 2025 20:48:52 +0300 Subject: [PATCH 100/313] apollo_l1_provider: detach setup from scraper (#7618) (#9654) * apollo_l1_provider: remove duplicated calculation in test (#7617) * l1: inline scraper test util Will soon convert this test into an integration test, which has no access to test_utils, and to `FakeL1ProviderClient` in particular, so next we'll replace it with the mockall one, which requires asserting before initializing the scraper. Note: The reason why we'll convert the test to an integration test is to prevent multiple Anvil instances running at once, which isn't possible in unit tests which are parallelized. * l1: remove duplicated calculation in test --------- Co-authored-by: Gilad Chase * apollo_l1_provider: detach setup from scraper (#7618) Scraper initialization will soon be pushed down once we add `mockall` l1 provider client. Note that the chain_id is identical to the one used when initializing the scraper. Co-authored-by: Gilad Chase --------- Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/l1_scraper_tests.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 119b72bbd01..997c044ec2d 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -91,7 +91,7 @@ async fn txs_happy_flow() { let mut scraper = L1Scraper::new( l1_scraper_config, fake_client.clone(), - base_layer, + base_layer.clone(), event_identifiers_to_track(), l1_start_block, ) @@ -102,18 +102,18 @@ async fn txs_happy_flow() { let l2_contract_address = "0x12"; let l2_entry_point = "0x34"; - let message_to_l2_0 = scraper.base_layer.contract.sendMessageToL2( + let message_to_l2_0 = base_layer.contract.sendMessageToL2( l2_contract_address.parse().unwrap(), l2_entry_point.parse().unwrap(), vec![U256::from(1_u8), U256::from(2_u8)], ); - let message_to_l2_1 = scraper.base_layer.contract.sendMessageToL2( + let message_to_l2_1 = base_layer.contract.sendMessageToL2( l2_contract_address.parse().unwrap(), l2_entry_point.parse().unwrap(), vec![U256::from(3_u8), U256::from(4_u8)], ); let nonce_of_message_to_l2_0 = U256::from(0_u8); - let request_cancel_message_0 = scraper.base_layer.contract.startL1ToL2MessageCancellation( + let request_cancel_message_0 = base_layer.contract.startL1ToL2MessageCancellation( l2_contract_address.parse().unwrap(), l2_entry_point.parse().unwrap(), vec![U256::from(1_u8), U256::from(2_u8)], @@ -125,8 +125,7 @@ async fn txs_happy_flow() { for msg in &[message_to_l2_0, message_to_l2_1] { let receipt = msg.send().await.unwrap().get_receipt().await.unwrap(); block_timestamps.push( - scraper - .base_layer + base_layer .get_block_header(receipt.block_number.unwrap()) .await .unwrap() @@ -137,8 +136,7 @@ async fn txs_happy_flow() { let cancel_receipt = request_cancel_message_0.send().await.unwrap().get_receipt().await.unwrap(); - let cancel_timestamp = scraper - .base_layer + let cancel_timestamp = base_layer .get_block_header(cancel_receipt.block_number.unwrap()) .await .unwrap() @@ -157,8 +155,9 @@ async fn txs_happy_flow() { vec![default_anvil_l1_account_address, StarkHash::ONE, StarkHash::from(2)].into(), ), }; + let default_chain_id = L1ScraperConfig::default().chain_id; let tx_hash_first_tx = expected_internal_l1_tx - .calculate_transaction_hash(&scraper.config.chain_id, &EXPECTED_VERSION) + .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) .unwrap(); let tx = ExecutableL1HandlerTransaction { tx_hash: tx_hash_first_tx, @@ -181,7 +180,7 @@ async fn txs_happy_flow() { let second_expected_log = Event::L1HandlerTransaction { l1_handler_tx: ExecutableL1HandlerTransaction { tx_hash: expected_internal_l1_tx_2 - .calculate_transaction_hash(&scraper.config.chain_id, &EXPECTED_VERSION) + .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) .unwrap(), tx: expected_internal_l1_tx_2, ..tx From 9d2eabbadc1edd947fc1eb6808e7a9e474c6fddb Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Tue, 21 Oct 2025 21:10:01 +0300 Subject: [PATCH 101/313] apollo_l1_provider: use identical const in test (#7619) (#9655) * apollo_l1_provider: remove duplicated calculation in test (#7617) * l1: inline scraper test util Will soon convert this test into an integration test, which has no access to test_utils, and to `FakeL1ProviderClient` in particular, so next we'll replace it with the mockall one, which requires asserting before initializing the scraper. Note: The reason why we'll convert the test to an integration test is to prevent multiple Anvil instances running at once, which isn't possible in unit tests which are parallelized. * l1: remove duplicated calculation in test --------- Co-authored-by: Gilad Chase * apollo_l1_provider: detach setup from scraper (#7618) Scraper initialization will soon be pushed down once we add `mockall` l1 provider client. Note that the chain_id is identical to the one used when initializing the scraper. Co-authored-by: Gilad Chase * apollo_l1_provider: use identical const in test (#7619) Co-authored-by: Gilad Chase --------- Co-authored-by: giladchase Co-authored-by: Gilad Chase --- crates/apollo_l1_provider/src/l1_scraper_tests.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 997c044ec2d..57fc7d7ae61 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -19,6 +19,7 @@ use papyrus_base_layer::ethereum_base_layer_contract::{EthereumBaseLayerContract use papyrus_base_layer::test_utils::{ anvil_instance_from_url, ethereum_base_layer_config_for_anvil, + DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, }; use papyrus_base_layer::{BaseLayerContract, L1BlockHash, L1BlockReference, MockBaseLayerContract}; use rstest::{fixture, rstest}; @@ -79,7 +80,7 @@ async fn txs_happy_flow() { // Setup. let (base_layer_config, base_layer_url) = ethereum_base_layer_config_for_anvil(None); - let anvil = anvil_instance_from_url(&base_layer_url); + let _anvil_server_guard = anvil_instance_from_url(&base_layer_url); let fake_client = Arc::new(FakeL1ProviderClient::default()); let base_layer = EthereumBaseLayerContract::new(base_layer_config, base_layer_url); let l1_scraper_config = L1ScraperConfig::default(); @@ -144,15 +145,13 @@ async fn txs_happy_flow() { .timestamp; const EXPECTED_VERSION: TransactionVersion = TransactionVersion(StarkHash::ZERO); - let default_anvil_l1_account_address: StarkHash = - StarkHash::from_bytes_be_slice(anvil.addresses()[0].as_slice()); let expected_internal_l1_tx = L1HandlerTransaction { version: EXPECTED_VERSION, nonce: Nonce(StarkHash::ZERO), contract_address: contract_address!(l2_contract_address), entry_point_selector: EntryPointSelector(StarkHash::from_hex_unchecked(l2_entry_point)), calldata: Calldata( - vec![default_anvil_l1_account_address, StarkHash::ONE, StarkHash::from(2)].into(), + vec![DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, StarkHash::ONE, StarkHash::from(2)].into(), ), }; let default_chain_id = L1ScraperConfig::default().chain_id; @@ -173,7 +172,7 @@ async fn txs_happy_flow() { let expected_internal_l1_tx_2 = L1HandlerTransaction { nonce: Nonce(StarkHash::ONE), calldata: Calldata( - vec![default_anvil_l1_account_address, StarkHash::from(3), StarkHash::from(4)].into(), + vec![DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, StarkHash::from(3), StarkHash::from(4)].into(), ), ..tx.tx }; From 887740d58680e70cba77b24afb2c773f16583b1a Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 22 Oct 2025 09:54:39 +0300 Subject: [PATCH 102/313] apollo_l1_provider: extract to variable for consistency (#7620) (#9656) Co-authored-by: giladchase Co-authored-by: Gilad Chase --- crates/apollo_l1_provider/src/l1_scraper_tests.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 57fc7d7ae61..ca0b6642697 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -176,14 +176,15 @@ async fn txs_happy_flow() { ), ..tx.tx }; + let tx_2 = ExecutableL1HandlerTransaction { + tx_hash: expected_internal_l1_tx_2 + .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) + .unwrap(), + tx: expected_internal_l1_tx_2, + ..tx + }; let second_expected_log = Event::L1HandlerTransaction { - l1_handler_tx: ExecutableL1HandlerTransaction { - tx_hash: expected_internal_l1_tx_2 - .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) - .unwrap(), - tx: expected_internal_l1_tx_2, - ..tx - }, + l1_handler_tx: tx_2, block_timestamp: block_timestamps[1], scrape_timestamp: block_timestamps[1].0, }; From 522c58ce5c557d0e749feb30eb62c954838d18c9 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 22 Oct 2025 10:30:33 +0300 Subject: [PATCH 103/313] apollo_l1_provider: rename only (#7621) (#9657) The name is wrong, it's not internal, it's external. Internal will be renamed next, into "executable" by convention. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- crates/apollo_l1_provider/src/l1_scraper_tests.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index ca0b6642697..e357b496efa 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -145,7 +145,7 @@ async fn txs_happy_flow() { .timestamp; const EXPECTED_VERSION: TransactionVersion = TransactionVersion(StarkHash::ZERO); - let expected_internal_l1_tx = L1HandlerTransaction { + let expected_l1_handler_0 = L1HandlerTransaction { version: EXPECTED_VERSION, nonce: Nonce(StarkHash::ZERO), contract_address: contract_address!(l2_contract_address), @@ -155,12 +155,12 @@ async fn txs_happy_flow() { ), }; let default_chain_id = L1ScraperConfig::default().chain_id; - let tx_hash_first_tx = expected_internal_l1_tx + let tx_hash_first_tx = expected_l1_handler_0 .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) .unwrap(); let tx = ExecutableL1HandlerTransaction { tx_hash: tx_hash_first_tx, - tx: expected_internal_l1_tx, + tx: expected_l1_handler_0, paid_fee_on_l1: Fee(0), }; let first_expected_log = Event::L1HandlerTransaction { @@ -169,7 +169,7 @@ async fn txs_happy_flow() { scrape_timestamp: block_timestamps[0].0, }; - let expected_internal_l1_tx_2 = L1HandlerTransaction { + let expected_l1_handler_1 = L1HandlerTransaction { nonce: Nonce(StarkHash::ONE), calldata: Calldata( vec![DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, StarkHash::from(3), StarkHash::from(4)].into(), @@ -177,10 +177,10 @@ async fn txs_happy_flow() { ..tx.tx }; let tx_2 = ExecutableL1HandlerTransaction { - tx_hash: expected_internal_l1_tx_2 + tx_hash: expected_l1_handler_1 .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) .unwrap(), - tx: expected_internal_l1_tx_2, + tx: expected_l1_handler_1, ..tx }; let second_expected_log = Event::L1HandlerTransaction { From 1ffe37d2ddff9ccad9fc4063ad5bd4402d117524 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 22 Oct 2025 10:55:49 +0300 Subject: [PATCH 104/313] apollo_l1_provider: rename test variables (#7622) (#9658) Co-authored-by: giladchase Co-authored-by: Gilad Chase --- crates/apollo_l1_provider/src/l1_scraper_tests.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index e357b496efa..9aa081ae653 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -158,13 +158,13 @@ async fn txs_happy_flow() { let tx_hash_first_tx = expected_l1_handler_0 .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) .unwrap(); - let tx = ExecutableL1HandlerTransaction { + let expected_executable_l1_handler_0 = ExecutableL1HandlerTransaction { tx_hash: tx_hash_first_tx, tx: expected_l1_handler_0, paid_fee_on_l1: Fee(0), }; let first_expected_log = Event::L1HandlerTransaction { - l1_handler_tx: tx.clone(), + l1_handler_tx: expected_executable_l1_handler_0.clone(), block_timestamp: block_timestamps[0], scrape_timestamp: block_timestamps[0].0, }; @@ -174,17 +174,17 @@ async fn txs_happy_flow() { calldata: Calldata( vec![DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, StarkHash::from(3), StarkHash::from(4)].into(), ), - ..tx.tx + ..expected_executable_l1_handler_0.tx }; - let tx_2 = ExecutableL1HandlerTransaction { + let expected_executable_l1_handler_1 = ExecutableL1HandlerTransaction { tx_hash: expected_l1_handler_1 .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) .unwrap(), tx: expected_l1_handler_1, - ..tx + ..expected_executable_l1_handler_0 }; let second_expected_log = Event::L1HandlerTransaction { - l1_handler_tx: tx_2, + l1_handler_tx: expected_executable_l1_handler_1, block_timestamp: block_timestamps[1], scrape_timestamp: block_timestamps[1].0, }; From 5e553dc6e5772483cf98b9573e6f798a508ecdc1 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 22 Oct 2025 11:27:13 +0300 Subject: [PATCH 105/313] apollo_l1_provider: move scraper closer to usage in test (#7623) (#9659) Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/l1_scraper_tests.rs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 9aa081ae653..10313c08be7 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -81,24 +81,11 @@ async fn txs_happy_flow() { // Setup. let (base_layer_config, base_layer_url) = ethereum_base_layer_config_for_anvil(None); let _anvil_server_guard = anvil_instance_from_url(&base_layer_url); - let fake_client = Arc::new(FakeL1ProviderClient::default()); let base_layer = EthereumBaseLayerContract::new(base_layer_config, base_layer_url); - let l1_scraper_config = L1ScraperConfig::default(); - let l1_start_block = fetch_start_block(&base_layer, &l1_scraper_config).await.unwrap(); // Deploy a fresh Starknet contract on Anvil from the bytecode in the JSON file. Starknet::deploy(base_layer.contract.provider().clone()).await.unwrap(); - let mut scraper = L1Scraper::new( - l1_scraper_config, - fake_client.clone(), - base_layer.clone(), - event_identifiers_to_track(), - l1_start_block, - ) - .await - .unwrap(); - // Test. // Scrape multiple events. let l2_contract_address = "0x12"; let l2_entry_point = "0x34"; @@ -194,7 +181,24 @@ async fn txs_happy_flow() { cancellation_request_timestamp: cancel_timestamp, }; - // Assert. + let fake_client = Arc::new(FakeL1ProviderClient::default()); + let l1_scraper_config = L1ScraperConfig { + // Start scraping far enough back to capture all of the events created before. + startup_rewind_time_seconds: Duration::from_secs(100), + ..Default::default() + }; + let l1_start_block = fetch_start_block(&base_layer, &l1_scraper_config).await.unwrap(); + let mut scraper = L1Scraper::new( + l1_scraper_config, + fake_client.clone(), + base_layer.clone(), + event_identifiers_to_track(), + l1_start_block, + ) + .await + .unwrap(); + + // Test. scraper.send_events_to_l1_provider().await.unwrap(); fake_client.assert_add_events_received_with(&[ first_expected_log, From 5a1ad331bb58f52f465dd1fedc294847578955a2 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 22 Oct 2025 12:57:00 +0300 Subject: [PATCH 106/313] apollo_l1_provider: rename variable in scraper test (#7624) (#9660) * l1: move scraper closer to usage in test * l1: rename variable in scraper test --------- Co-authored-by: giladchase Co-authored-by: Gilad Chase --- crates/apollo_l1_provider/src/l1_scraper_tests.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 10313c08be7..53209ad6985 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -109,10 +109,10 @@ async fn txs_happy_flow() { ); // Send the transactions. - let mut block_timestamps: Vec = Vec::with_capacity(2); + let mut l1_handler_timestamps: Vec = Vec::with_capacity(2); for msg in &[message_to_l2_0, message_to_l2_1] { let receipt = msg.send().await.unwrap().get_receipt().await.unwrap(); - block_timestamps.push( + l1_handler_timestamps.push( base_layer .get_block_header(receipt.block_number.unwrap()) .await @@ -152,8 +152,8 @@ async fn txs_happy_flow() { }; let first_expected_log = Event::L1HandlerTransaction { l1_handler_tx: expected_executable_l1_handler_0.clone(), - block_timestamp: block_timestamps[0], - scrape_timestamp: block_timestamps[0].0, + block_timestamp: l1_handler_timestamps[0], + scrape_timestamp: l1_handler_timestamps[0].0, }; let expected_l1_handler_1 = L1HandlerTransaction { @@ -172,8 +172,8 @@ async fn txs_happy_flow() { }; let second_expected_log = Event::L1HandlerTransaction { l1_handler_tx: expected_executable_l1_handler_1, - block_timestamp: block_timestamps[1], - scrape_timestamp: block_timestamps[1].0, + block_timestamp: l1_handler_timestamps[1], + scrape_timestamp: l1_handler_timestamps[1].0, }; let expected_cancel_message = Event::TransactionCancellationStarted { From e4cc6995c49a0615faca541722bc719244c2cb59 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Wed, 22 Oct 2025 13:22:39 +0300 Subject: [PATCH 107/313] apollo_dashboard: lower window for avg block time to 1m (#9688) --- crates/apollo_dashboard/resources/dev_grafana.json | 8 ++++---- crates/apollo_dashboard/src/panels/consensus.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 7720977f09a..787aa28c6ab 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -4,10 +4,10 @@ "panels": [ { "title": "Average Block Time", - "description": "Average block time (10m window)", + "description": "Average block time (1m window)", "type": "timeseries", "exprs": [ - "1 / rate(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + "1 / rate(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1m])" ], "extra_params": { "unit": "s" @@ -106,10 +106,10 @@ }, { "title": "Average Block Time", - "description": "Average block time (10m window)", + "description": "Average block time (1m window)", "type": "timeseries", "exprs": [ - "1 / rate(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + "1 / rate(consensus_block_number{cluster=~\"$cluster\", namespace=~\"$namespace\"}[1m])" ], "extra_params": { "unit": "s" diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index c8be109e2a6..53ac6220881 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -116,8 +116,8 @@ fn get_panel_consensus_round_above_zero() -> Panel { pub(crate) fn get_panel_consensus_block_time_avg() -> Panel { Panel::new( "Average Block Time", - "Average block time (10m window)", - vec![format!("1 / rate({}[10m])", CONSENSUS_BLOCK_NUMBER.get_name_with_filter())], + "Average block time (1m window)", + vec![format!("1 / rate({}[1m])", CONSENSUS_BLOCK_NUMBER.get_name_with_filter())], PanelType::TimeSeries, ) .with_unit(Unit::Seconds) From 13378cefbb36372380c1a2e55be62c560c612a56 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 22 Oct 2025 13:37:51 +0300 Subject: [PATCH 108/313] apollo_l1_provider: switch from fake l1 provider client to mock (#7625) (#9661) Using `Sequence` to enforce order between the expectations. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/l1_scraper_tests.rs | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 53209ad6985..01d1f33d526 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -15,6 +15,8 @@ use apollo_state_sync_types::state_sync_types::SyncBlock; use assert_matches::assert_matches; use indexmap::IndexSet; use itertools::Itertools; +use mockall::predicate::eq; +use mockall::Sequence; use papyrus_base_layer::ethereum_base_layer_contract::{EthereumBaseLayerContract, Starknet}; use papyrus_base_layer::test_utils::{ anvil_instance_from_url, @@ -81,15 +83,15 @@ async fn txs_happy_flow() { // Setup. let (base_layer_config, base_layer_url) = ethereum_base_layer_config_for_anvil(None); let _anvil_server_guard = anvil_instance_from_url(&base_layer_url); + let mut l1_provider_client = MockL1ProviderClient::default(); let base_layer = EthereumBaseLayerContract::new(base_layer_config, base_layer_url); // Deploy a fresh Starknet contract on Anvil from the bytecode in the JSON file. Starknet::deploy(base_layer.contract.provider().clone()).await.unwrap(); - // Scrape multiple events. + // Send messages from L1 to L2. let l2_contract_address = "0x12"; let l2_entry_point = "0x34"; - let message_to_l2_0 = base_layer.contract.sendMessageToL2( l2_contract_address.parse().unwrap(), l2_entry_point.parse().unwrap(), @@ -108,7 +110,7 @@ async fn txs_happy_flow() { nonce_of_message_to_l2_0, ); - // Send the transactions. + // Send the transactions to Anvil, and record the timestamps of the blocks they are included in. let mut l1_handler_timestamps: Vec = Vec::with_capacity(2); for msg in &[message_to_l2_0, message_to_l2_1] { let receipt = msg.send().await.unwrap().get_receipt().await.unwrap(); @@ -181,7 +183,18 @@ async fn txs_happy_flow() { cancellation_request_timestamp: cancel_timestamp, }; - let fake_client = Arc::new(FakeL1ProviderClient::default()); + let mut sequence = Sequence::new(); + // Expect first call to return all the events defined further down. + l1_provider_client + .expect_add_events() + .once() + .in_sequence(&mut sequence) + .with(eq(vec![first_expected_log, second_expected_log, expected_cancel_message])) + .returning(|_| Ok(())); + + // Expect second call to return nothing, no events left to scrape. + l1_provider_client.expect_add_events().once().in_sequence(&mut sequence).returning(|_| Ok(())); + let l1_scraper_config = L1ScraperConfig { // Start scraping far enough back to capture all of the events created before. startup_rewind_time_seconds: Duration::from_secs(100), @@ -190,7 +203,7 @@ async fn txs_happy_flow() { let l1_start_block = fetch_start_block(&base_layer, &l1_scraper_config).await.unwrap(); let mut scraper = L1Scraper::new( l1_scraper_config, - fake_client.clone(), + Arc::new(l1_provider_client), base_layer.clone(), event_identifiers_to_track(), l1_start_block, @@ -200,15 +213,9 @@ async fn txs_happy_flow() { // Test. scraper.send_events_to_l1_provider().await.unwrap(); - fake_client.assert_add_events_received_with(&[ - first_expected_log, - second_expected_log, - expected_cancel_message, - ]); // Previous events had been scraped, should no longer appear. scraper.send_events_to_l1_provider().await.unwrap(); - fake_client.assert_add_events_received_with(&[]); } // TODO(Gilad): figure out how To setup anvil on a specific L1 block (through genesis.json?) and From 901031dced2717db37df0d24821e1ee9d2b8b6ba Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 22 Oct 2025 14:18:17 +0300 Subject: [PATCH 109/313] apollo_l1_provider: convert happy flow test into integration test (#7626) (#9662) MOVE only, no logic changes except making `send_events_to_l1_provider` pub. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/l1_scraper_tests.rs | 174 +----------------- .../tests/scraper_end_to_end.rs | 19 +- 2 files changed, 10 insertions(+), 183 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_scraper_tests.rs b/crates/apollo_l1_provider/src/l1_scraper_tests.rs index 01d1f33d526..22daed8af22 100644 --- a/crates/apollo_l1_provider/src/l1_scraper_tests.rs +++ b/crates/apollo_l1_provider/src/l1_scraper_tests.rs @@ -2,12 +2,11 @@ use std::collections::HashMap; use std::sync::{Arc, Mutex}; use std::time::Duration; -use alloy::primitives::U256; use apollo_batcher_types::batcher_types::GetHeightResponse; use apollo_batcher_types::communication::MockBatcherClient; use apollo_infra::trace_util::configure_tracing; use apollo_l1_provider_types::errors::L1ProviderError; -use apollo_l1_provider_types::{Event, L1ProviderClient, MockL1ProviderClient}; +use apollo_l1_provider_types::{L1ProviderClient, MockL1ProviderClient}; use apollo_l1_scraper_config::config::L1ScraperConfig; use apollo_state_sync_types::communication::MockStateSyncClient; use apollo_state_sync_types::errors::StateSyncError; @@ -15,32 +14,14 @@ use apollo_state_sync_types::state_sync_types::SyncBlock; use assert_matches::assert_matches; use indexmap::IndexSet; use itertools::Itertools; -use mockall::predicate::eq; -use mockall::Sequence; -use papyrus_base_layer::ethereum_base_layer_contract::{EthereumBaseLayerContract, Starknet}; -use papyrus_base_layer::test_utils::{ - anvil_instance_from_url, - ethereum_base_layer_config_for_anvil, - DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, -}; -use papyrus_base_layer::{BaseLayerContract, L1BlockHash, L1BlockReference, MockBaseLayerContract}; +use papyrus_base_layer::{L1BlockHash, L1BlockReference, MockBaseLayerContract}; use rstest::{fixture, rstest}; -use starknet_api::block::{BlockNumber, BlockTimestamp}; -use starknet_api::contract_address; -use starknet_api::core::{EntryPointSelector, Nonce}; -use starknet_api::executable_transaction::L1HandlerTransaction as ExecutableL1HandlerTransaction; -use starknet_api::hash::StarkHash; -use starknet_api::transaction::fields::{Calldata, Fee}; -use starknet_api::transaction::{ - L1HandlerTransaction, - TransactionHash, - TransactionHasher, - TransactionVersion, -}; +use starknet_api::block::BlockNumber; +use starknet_api::transaction::TransactionHash; use crate::bootstrapper::Bootstrapper; use crate::l1_provider::{L1Provider, L1ProviderBuilder}; -use crate::l1_scraper::{fetch_start_block, L1Scraper, L1ScraperError}; +use crate::l1_scraper::{L1Scraper, L1ScraperError}; use crate::test_utils::FakeL1ProviderClient; use crate::{event_identifiers_to_track, L1ProviderConfig}; @@ -73,151 +54,6 @@ fn receive_commit_block( l1_provider.commit_block(committed.iter().copied().collect(), [].into(), height).unwrap(); } -#[tokio::test] -// TODO(Gilad): extract setup stuff into test helpers once more tests are added and patterns emerge. -async fn txs_happy_flow() { - if !in_ci() { - return; - } - - // Setup. - let (base_layer_config, base_layer_url) = ethereum_base_layer_config_for_anvil(None); - let _anvil_server_guard = anvil_instance_from_url(&base_layer_url); - let mut l1_provider_client = MockL1ProviderClient::default(); - let base_layer = EthereumBaseLayerContract::new(base_layer_config, base_layer_url); - - // Deploy a fresh Starknet contract on Anvil from the bytecode in the JSON file. - Starknet::deploy(base_layer.contract.provider().clone()).await.unwrap(); - - // Send messages from L1 to L2. - let l2_contract_address = "0x12"; - let l2_entry_point = "0x34"; - let message_to_l2_0 = base_layer.contract.sendMessageToL2( - l2_contract_address.parse().unwrap(), - l2_entry_point.parse().unwrap(), - vec![U256::from(1_u8), U256::from(2_u8)], - ); - let message_to_l2_1 = base_layer.contract.sendMessageToL2( - l2_contract_address.parse().unwrap(), - l2_entry_point.parse().unwrap(), - vec![U256::from(3_u8), U256::from(4_u8)], - ); - let nonce_of_message_to_l2_0 = U256::from(0_u8); - let request_cancel_message_0 = base_layer.contract.startL1ToL2MessageCancellation( - l2_contract_address.parse().unwrap(), - l2_entry_point.parse().unwrap(), - vec![U256::from(1_u8), U256::from(2_u8)], - nonce_of_message_to_l2_0, - ); - - // Send the transactions to Anvil, and record the timestamps of the blocks they are included in. - let mut l1_handler_timestamps: Vec = Vec::with_capacity(2); - for msg in &[message_to_l2_0, message_to_l2_1] { - let receipt = msg.send().await.unwrap().get_receipt().await.unwrap(); - l1_handler_timestamps.push( - base_layer - .get_block_header(receipt.block_number.unwrap()) - .await - .unwrap() - .unwrap() - .timestamp, - ); - } - - let cancel_receipt = - request_cancel_message_0.send().await.unwrap().get_receipt().await.unwrap(); - let cancel_timestamp = base_layer - .get_block_header(cancel_receipt.block_number.unwrap()) - .await - .unwrap() - .unwrap() - .timestamp; - - const EXPECTED_VERSION: TransactionVersion = TransactionVersion(StarkHash::ZERO); - let expected_l1_handler_0 = L1HandlerTransaction { - version: EXPECTED_VERSION, - nonce: Nonce(StarkHash::ZERO), - contract_address: contract_address!(l2_contract_address), - entry_point_selector: EntryPointSelector(StarkHash::from_hex_unchecked(l2_entry_point)), - calldata: Calldata( - vec![DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, StarkHash::ONE, StarkHash::from(2)].into(), - ), - }; - let default_chain_id = L1ScraperConfig::default().chain_id; - let tx_hash_first_tx = expected_l1_handler_0 - .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) - .unwrap(); - let expected_executable_l1_handler_0 = ExecutableL1HandlerTransaction { - tx_hash: tx_hash_first_tx, - tx: expected_l1_handler_0, - paid_fee_on_l1: Fee(0), - }; - let first_expected_log = Event::L1HandlerTransaction { - l1_handler_tx: expected_executable_l1_handler_0.clone(), - block_timestamp: l1_handler_timestamps[0], - scrape_timestamp: l1_handler_timestamps[0].0, - }; - - let expected_l1_handler_1 = L1HandlerTransaction { - nonce: Nonce(StarkHash::ONE), - calldata: Calldata( - vec![DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, StarkHash::from(3), StarkHash::from(4)].into(), - ), - ..expected_executable_l1_handler_0.tx - }; - let expected_executable_l1_handler_1 = ExecutableL1HandlerTransaction { - tx_hash: expected_l1_handler_1 - .calculate_transaction_hash(&default_chain_id, &EXPECTED_VERSION) - .unwrap(), - tx: expected_l1_handler_1, - ..expected_executable_l1_handler_0 - }; - let second_expected_log = Event::L1HandlerTransaction { - l1_handler_tx: expected_executable_l1_handler_1, - block_timestamp: l1_handler_timestamps[1], - scrape_timestamp: l1_handler_timestamps[1].0, - }; - - let expected_cancel_message = Event::TransactionCancellationStarted { - tx_hash: tx_hash_first_tx, - cancellation_request_timestamp: cancel_timestamp, - }; - - let mut sequence = Sequence::new(); - // Expect first call to return all the events defined further down. - l1_provider_client - .expect_add_events() - .once() - .in_sequence(&mut sequence) - .with(eq(vec![first_expected_log, second_expected_log, expected_cancel_message])) - .returning(|_| Ok(())); - - // Expect second call to return nothing, no events left to scrape. - l1_provider_client.expect_add_events().once().in_sequence(&mut sequence).returning(|_| Ok(())); - - let l1_scraper_config = L1ScraperConfig { - // Start scraping far enough back to capture all of the events created before. - startup_rewind_time_seconds: Duration::from_secs(100), - ..Default::default() - }; - let l1_start_block = fetch_start_block(&base_layer, &l1_scraper_config).await.unwrap(); - let mut scraper = L1Scraper::new( - l1_scraper_config, - Arc::new(l1_provider_client), - base_layer.clone(), - event_identifiers_to_track(), - l1_start_block, - ) - .await - .unwrap(); - - // Test. - scraper.send_events_to_l1_provider().await.unwrap(); - - // Previous events had been scraped, should no longer appear. - scraper.send_events_to_l1_provider().await.unwrap(); -} - // TODO(Gilad): figure out how To setup anvil on a specific L1 block (through genesis.json?) and // with a specified L2 block logged to L1 (hopefully without having to use real backup). /// This test simulates a bootstrapping flow, in which 3 blocks are synced from L2, during which two diff --git a/crates/apollo_l1_provider/tests/scraper_end_to_end.rs b/crates/apollo_l1_provider/tests/scraper_end_to_end.rs index eb66ba42f04..d9aa6f1c34e 100644 --- a/crates/apollo_l1_provider/tests/scraper_end_to_end.rs +++ b/crates/apollo_l1_provider/tests/scraper_end_to_end.rs @@ -6,6 +6,7 @@ use apollo_l1_provider::event_identifiers_to_track; use apollo_l1_provider::l1_scraper::{fetch_start_block, L1Scraper}; use apollo_l1_provider_types::{Event, MockL1ProviderClient}; use apollo_l1_scraper_config::config::L1ScraperConfig; +use mockall::predicate::eq; use mockall::Sequence; use papyrus_base_layer::ethereum_base_layer_contract::{EthereumBaseLayerContract, Starknet}; use papyrus_base_layer::test_utils::{ @@ -28,9 +29,9 @@ pub fn in_ci() -> bool { #[tokio::test] async fn scraper_end_to_end() { - // if !in_ci() { - // return; - // } + if !in_ci() { + return; + } // Setup. let (base_layer_config, base_layer_url) = ethereum_base_layer_config_for_anvil(None); @@ -135,23 +136,13 @@ async fn scraper_end_to_end() { cancellation_request_timestamp: cancel_timestamp, }; - let expected_events = vec![first_expected_log, second_expected_log, expected_cancel_message]; - let mut sequence = Sequence::new(); // Expect first call to return all the events defined further down. l1_provider_client .expect_add_events() .once() .in_sequence(&mut sequence) - .withf(move |events| { - if events.len() != expected_events.len() { - return false; - } - for (event, expected_event) in events.iter().zip(expected_events.iter()) { - event.assert_event_almost_eq(expected_event); - } - true - }) + .with(eq(vec![first_expected_log, second_expected_log, expected_cancel_message])) .returning(|_| Ok(())); // Expect second call to return nothing, no events left to scrape. From 9fa10ad5588e55479ac4b8df164abe6afb82d751 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Wed, 22 Oct 2025 15:17:49 +0300 Subject: [PATCH 110/313] apollo_infra_utils,apollo_integration_tests: fix max ports gen, support hybrid node args (#9671) --- .github/workflows/hybrid_system_test.yaml | 2 +- Cargo.lock | 1 + crates/apollo_infra_utils/Cargo.toml | 4 +++- crates/apollo_infra_utils/src/test_utils.rs | 6 ++++-- .../integration_test_central_and_p2p_sync_flow.rs | 4 +++- .../integration_test_positive_flow.rs | 5 ++++- .../integration_test_restart_flow.rs | 5 ++++- .../integration_test_revert_flow.rs | 3 +++ .../src/bin/sequencer_node_setup.rs | 4 ++++ .../src/integration_test_manager.rs | 14 ++++++++------ deployments/monitoring/local/docker-compose.yml | 2 +- 11 files changed, 36 insertions(+), 14 deletions(-) diff --git a/.github/workflows/hybrid_system_test.yaml b/.github/workflows/hybrid_system_test.yaml index 60a9c233bf8..0d747de7adf 100644 --- a/.github/workflows/hybrid_system_test.yaml +++ b/.github/workflows/hybrid_system_test.yaml @@ -297,7 +297,7 @@ jobs: run: chmod +x ./target/debug/sequencer_node_setup ./target/debug/sequencer_simulator - name: Create storage files - run: ./target/debug/sequencer_node_setup --output-base-dir ./output --data-prefix-path /data --n-consolidated 1 --n-distributed 0 + run: ./target/debug/sequencer_node_setup --output-base-dir ./output --data-prefix-path /data --n-consolidated 1 --n-hybrid 0 --n-distributed 0 - name: Export application config dir run: | diff --git a/Cargo.lock b/Cargo.lock index bf44c0f7803..0831c0bbb47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1522,6 +1522,7 @@ dependencies = [ "serde", "serde_json", "socket2 0.5.10", + "strum 0.25.0", "tempfile", "thiserror 1.0.69", "tokio", diff --git a/crates/apollo_infra_utils/Cargo.toml b/crates/apollo_infra_utils/Cargo.toml index 4b08d7f5310..733133cdd56 100644 --- a/crates/apollo_infra_utils/Cargo.toml +++ b/crates/apollo_infra_utils/Cargo.toml @@ -7,7 +7,7 @@ license-file.workspace = true description = "Infrastructure utility." [features] -testing = ["colored", "dep:assert-json-diff", "socket2", "tempfile"] +testing = ["colored", "dep:assert-json-diff", "socket2", "strum", "tempfile"] [lints] workspace = true @@ -20,6 +20,7 @@ num_enum.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true socket2 = { workspace = true, optional = true } +strum = { workspace = true, optional = true } tempfile = { workspace = true, optional = true } thiserror.workspace = true tokio = { workspace = true, features = ["process", "rt", "time"] } @@ -32,6 +33,7 @@ nix.workspace = true pretty_assertions.workspace = true rstest.workspace = true socket2.workspace = true +strum.workspace = true tempfile.workspace = true tokio = { workspace = true, features = ["macros", "rt", "signal", "sync"] } toml.workspace = true diff --git a/crates/apollo_infra_utils/src/test_utils.rs b/crates/apollo_infra_utils/src/test_utils.rs index 2a382410108..cdd807c1ffb 100644 --- a/crates/apollo_infra_utils/src/test_utils.rs +++ b/crates/apollo_infra_utils/src/test_utils.rs @@ -4,11 +4,13 @@ use assert_json_diff::{assert_json_matches_no_panic, CompareMode, Config}; use num_enum::IntoPrimitive; use serde::Serialize; use socket2::{Domain, Socket, Type}; +use strum::EnumCount; use tracing::{info, instrument}; const PORTS_PER_INSTANCE: u16 = 60; pub const MAX_NUMBER_OF_INSTANCES_PER_TEST: u16 = 28; -const MAX_NUMBER_OF_TESTS: u16 = 11; +#[allow(clippy::as_conversions)] +const MAX_NUMBER_OF_TESTS: u16 = TestIdentifier::COUNT as u16; const BASE_PORT: u16 = 11000; // Ensure available ports don't exceed u16::MAX. @@ -21,7 +23,7 @@ const _: () = { }; #[repr(u16)] -#[derive(Debug, Copy, Clone, IntoPrimitive)] +#[derive(Debug, Copy, Clone, IntoPrimitive, EnumCount)] // TODO(Nadin): Come up with a better name for this enum. pub enum TestIdentifier { EndToEndFlowTest, diff --git a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_central_and_p2p_sync_flow.rs b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_central_and_p2p_sync_flow.rs index a90d0a1b9b5..0faf0945aaf 100644 --- a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_central_and_p2p_sync_flow.rs +++ b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_central_and_p2p_sync_flow.rs @@ -18,12 +18,14 @@ async fn main() { const N_CONSOLIDATED_SEQUENCERS: usize = 2; /// The number of distributed remote sequencers that participate in the test. const N_DISTRIBUTED_SEQUENCERS: usize = 0; - + /// The number of hybrid sequencers that participate in the test. + const N_HYBRID_SEQUENCERS: usize = 0; const CENTRAL_SYNC_NODE: usize = 1; let mut integration_test_manager = IntegrationTestManager::new( N_CONSOLIDATED_SEQUENCERS, N_DISTRIBUTED_SEQUENCERS, + N_HYBRID_SEQUENCERS, None, TestIdentifier::SyncFlowIntegrationTest, ) diff --git a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_positive_flow.rs b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_positive_flow.rs index 29c7ab0892b..1c80c92402b 100644 --- a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_positive_flow.rs +++ b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_positive_flow.rs @@ -13,12 +13,15 @@ async fn main() { /// The number of consolidated local sequencers that participate in the test. const N_CONSOLIDATED_SEQUENCERS: usize = 3; /// The number of distributed remote sequencers that participate in the test. - const N_DISTRIBUTED_SEQUENCERS: usize = 2; + const N_DISTRIBUTED_SEQUENCERS: usize = 1; + /// The number of hybrid sequencers that participate in the test. + const N_HYBRID_SEQUENCERS: usize = 1; // Get the sequencer configurations. let mut integration_test_manager = IntegrationTestManager::new( N_CONSOLIDATED_SEQUENCERS, N_DISTRIBUTED_SEQUENCERS, + N_HYBRID_SEQUENCERS, None, TestIdentifier::PositiveFlowIntegrationTest, ) diff --git a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_restart_flow.rs b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_restart_flow.rs index 887e1438148..8c97454fc5b 100644 --- a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_restart_flow.rs +++ b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_restart_flow.rs @@ -25,7 +25,9 @@ async fn main() { /// The number of consolidated local sequencers that participate in the test. const N_CONSOLIDATED_SEQUENCERS: usize = 1; /// The number of distributed remote sequencers that participate in the test. - const N_DISTRIBUTED_SEQUENCERS: usize = 2; + const N_DISTRIBUTED_SEQUENCERS: usize = 1; + /// The number of hybrid sequencers that participate in the test. + const N_HYBRID_SEQUENCERS: usize = 1; // The indices of the nodes that we will be shutting down. // The test restarts a hybrid node and shuts down a non-consolidated (hybrid/distributed) node. const RESTART_NODE: usize = N_CONSOLIDATED_SEQUENCERS; @@ -35,6 +37,7 @@ async fn main() { let mut integration_test_manager = IntegrationTestManager::new( N_CONSOLIDATED_SEQUENCERS, N_DISTRIBUTED_SEQUENCERS, + N_HYBRID_SEQUENCERS, None, TestIdentifier::RestartFlowIntegrationTest, ) diff --git a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs index ff3f7dd3372..84b80f0aa91 100644 --- a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs +++ b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs @@ -25,6 +25,8 @@ async fn main() { const N_L1_HANDLER_TXS: usize = 0; /// The number of consolidated local sequencers that participate in the test. const N_CONSOLIDATED_SEQUENCERS: usize = 5; + /// The number of hybrid sequencers that participate in the test. + const N_HYBRID_SEQUENCERS: usize = 0; /// The number of distributed remote sequencers that participate in the test. const N_DISTRIBUTED_SEQUENCERS: usize = 0; @@ -36,6 +38,7 @@ async fn main() { let mut integration_test_manager = IntegrationTestManager::new( N_CONSOLIDATED_SEQUENCERS, N_DISTRIBUTED_SEQUENCERS, + N_HYBRID_SEQUENCERS, None, TestIdentifier::RevertFlowIntegrationTest, ) diff --git a/crates/apollo_integration_tests/src/bin/sequencer_node_setup.rs b/crates/apollo_integration_tests/src/bin/sequencer_node_setup.rs index 8e3f641cb4c..1e00661d67a 100644 --- a/crates/apollo_integration_tests/src/bin/sequencer_node_setup.rs +++ b/crates/apollo_integration_tests/src/bin/sequencer_node_setup.rs @@ -27,6 +27,7 @@ async fn main() { let test_manager = IntegrationTestManager::new( args.n_consolidated, args.n_distributed, + args.n_hybrid, Some(custom_paths), // TODO(Tsabary/Nadin): add a different identifier. TestIdentifier::PositiveFlowIntegrationTest, @@ -58,6 +59,9 @@ struct Args { #[arg(long)] n_distributed: usize, + #[arg(long)] + n_hybrid: usize, + #[arg(long)] output_base_dir: String, diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index f3a187e045c..8a689d02020 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -265,6 +265,7 @@ impl IntegrationTestManager { pub async fn new( num_of_consolidated_nodes: usize, num_of_distributed_nodes: usize, + num_of_hybrid_nodes: usize, custom_paths: Option, test_unique_id: TestIdentifier, ) -> Self { @@ -274,6 +275,7 @@ impl IntegrationTestManager { &tx_generator, num_of_consolidated_nodes, num_of_distributed_nodes, + num_of_hybrid_nodes, custom_paths, test_unique_id, ) @@ -856,23 +858,23 @@ async fn get_sequencer_setup_configs( // TODO(Tsabary/Nadin): instead of number of nodes, this should be a vector of deployments. num_of_consolidated_nodes: usize, num_of_distributed_nodes: usize, + num_of_hybrid_nodes: usize, custom_paths: Option, test_unique_id: TestIdentifier, ) -> (Vec, HashSet) { let mut available_ports_generator = AvailablePortsGenerator::new(test_unique_id.into()); - let mut node_component_configs = - Vec::with_capacity(num_of_consolidated_nodes + num_of_distributed_nodes); + let mut node_component_configs = Vec::with_capacity( + num_of_consolidated_nodes + num_of_distributed_nodes + num_of_hybrid_nodes, + ); for _ in 0..num_of_consolidated_nodes { node_component_configs.push(create_consolidated_component_configs()); } - // Testing the two various node configurations: distributed and hybrid. - // TODO(Tsabary): better handling of the number of each type. - for _ in 0..num_of_distributed_nodes / 2 { + for _ in 0..num_of_hybrid_nodes { node_component_configs .push(create_hybrid_component_configs(&mut available_ports_generator)); } - for _ in num_of_distributed_nodes / 2..num_of_distributed_nodes { + for _ in 0..num_of_distributed_nodes { node_component_configs .push(create_distributed_component_configs(&mut available_ports_generator)); } diff --git a/deployments/monitoring/local/docker-compose.yml b/deployments/monitoring/local/docker-compose.yml index 6550912aec3..d1d908361eb 100644 --- a/deployments/monitoring/local/docker-compose.yml +++ b/deployments/monitoring/local/docker-compose.yml @@ -31,7 +31,7 @@ services: - RUST_BACKTRACE=${RUST_BACKTRACE} entrypoint: "/bin/bash -c" command: > - "./target/debug/sequencer_node_setup --output-base-dir ./output --data-prefix-path /data --n-distributed 0 --n-consolidated 1; + "./target/debug/sequencer_node_setup --output-base-dir ./output --data-prefix-path /data --n-distributed 0 --n-hybrid 0 --n-consolidated 1; cp -r ./output/data/* /data; cp -r ./output/configs/* /config" volumes: - data:/data From 9c155f34aa712e538d5be0861efa8ced624814e1 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Wed, 22 Oct 2025 15:52:10 +0300 Subject: [PATCH 111/313] apollo_mempool: log expired txs upon removal (#9640) (#9692) --- crates/apollo_mempool/src/mempool.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index e4d615693e3..53566710881 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -634,12 +634,23 @@ impl Mempool { incoming_value >= escalation_qualified_value } + #[instrument(skip_all, parent = None)] + fn log_and_count_expired_txs(&self, expired_txs: &[TransactionReference]) { + if !expired_txs.is_empty() { + metric_count_expired_txs(expired_txs.len()); + info!( + "Removed expired transactions: {:?}", + expired_txs.iter().map(|tx| tx.tx_hash).collect::>() + ); + } + } + fn remove_expired_txs(&mut self) -> AddressToNonce { let removed_txs = self.tx_pool.remove_txs_older_than(self.config.transaction_ttl, &self.state.staged); let queued_txs = self.tx_queue.remove_txs(&removed_txs); - metric_count_expired_txs(removed_txs.len()); + self.log_and_count_expired_txs(&removed_txs); self.update_state_metrics(); queued_txs .into_iter() @@ -666,7 +677,7 @@ impl Mempool { }); // Remove old transactions from the pool. - metric_count_expired_txs(old_txs.len()); + self.log_and_count_expired_txs(&old_txs); let account_nonce_updates: AddressToNonce = old_txs .into_iter() .map(|tx| { From d499f89fa0b406f38eaa382193e53ae5d074e7c2 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Wed, 22 Oct 2025 15:52:17 +0300 Subject: [PATCH 112/313] apollo_http_server: log GW error (#9672) (#9693) --- crates/apollo_http_server/src/http_server.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/apollo_http_server/src/http_server.rs b/crates/apollo_http_server/src/http_server.rs index ec4cbe0e6e0..fab166eaeec 100644 --- a/crates/apollo_http_server/src/http_server.rs +++ b/crates/apollo_http_server/src/http_server.rs @@ -26,7 +26,7 @@ use serde::de::Error; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::serde_utils::bytes_from_hex_str; use starknet_api::transaction::fields::ValidResourceBounds; -use tracing::{debug, info, instrument}; +use tracing::{debug, info, instrument, warn}; use crate::config::HttpServerConfig; use crate::deprecated_gateway_transaction::DeprecatedGatewayTransactionV3; @@ -217,7 +217,13 @@ fn record_added_transactions(add_tx_result: &HttpServerResult, re ); ADDED_TRANSACTIONS_SUCCESS.increment(1); } - Err(err) => increment_failure_metrics(err), + Err(err) => { + warn!( + error = %err, + "Failed to record transaction" + ); + increment_failure_metrics(err); + } } } From 42e30b9a3d412e19a3a3c81c1ee9829ee1990964 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Wed, 22 Oct 2025 15:59:46 +0300 Subject: [PATCH 113/313] apollo_deployments: add integration nodes 10 and 11 (#9700) --- .../sepolia_integration.json | 2 +- .../deployment_config_hybrid_10.json | 273 ++++++++++++++++++ .../deployment_config_hybrid_11.json | 273 ++++++++++++++++++ .../deployment_config_override.json | 4 +- .../sepolia_integration/hybrid_10.json | 7 + .../sepolia_integration/hybrid_11.json | 7 + 6 files changed, 563 insertions(+), 3 deletions(-) create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_10.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_11.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_10.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_11.json diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json index f2d3cb29b46..5c2f6e9fcce 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json @@ -1,5 +1,5 @@ { - "node_and_validator_ids": [[0, "0x64"], [1,"0x65"], [2,"0x66"], [12,"0x1"]], + "node_and_validator_ids": [[0, "0x64"], [1,"0x65"], [2,"0x66"], [10,"0x1"], [11,"0x1"],[12,"0x1"]], "num_validators": 3, "http_server_ingress_alternative_name": "integration-sepolia.starknet.io", "ingress_domain": "starknet.io", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_10.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_10.json new file mode 100644 index 00000000000..7bc37bf0c92 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_10.json @@ -0,0 +1,273 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_10.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 7, + "memory": 14 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-10" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_10.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "integration-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_10.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_10.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-10" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_10.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-10" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_10.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_11.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_11.json new file mode 100644 index 00000000000..c967cfdd92b --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_11.json @@ -0,0 +1,273 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_11.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 7, + "memory": 14 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-11" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_11.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "integration-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_11.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_11.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-11" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_11.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-11" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/sepolia_integration/deployment_config_override.json", + "deployments/sepolia_integration/hybrid_11.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-integration-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json index 62f5c97be7e..6c94bf74b7c 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json @@ -2,12 +2,12 @@ "base_layer_config.starknet_contract_address": "0x4737c0c1B4D5b1A687B42610DdabEE781152359c", "chain_id": "SN_INTEGRATION_SEPOLIA", "consensus_manager_config.context_config.num_validators": 3, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://feeder.integration-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_10.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_10.json new file mode 100644 index 00000000000..a1e64457f84 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_10.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_11.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_11.json new file mode 100644 index 00000000000..a1e64457f84 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_11.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "validator_id": "0x1" +} From 79bfdb0b3a1166826cdbe7f99af445ed1112b4e1 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Thu, 23 Oct 2025 09:09:10 +0300 Subject: [PATCH 114/313] l1: extract magic number to MIN_EXPECTED_BLOCK_NUMBER (#9701) --- crates/apollo_l1_endpoint_monitor/src/monitor.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/apollo_l1_endpoint_monitor/src/monitor.rs b/crates/apollo_l1_endpoint_monitor/src/monitor.rs index 22035c4dcf6..191ed16c182 100644 --- a/crates/apollo_l1_endpoint_monitor/src/monitor.rs +++ b/crates/apollo_l1_endpoint_monitor/src/monitor.rs @@ -15,6 +15,9 @@ pub mod l1_endpoint_monitor_tests; // a bug in infura where the connectivity was fine, but get_block_number() failed. pub const HEALTH_CHECK_RPC_METHOD: &str = "eth_blockNumber"; +/// The minimum expected L1 block number for a valid endpoint response. +pub const MIN_EXPECTED_BLOCK_NUMBER: u64 = 1000; + #[derive(Debug, Clone, PartialEq, Eq)] pub struct L1EndpointMonitor { pub current_l1_endpoint_index: usize, @@ -91,7 +94,7 @@ impl L1EndpointMonitor { Ok(Ok(block_number)) => { // TODO(guyn): remove this once we understand where these low numbers are coming // from. - if block_number < U64::from(1000) { + if block_number < U64::from(MIN_EXPECTED_BLOCK_NUMBER) { warn!( "L1 endpoint {l1_endpoint_url} is operational, but block number is too \ low: {block_number}" From e43e319702fa943a401f4e6dacfc0f0da9cf3073 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 23 Oct 2025 11:01:24 +0300 Subject: [PATCH 115/313] ci: add bench_tools CLI scaffold (#9612) --- Cargo.lock | 7 +++++++ Cargo.toml | 2 ++ crates/bench_tools/Cargo.toml | 10 ++++++++++ crates/bench_tools/src/main.rs | 31 +++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 crates/bench_tools/Cargo.toml create mode 100644 crates/bench_tools/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 0831c0bbb47..0bb35a2b91a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3320,6 +3320,13 @@ dependencies = [ "serde", ] +[[package]] +name = "bench_tools" +version = "0.16.0-rc.0" +dependencies = [ + "clap", +] + [[package]] name = "bincode" version = "2.0.1" diff --git a/Cargo.toml b/Cargo.toml index 4a6aa5ac7af..de11081e100 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,7 @@ members = [ "crates/apollo_task_executor", "crates/apollo_test_utils", "crates/apollo_time", + "crates/bench_tools", "crates/blockifier", "crates/blockifier_reexecution", "crates/blockifier_test_utils", @@ -211,6 +212,7 @@ async-trait = "0.1.79" atomic_refcell = "0.1.13" axum = "0.6.12" base64 = "0.13.0" +bench_tools.path = "crates/bench_tools" bincode = "1.3.3" bisection = "0.1.0" bitvec = "1.0.1" diff --git a/crates/bench_tools/Cargo.toml b/crates/bench_tools/Cargo.toml new file mode 100644 index 00000000000..8dc81ebab79 --- /dev/null +++ b/crates/bench_tools/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "bench_tools" +edition.workspace = true +version.workspace = true + +[lints] +workspace = true + +[dependencies] +clap = { workspace = true, features = ["derive"] } diff --git a/crates/bench_tools/src/main.rs b/crates/bench_tools/src/main.rs new file mode 100644 index 00000000000..0641a32efde --- /dev/null +++ b/crates/bench_tools/src/main.rs @@ -0,0 +1,31 @@ +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +#[command(about = "Benchmark runner and comparison tool for CI.")] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Run benchmarks and output results. + Run { + /// Package name to run benchmarks for. + #[arg(short, long)] + package: String, + /// Output directory for results. + #[arg(short, long)] + out: String, + }, +} + +fn main() { + let cli = Cli::parse(); + + match cli.command { + Commands::Run { package: _, out: _ } => { + unimplemented!() + } + } +} From 87e67607a57628afa30961f4a2b3ed1e5f27ad38 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 23 Oct 2025 11:48:28 +0300 Subject: [PATCH 116/313] apollo_gateway: remove the max_l2_gas_amount validation for declare (#9726) --- .../src/stateless_transaction_validator.rs | 4 +- .../stateless_transaction_validator_test.rs | 50 +++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/crates/apollo_gateway/src/stateless_transaction_validator.rs b/crates/apollo_gateway/src/stateless_transaction_validator.rs index a6e6b4e1c0c..52e8839b138 100644 --- a/crates/apollo_gateway/src/stateless_transaction_validator.rs +++ b/crates/apollo_gateway/src/stateless_transaction_validator.rs @@ -65,7 +65,9 @@ impl StatelessTransactionValidator { }); } - if resource_bounds.l2_gas.max_amount.0 > self.config.max_l2_gas_amount { + // TODO(Arni): Consider adding a validation for max_l2_gas_amount for declare. + if let RpcTransaction::Declare(_) = tx { + } else if resource_bounds.l2_gas.max_amount.0 > self.config.max_l2_gas_amount { return Err(StatelessTransactionValidatorError::MaxGasAmountTooHigh { gas_amount: resource_bounds.l2_gas.max_amount, max_gas_amount: self.config.max_l2_gas_amount, diff --git a/crates/apollo_gateway/src/stateless_transaction_validator_test.rs b/crates/apollo_gateway/src/stateless_transaction_validator_test.rs index 5d94faaf71a..f6f69e7a4b9 100644 --- a/crates/apollo_gateway/src/stateless_transaction_validator_test.rs +++ b/crates/apollo_gateway/src/stateless_transaction_validator_test.rs @@ -146,6 +146,36 @@ fn test_positive_flow( assert_matches!(tx_validator.validate(&tx), Ok(())); } +#[rstest] +#[case::l2_gas_amount_out_of_limit( + StatelessTransactionValidatorConfig { + validate_resource_bounds: true, + max_l2_gas_amount: 100, + ..*DEFAULT_VALIDATOR_CONFIG_FOR_TESTING + }, + RpcTransactionArgs { + resource_bounds: AllResourceBounds { + l2_gas: ResourceBounds { + max_amount: GasAmount(200), + ..NON_EMPTY_RESOURCE_BOUNDS + }, + ..Default::default() + }, + ..Default::default() + } +)] +fn valid_l2_gas_amount_on_declare( + #[case] config: StatelessTransactionValidatorConfig, + #[case] rpc_tx_args: RpcTransactionArgs, +) { + let tx_type = TransactionType::Declare; + let tx_validator = StatelessTransactionValidator { config }; + + let tx = rpc_tx_for_testing(tx_type, rpc_tx_args); + + assert_matches!(tx_validator.validate(&tx), Ok(())); +} + #[rstest] #[case::zero_resource_bounds( RpcTransactionArgs { @@ -172,6 +202,21 @@ fn test_positive_flow( min_gas_price: DEFAULT_VALIDATOR_CONFIG.min_gas_price }, )] +fn test_invalid_resource_bounds( + #[case] rpc_tx_args: RpcTransactionArgs, + #[case] expected_error: StatelessTransactionValidatorError, + #[values(TransactionType::Declare, TransactionType::DeployAccount, TransactionType::Invoke)] + tx_type: TransactionType, +) { + let tx_validator = + StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG.to_owned() }; + + let tx = rpc_tx_for_testing(tx_type, rpc_tx_args); + + assert_eq!(tx_validator.validate(&tx).unwrap_err(), expected_error); +} + +#[rstest] #[case::max_l2_gas_amount_too_high( RpcTransactionArgs { resource_bounds: AllResourceBounds { @@ -188,11 +233,10 @@ fn test_positive_flow( max_gas_amount: DEFAULT_VALIDATOR_CONFIG.max_l2_gas_amount }, )] -fn test_invalid_resource_bounds( +fn test_invalid_max_l2_gas_amount( #[case] rpc_tx_args: RpcTransactionArgs, #[case] expected_error: StatelessTransactionValidatorError, - #[values(TransactionType::Declare, TransactionType::DeployAccount, TransactionType::Invoke)] - tx_type: TransactionType, + #[values(TransactionType::DeployAccount, TransactionType::Invoke)] tx_type: TransactionType, ) { let tx_validator = StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG.to_owned() }; From 2a4cd4dbfc20e6c351ede8c0b452f7bb6eee9d6b Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 23 Oct 2025 13:00:06 +0300 Subject: [PATCH 117/313] ci: deserialize cargo bench result (#9624) --- Cargo.lock | 6 ++ crates/bench_tools/Cargo.toml | 13 +++ .../dummy_sum_1000_estimates.json | 47 ++++++++++ .../dummy_sum_100_estimates.json | 47 ++++++++++ crates/bench_tools/src/benches.rs | 2 + crates/bench_tools/src/benches/dummy_bench.rs | 23 +++++ crates/bench_tools/src/lib.rs | 3 + crates/bench_tools/src/types.rs | 3 + crates/bench_tools/src/types/estimates.rs | 30 +++++++ .../bench_tools/src/types/estimates_test.rs | 88 +++++++++++++++++++ 10 files changed, 262 insertions(+) create mode 100644 crates/bench_tools/data/dummy_benches_result/dummy_sum_1000_estimates.json create mode 100644 crates/bench_tools/data/dummy_benches_result/dummy_sum_100_estimates.json create mode 100644 crates/bench_tools/src/benches.rs create mode 100644 crates/bench_tools/src/benches/dummy_bench.rs create mode 100644 crates/bench_tools/src/lib.rs create mode 100644 crates/bench_tools/src/types.rs create mode 100644 crates/bench_tools/src/types/estimates.rs create mode 100644 crates/bench_tools/src/types/estimates_test.rs diff --git a/Cargo.lock b/Cargo.lock index 0bb35a2b91a..6832b59b597 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3324,7 +3324,13 @@ dependencies = [ name = "bench_tools" version = "0.16.0-rc.0" dependencies = [ + "apollo_infra_utils", "clap", + "criterion", + "glob", + "rstest", + "serde", + "serde_json", ] [[package]] diff --git a/crates/bench_tools/Cargo.toml b/crates/bench_tools/Cargo.toml index 8dc81ebab79..3ec042238f8 100644 --- a/crates/bench_tools/Cargo.toml +++ b/crates/bench_tools/Cargo.toml @@ -8,3 +8,16 @@ workspace = true [dependencies] clap = { workspace = true, features = ["derive"] } +criterion.workspace = true +serde = { workspace = true, features = ["derive"] } + +[dev-dependencies] +apollo_infra_utils.workspace = true +glob.workspace = true +rstest.workspace = true +serde_json.workspace = true + +[[bench]] +harness = false +name = "dummy_bench" +path = "src/benches/dummy_bench.rs" diff --git a/crates/bench_tools/data/dummy_benches_result/dummy_sum_1000_estimates.json b/crates/bench_tools/data/dummy_benches_result/dummy_sum_1000_estimates.json new file mode 100644 index 00000000000..07cffaf9d0e --- /dev/null +++ b/crates/bench_tools/data/dummy_benches_result/dummy_sum_1000_estimates.json @@ -0,0 +1,47 @@ +{ + "mean": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.4627450463077952, + "upper_bound": 0.4672721018359347 + }, + "point_estimate": 0.464843138908376, + "standard_error": 0.001159579008842323 + }, + "median": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.46018939259554725, + "upper_bound": 0.4630457711597157 + }, + "point_estimate": 0.46110773204298744, + "standard_error": 0.0007700792406655315 + }, + "median_abs_dev": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.004389190374631315, + "upper_bound": 0.008068153741443406 + }, + "point_estimate": 0.0057180067999875826, + "standard_error": 0.0008869433017250109 + }, + "slope": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.4613537171491014, + "upper_bound": 0.4679905568783797 + }, + "point_estimate": 0.4641046136274776, + "standard_error": 0.001730736547763549 + }, + "std_dev": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.007242933241527838, + "upper_bound": 0.01557482754536567 + }, + "point_estimate": 0.01165848802634422, + "standard_error": 0.00216291128423961 + } +} \ No newline at end of file diff --git a/crates/bench_tools/data/dummy_benches_result/dummy_sum_100_estimates.json b/crates/bench_tools/data/dummy_benches_result/dummy_sum_100_estimates.json new file mode 100644 index 00000000000..5e3be72f309 --- /dev/null +++ b/crates/bench_tools/data/dummy_benches_result/dummy_sum_100_estimates.json @@ -0,0 +1,47 @@ +{ + "mean": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.45957162353881537, + "upper_bound": 0.47252808549400704 + }, + "point_estimate": 0.4656174818033215, + "standard_error": 0.0033071130641006297 + }, + "median": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.45151445843970833, + "upper_bound": 0.4538904649825635 + }, + "point_estimate": 0.4526323188039608, + "standard_error": 0.0006992971024409143 + }, + "median_abs_dev": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.005240482428601258, + "upper_bound": 0.010332193401481504 + }, + "point_estimate": 0.007727865411134973, + "standard_error": 0.001301158952978215 + }, + "slope": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.455400693078925, + "upper_bound": 0.46369875851255066 + }, + "point_estimate": 0.45933814542565166, + "standard_error": 0.002119888457921763 + }, + "std_dev": { + "confidence_interval": { + "confidence_level": 0.95, + "lower_bound": 0.02332892198500483, + "upper_bound": 0.041110549300589966 + }, + "point_estimate": 0.03317521516535013, + "standard_error": 0.004530135795169152 + } +} \ No newline at end of file diff --git a/crates/bench_tools/src/benches.rs b/crates/bench_tools/src/benches.rs new file mode 100644 index 00000000000..a2cd56b672b --- /dev/null +++ b/crates/bench_tools/src/benches.rs @@ -0,0 +1,2 @@ +#[cfg(test)] +pub(crate) mod dummy_bench; diff --git a/crates/bench_tools/src/benches/dummy_bench.rs b/crates/bench_tools/src/benches/dummy_bench.rs new file mode 100644 index 00000000000..c13f9ae4e95 --- /dev/null +++ b/crates/bench_tools/src/benches/dummy_bench.rs @@ -0,0 +1,23 @@ +use std::hint::black_box; + +use criterion::{criterion_group, criterion_main, Criterion}; + +#[allow(dead_code)] +fn dummy_function(n: u64) -> u64 { + // Simple function that does some work + (0..n).sum() +} + +/// Example benchmark function that demonstrates how to use Criterion for benchmarking. +/// This is used to test the benchmarking infrastructure and generate sample benchmark results +/// that can be parsed by the bench_tools framework. +#[allow(dead_code)] +fn dummy_benchmark(c: &mut Criterion) { + // black_box prevents the compiler from optimizing away the function call during benchmarking + c.bench_function("dummy_sum_100", |b| b.iter(|| black_box(dummy_function(100)))); + + c.bench_function("dummy_sum_1000", |b| b.iter(|| black_box(dummy_function(1000)))); +} + +criterion_group!(benches, dummy_benchmark); +criterion_main!(benches); diff --git a/crates/bench_tools/src/lib.rs b/crates/bench_tools/src/lib.rs new file mode 100644 index 00000000000..8f65f43e194 --- /dev/null +++ b/crates/bench_tools/src/lib.rs @@ -0,0 +1,3 @@ +#[cfg(test)] +pub(crate) mod benches; +pub mod types; diff --git a/crates/bench_tools/src/types.rs b/crates/bench_tools/src/types.rs new file mode 100644 index 00000000000..95640f033c2 --- /dev/null +++ b/crates/bench_tools/src/types.rs @@ -0,0 +1,3 @@ +pub mod estimates; +#[cfg(test)] +mod estimates_test; diff --git a/crates/bench_tools/src/types/estimates.rs b/crates/bench_tools/src/types/estimates.rs new file mode 100644 index 00000000000..62ea94836c5 --- /dev/null +++ b/crates/bench_tools/src/types/estimates.rs @@ -0,0 +1,30 @@ +use serde::Deserialize; + +/// Criterion benchmark estimates. +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +pub struct Estimates { + pub mean: Stat, + pub median: Stat, + pub std_dev: Stat, + pub median_abs_dev: Stat, + pub slope: Option, +} + +/// Statistical estimate with confidence interval. +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +pub struct Stat { + pub point_estimate: f64, + pub standard_error: f64, + pub confidence_interval: ConfidenceInterval, +} + +/// Confidence interval bounds. +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +pub struct ConfidenceInterval { + pub confidence_level: f64, + pub lower_bound: f64, + pub upper_bound: f64, +} diff --git a/crates/bench_tools/src/types/estimates_test.rs b/crates/bench_tools/src/types/estimates_test.rs new file mode 100644 index 00000000000..baf77b71c56 --- /dev/null +++ b/crates/bench_tools/src/types/estimates_test.rs @@ -0,0 +1,88 @@ +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use apollo_infra_utils::path::project_path; +use rstest::{fixture, rstest}; + +use crate::types::estimates::Estimates; + +/// Returns the bench_tools crate directory. +#[fixture] +fn bench_tools_crate_dir() -> PathBuf { + std::env::var("CARGO_MANIFEST_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| std::env::current_dir().unwrap()) +} + +/// Returns the directory where dummy benchmark estimate results are stored. +#[fixture] +fn dummy_bench_results_dir(bench_tools_crate_dir: PathBuf) -> PathBuf { + bench_tools_crate_dir.join("data/dummy_benches_result") +} + +/// Returns the workspace root directory. +#[fixture] +fn workspace_root() -> PathBuf { + project_path().expect("Failed to get project path") +} + +/// Returns the list of dummy benchmark names. +#[fixture] +fn dummy_bench_names() -> &'static [&'static str] { + &["dummy_sum_100", "dummy_sum_1000"] +} + +/// Helper function to deserialize dummy bench estimates JSON files in a directory. +fn assert_deserialize_dummy_bench_estimates(results_dir: &Path, bench_names: &[&str]) { + for bench_name in bench_names { + let path = results_dir.join(format!("{}_estimates.json", bench_name)); + let data = fs::read_to_string(&path) + .unwrap_or_else(|e| panic!("Failed to read {}: {}", path.display(), e)); + + let _est: Estimates = serde_json::from_str(&data).unwrap_or_else(|e| { + panic!("Failed to deserialize {}: {}\nContent: {}", path.display(), e, data) + }); + } +} + +#[rstest] +#[ignore] +/// Run dummy benchmark and deserialize the results. +fn run_dummy_bench_and_deserialize_estimates( + workspace_root: PathBuf, + dummy_bench_results_dir: PathBuf, + dummy_bench_names: &[&str], +) { + // 1) Run dummy benchmark. + let status = Command::new("cargo") + .args(["bench", "-p", "bench_tools", "--bench", "dummy_bench"]) + .status() + .expect("Failed to spawn `cargo bench`"); + assert!(status.success(), "`cargo bench` did not exit successfully"); + + // 2) Collect and save dummy_bench estimates.json files + fs::create_dir_all(&dummy_bench_results_dir).expect("Failed to create results directory"); + + for bench_name in dummy_bench_names { + let source_path = + workspace_root.join("target/criterion").join(bench_name).join("new/estimates.json"); + let dest_path = dummy_bench_results_dir.join(format!("{}_estimates.json", bench_name)); + + // Read, parse, and write the result to the results directory. + let data = fs::read_to_string(&source_path) + .unwrap_or_else(|e| panic!("Failed to read {}: {}", source_path.display(), e)); + let json: serde_json::Value = serde_json::from_str(&data).expect("Failed to parse JSON"); + let pretty_json = serde_json::to_string_pretty(&json).expect("Failed to serialize JSON"); + fs::write(&dest_path, pretty_json).expect("Failed to write benchmark result"); + } + + // 3) Deserialize and validate the saved results + assert_deserialize_dummy_bench_estimates(&dummy_bench_results_dir, dummy_bench_names); +} + +#[rstest] +/// Test that Estimates can be deserialized from the saved results. +fn deserialize_dummy_bench_estimates(dummy_bench_results_dir: PathBuf, dummy_bench_names: &[&str]) { + assert_deserialize_dummy_bench_estimates(&dummy_bench_results_dir, dummy_bench_names); +} From ada4eec39c23eab8e7f3c1b7a6806667e78c9353 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 23 Oct 2025 13:00:07 +0300 Subject: [PATCH 118/313] apollo_batcher: add log when block is built of tx hashes (#9706) --- crates/apollo_batcher/src/block_builder.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index 3590b9f2e01..f38a1965818 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -313,6 +313,28 @@ impl BlockBuilder { self.n_executed_txs, final_n_executed_txs_nonopt, ); + // Sanity check to avoid panic and skip logging if numbers aren't aligned + if final_n_executed_txs_nonopt <= self.n_executed_txs + && self.n_executed_txs <= self.block_txs.len() + { + debug!( + "Finished building block as {}. Transaction hashes: included in block: {:?}, \ + proposer excluded but we executed: {:?}, not finished executing: {:?}", + if self.execution_params.is_validator { "validator" } else { "proposer" }, + self.block_txs[0..final_n_executed_txs_nonopt] + .iter() + .map(|tx| tx.tx_hash()) + .collect::>(), + self.block_txs[final_n_executed_txs_nonopt..self.n_executed_txs] + .iter() + .map(|tx| tx.tx_hash()) + .collect::>(), + self.block_txs[self.n_executed_txs..] + .iter() + .map(|tx| tx.tx_hash()) + .collect::>(), + ); + } // Move a clone of the executor into the lambda function. let executor = self.executor.clone(); From 5b58d49f3996b5e324b6d4179e3ee7ee273567e3 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 23 Oct 2025 13:15:47 +0300 Subject: [PATCH 119/313] ci: add benchmark config (#9625) --- crates/bench_tools/src/main.rs | 34 ++++++++++++++- crates/bench_tools/src/types.rs | 1 + .../bench_tools/src/types/benchmark_config.rs | 42 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 crates/bench_tools/src/types/benchmark_config.rs diff --git a/crates/bench_tools/src/main.rs b/crates/bench_tools/src/main.rs index 0641a32efde..bb53dd44263 100644 --- a/crates/bench_tools/src/main.rs +++ b/crates/bench_tools/src/main.rs @@ -1,3 +1,4 @@ +use bench_tools::types::benchmark_config::{find_benchmarks_by_package, BENCHMARKS}; use clap::{Parser, Subcommand}; #[derive(Parser)] @@ -18,14 +19,45 @@ enum Commands { #[arg(short, long)] out: String, }, + /// List benchmarks for a package. + List { + /// Package name to list benchmarks for. If not provided, lists all benchmarks. + #[arg(short, long)] + package: Option, + }, } fn main() { let cli = Cli::parse(); - match cli.command { Commands::Run { package: _, out: _ } => { unimplemented!() } + Commands::List { package } => match package { + Some(package_name) => { + let benchmarks = find_benchmarks_by_package(&package_name); + + if benchmarks.is_empty() { + println!("No benchmarks found for package: {}", package_name); + return; + } + + println!("Available benchmarks for package '{}':", package_name); + for bench in &benchmarks { + println!(" - {} (runs: {})", bench.name, bench.cmd_args.join(" ")); + } + } + None => { + println!("All available benchmarks:"); + for bench in BENCHMARKS { + println!( + " - {} (package: {}, runs: {})", + bench.name, + bench.package, + bench.cmd_args.join(" ") + ); + } + } + }, } } diff --git a/crates/bench_tools/src/types.rs b/crates/bench_tools/src/types.rs index 95640f033c2..65cbc4b5a34 100644 --- a/crates/bench_tools/src/types.rs +++ b/crates/bench_tools/src/types.rs @@ -1,3 +1,4 @@ +pub mod benchmark_config; pub mod estimates; #[cfg(test)] mod estimates_test; diff --git a/crates/bench_tools/src/types/benchmark_config.rs b/crates/bench_tools/src/types/benchmark_config.rs new file mode 100644 index 00000000000..516f79e3cfa --- /dev/null +++ b/crates/bench_tools/src/types/benchmark_config.rs @@ -0,0 +1,42 @@ +/// Configuration for a single benchmark. +#[derive(Debug, Clone)] +pub struct BenchmarkConfig { + pub name: &'static str, + pub package: &'static str, + pub cmd_args: &'static [&'static str], +} + +impl BenchmarkConfig { + /// Get the full cargo bench command as owned strings. + pub fn cmd_args_owned(&self) -> Vec { + self.cmd_args.iter().map(|s| s.to_string()).collect() + } +} + +/// All available benchmarks defined as a const array. +pub const BENCHMARKS: &[BenchmarkConfig] = &[ + BenchmarkConfig { + name: "full_committer_flow", + package: "starknet_committer_and_os_cli", + cmd_args: &["bench", "-p", "starknet_committer_and_os_cli", "full_committer_flow"], + }, + BenchmarkConfig { + name: "single_tree_flow", + package: "starknet_committer_and_os_cli", + cmd_args: &["bench", "-p", "starknet_committer_and_os_cli", "single_tree_flow"], + }, + BenchmarkConfig { + name: "gateway_apply_block", + package: "apollo_gateway", + cmd_args: &["bench", "-p", "apollo_gateway", "apply_block"], + }, +]; + +/// Helper functions for working with benchmarks. +pub fn find_benchmark_by_name(name: &str) -> Option<&'static BenchmarkConfig> { + BENCHMARKS.iter().find(|b| b.name == name) +} + +pub fn find_benchmarks_by_package(package: &str) -> Vec<&'static BenchmarkConfig> { + BENCHMARKS.iter().filter(|b| b.package == package).collect() +} From 4be6195ff26232ef6f804a3768ca9d7797d48897 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 23 Oct 2025 13:34:09 +0300 Subject: [PATCH 120/313] apollo_gateway: soften the `max_l2_gas_amount` check. (#9727) We want to account for the sierra gas used for fee transfer as well as for the gas used for validate and execute. --- .../resources/app_configs/gateway_config.json | 2 +- crates/apollo_gateway/src/config.rs | 2 +- crates/apollo_node/resources/config_schema.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/apollo_deployments/resources/app_configs/gateway_config.json b/crates/apollo_deployments/resources/app_configs/gateway_config.json index 85090d37eca..ad761e16315 100644 --- a/crates/apollo_deployments/resources/app_configs/gateway_config.json +++ b/crates/apollo_deployments/resources/app_configs/gateway_config.json @@ -9,7 +9,7 @@ "gateway_config.stateless_tx_validator_config.max_calldata_length": 5000, "gateway_config.stateless_tx_validator_config.max_contract_bytecode_size": 81920, "gateway_config.stateless_tx_validator_config.max_contract_class_object_size": 4089446, - "gateway_config.stateless_tx_validator_config.max_l2_gas_amount": 1100000000, + "gateway_config.stateless_tx_validator_config.max_l2_gas_amount": 1200000000, "gateway_config.stateless_tx_validator_config.max_sierra_version.major": 1, "gateway_config.stateless_tx_validator_config.max_sierra_version.minor": 7, "gateway_config.stateless_tx_validator_config.max_sierra_version.patch": 0, diff --git a/crates/apollo_gateway/src/config.rs b/crates/apollo_gateway/src/config.rs index e8b92733b60..fee3391dc96 100644 --- a/crates/apollo_gateway/src/config.rs +++ b/crates/apollo_gateway/src/config.rs @@ -127,7 +127,7 @@ impl Default for StatelessTransactionValidatorConfig { StatelessTransactionValidatorConfig { validate_resource_bounds: true, min_gas_price: 3_000_000_000, - max_l2_gas_amount: 1_100_000_000, + max_l2_gas_amount: 1_200_000_000, max_calldata_length: 4000, max_signature_length: 4000, max_contract_bytecode_size: 81920, diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index f6037af105d..08159ced458 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -1792,7 +1792,7 @@ "gateway_config.stateless_tx_validator_config.max_l2_gas_amount": { "description": "Maximum allowed L2 gas amount for transactions.", "privacy": "Public", - "value": 1100000000 + "value": 1200000000 }, "gateway_config.stateless_tx_validator_config.max_sierra_version.major": { "description": "The major version of the configuration.", From 7337cf6e466403a7e92ce4cdb5fb45213d08b70f Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Thu, 23 Oct 2025 13:47:48 +0300 Subject: [PATCH 121/313] apollo_integration_tests: add mine blocks utils (#9702) --- .../src/integration_test_manager.rs | 23 +++++------------- crates/papyrus_base_layer/src/test_utils.rs | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index 8a689d02020..9992adfc9a6 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -34,10 +34,9 @@ use papyrus_base_layer::ethereum_base_layer_contract::{ StarknetL1Contract, }; use papyrus_base_layer::test_utils::{ + anvil_mine_blocks, ethereum_base_layer_config_for_anvil, - make_block_history_on_anvil, spawn_anvil_and_deploy_starknet_l1_contract, - DEFAULT_ANVIL_ADDITIONAL_ADDRESS_INDEX, }; use starknet_api::block::BlockNumber; use starknet_api::core::{ChainId, Nonce}; @@ -322,21 +321,11 @@ impl IntegrationTestManager { let (anvil, starknet_l1_contract) = spawn_anvil_and_deploy_starknet_l1_contract(&base_layer_config, &base_layer_url).await; // Send some transactions to L1 so it has a history of blocks to scrape gas prices from. - let num_blocks_needed_on_l1 = (l1_gas_price_scraper_config.number_of_blocks_for_mean - + l1_gas_price_scraper_config.finality) - .try_into() - .unwrap(); - let sender_address = anvil.addresses()[DEFAULT_ANVIL_ADDITIONAL_ADDRESS_INDEX]; - let receiver_address = anvil.addresses()[DEFAULT_ANVIL_ADDITIONAL_ADDRESS_INDEX + 1]; - - make_block_history_on_anvil( - sender_address, - receiver_address, - base_layer_config.clone(), - &base_layer_url, - num_blocks_needed_on_l1, - ) - .await; + let num_blocks_needed_on_l1 = l1_gas_price_scraper_config.number_of_blocks_for_mean + + l1_gas_price_scraper_config.finality; + + anvil_mine_blocks(base_layer_config.clone(), num_blocks_needed_on_l1, &base_layer_url) + .await; let idle_nodes = create_map(sequencers_setup, |node| node.get_node_index()); let running_nodes = HashMap::new(); diff --git a/crates/papyrus_base_layer/src/test_utils.rs b/crates/papyrus_base_layer/src/test_utils.rs index a4c92ea5ecc..f34738ce2e0 100644 --- a/crates/papyrus_base_layer/src/test_utils.rs +++ b/crates/papyrus_base_layer/src/test_utils.rs @@ -192,3 +192,27 @@ pub async fn make_block_history_on_anvil( prev_block_number = new_block_number; } } + +/// Mine multiple blocks instantly on Anvil using the `anvil_mine` RPC method. +/// +/// Note: This creates empty blocks. For blocks with transactions, use the +/// `make_block_history_on_anvil` function instead. +pub async fn anvil_mine_blocks( + base_layer_config: EthereumBaseLayerConfig, + num_blocks: u64, + url: &Url, +) { + let base_layer = EthereumBaseLayerContract::new(base_layer_config.clone(), url.clone()); + let provider = base_layer.contract.provider(); + + let block_before = provider.get_block_number().await.expect("Failed to get block number"); + debug!("Block number before mining: {}", block_before); + + let _result: Option = provider + .raw_request("anvil_mine".into(), [num_blocks]) + .await + .expect("Failed to mine blocks on Anvil"); + + let block_after = provider.get_block_number().await.expect("Failed to get block number"); + debug!("Block number after mining: {}", block_after); +} From 50d84be66c7baa6b284657fa1a6ccb293570904b Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Thu, 23 Oct 2025 14:15:03 +0300 Subject: [PATCH 122/313] apollo_batcher: close blocks if there are no new txs after 2 seconds (#9675) --- crates/apollo_batcher/src/block_builder.rs | 41 +++++++++++ .../apollo_batcher/src/block_builder_test.rs | 68 ++++++++++++++++++- crates/apollo_batcher/src/metrics.rs | 5 ++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index f38a1965818..cd1f286ca44 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -55,6 +55,10 @@ use crate::pre_confirmed_block_writer::{CandidateTxSender, PreconfirmedTxSender} use crate::transaction_executor::TransactionExecutorTrait; use crate::transaction_provider::{TransactionProvider, TransactionProviderError}; +/// Minimum timeout for block building before finishing due to timeout without new transactions. +// TODO(dan): Make this configurable and fix the corresponding test. +pub const MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS: u64 = 2; + #[derive(Debug, Error)] pub enum BlockBuilderError { #[error(transparent)] @@ -181,6 +185,9 @@ pub struct BlockBuilder { n_concurrent_txs: usize, tx_polling_interval_millis: u64, execution_params: BlockBuilderExecutionParams, + + /// Timestamp when block building started. + block_building_start: tokio::time::Instant, } impl BlockBuilder { @@ -214,6 +221,7 @@ impl BlockBuilder { n_concurrent_txs, tx_polling_interval_millis, execution_params, + block_building_start: tokio::time::Instant::now(), } } } @@ -238,6 +246,7 @@ impl BlockBuilder { if self.execution_params.is_validator { return Err(BlockBuilderError::FailOnError(FailOnErrorCause::DeadlineReached)); } + // TODO(Dan): extract to a function (as in record_validate_proposal_failure). crate::metrics::BLOCK_CLOSE_REASON.increment( 1, &[( @@ -247,6 +256,25 @@ impl BlockBuilder { ); break; } + + if self.should_finish_due_to_timeout_while_propose() { + let now = tokio::time::Instant::now(); + let time_since_start = now.duration_since(self.block_building_start); + info!( + "No transactions are being executed and {:?} passed since block building \ + started (timeout is set to {:?}), finishing block building.", + time_since_start, MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS + ); + // TODO(Dan): extract to a function (as in record_validate_proposal_failure). + crate::metrics::BLOCK_CLOSE_REASON.increment( + 1, + &[( + crate::metrics::LABEL_NAME_BLOCK_CLOSE_REASON, + crate::metrics::BlockCloseReason::IdleExecutionTimeout.into(), + )], + ); + break; + } if final_n_executed_txs.is_none() { if let Some(res) = self.tx_provider.get_final_n_executed_txs().await { info!("Received final number of transactions in block proposal: {res}."); @@ -267,6 +295,7 @@ impl BlockBuilder { // Call `handle_executed_txs()` once more to get the last results. self.handle_executed_txs().await?; info!("Block is full."); + // TODO(Dan): extract to a function (as in record_validate_proposal_failure). crate::metrics::BLOCK_CLOSE_REASON.increment( 1, &[( @@ -522,6 +551,18 @@ impl BlockBuilder { } } + fn should_finish_due_to_timeout_while_propose(&self) -> bool { + if self.execution_params.is_validator { + return false; + }; + if self.n_txs_in_progress() > 0 { + return false; + }; + let now = tokio::time::Instant::now(); + let time_since_start = now.duration_since(self.block_building_start); + time_since_start.as_secs() >= MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS + } + async fn sleep(&mut self) { tokio::time::sleep(tokio::time::Duration::from_millis(self.tx_polling_interval_millis)) .await; diff --git a/crates/apollo_batcher/src/block_builder_test.rs b/crates/apollo_batcher/src/block_builder_test.rs index 13f573ae004..e017bab2bd5 100644 --- a/crates/apollo_batcher/src/block_builder_test.rs +++ b/crates/apollo_batcher/src/block_builder_test.rs @@ -66,6 +66,8 @@ struct TestExpectations { expected_block_artifacts: BlockExecutionArtifacts, expected_txs_output: Vec, expected_full_blocks_metric: u64, + expected_idle_execution_timeout_metric: u64, + deadline_secs: u64, } fn output_channel() @@ -128,6 +130,8 @@ fn one_chunk_test_expectations() -> TestExpectations { expected_block_artifacts, expected_txs_output: input_txs, expected_full_blocks_metric: 0, + expected_idle_execution_timeout_metric: 0, + deadline_secs: BLOCK_GENERATION_DEADLINE_SECS, } } @@ -260,6 +264,8 @@ fn two_chunks_test_expectations() -> TestExpectations { expected_block_artifacts, expected_txs_output: chain!(first_chunk.iter(), second_chunk.iter()).cloned().collect(), expected_full_blocks_metric: 0, + expected_idle_execution_timeout_metric: 0, + deadline_secs: BLOCK_GENERATION_DEADLINE_SECS, } } @@ -279,6 +285,8 @@ fn empty_block_test_expectations() -> TestExpectations { expected_block_artifacts, expected_txs_output: vec![], expected_full_blocks_metric: 0, + expected_idle_execution_timeout_metric: 0, + deadline_secs: BLOCK_GENERATION_DEADLINE_SECS, } } @@ -305,6 +313,8 @@ fn block_full_test_expectations(before_is_done: bool) -> TestExpectations { expected_block_artifacts, expected_txs_output: input_txs, expected_full_blocks_metric: 1, + expected_idle_execution_timeout_metric: 0, + deadline_secs: BLOCK_GENERATION_DEADLINE_SECS, } } @@ -357,6 +367,8 @@ fn test_expectations_partial_transaction_execution() -> TestExpectations { expected_block_artifacts, expected_txs_output: input_txs, expected_full_blocks_metric: 0, + expected_idle_execution_timeout_metric: 0, + deadline_secs: BLOCK_GENERATION_DEADLINE_SECS, } } @@ -429,6 +441,52 @@ fn transaction_failed_test_expectations() -> TestExpectations { expected_block_artifacts, expected_txs_output: input_txs, expected_full_blocks_metric: 0, + expected_idle_execution_timeout_metric: 0, + deadline_secs: BLOCK_GENERATION_DEADLINE_SECS, + } +} + +fn idle_execution_timeout_test_expectations() -> TestExpectations { + let input_txs = test_txs(0..2); + let input_txs_clone = input_txs.clone(); + + let mut helper = ExpectationHelper::new(); + helper.expect_successful_get_new_results(0); + helper.expect_is_done(false); + helper.expect_add_txs_to_block(&input_txs); + helper.expect_successful_get_new_results(input_txs.len()); + helper.expect_is_done(false); + // After the timeout check, no more results will be returned. + helper.mock_transaction_executor.expect_get_new_results().returning(Vec::new); + // Keep reporting not done so the timeout can trigger. + helper.mock_transaction_executor.expect_is_done().returning(|| false); + + let expected_block_artifacts = + set_close_block_expectations(&mut helper.mock_transaction_executor, input_txs.len()); + + // Mock provider that returns initial transactions, then empty chunks. + let mut mock_tx_provider = MockTransactionProvider::new(); + + // First call returns the initial transactions. + mock_tx_provider.expect_get_final_n_executed_txs().times(1).return_const(None); + mock_tx_provider + .expect_get_txs() + .times(1) + .with(eq(N_CONCURRENT_TXS)) + .return_once(move |_n_txs| Ok(input_txs)); + + // Subsequent calls return empty (no new transactions). + mock_tx_provider.expect_get_final_n_executed_txs().return_const(None); + mock_tx_provider.expect_get_txs().with(eq(N_CONCURRENT_TXS)).returning(|_n_txs| Ok(vec![])); + + TestExpectations { + mock_transaction_executor: helper.mock_transaction_executor, + mock_tx_provider, + expected_block_artifacts, + expected_txs_output: input_txs_clone, + expected_full_blocks_metric: 0, + expected_idle_execution_timeout_metric: 1, + deadline_secs: 5, } } @@ -591,6 +649,7 @@ async fn verify_build_block_output( result_block_artifacts: BlockExecutionArtifacts, mut output_stream_receiver: UnboundedReceiver, expected_full_blocks_metric: u64, + expected_idle_execution_timeout_metric: u64, metrics: &str, ) { // Verify the transactions in the output channel. @@ -606,6 +665,11 @@ async fn verify_build_block_output( expected_full_blocks_metric, &[(LABEL_NAME_BLOCK_CLOSE_REASON, BlockCloseReason::FullBlock.into())], ); + BLOCK_CLOSE_REASON.assert_eq::( + metrics, + expected_idle_execution_timeout_metric, + &[(LABEL_NAME_BLOCK_CLOSE_REASON, BlockCloseReason::IdleExecutionTimeout.into())], + ); } async fn run_build_block( @@ -645,6 +709,7 @@ async fn run_build_block( #[case::block_full_after_is_done(block_full_test_expectations(false))] #[case::deadline_reached_after_first_chunk(test_expectations_partial_transaction_execution())] #[case::transaction_failed(transaction_failed_test_expectations())] +#[case::idle_execution_timeout(idle_execution_timeout_test_expectations())] #[tokio::test] async fn test_build_block(#[case] test_expectations: TestExpectations) { let recorder = PrometheusBuilder::new().build_recorder(); @@ -666,7 +731,7 @@ async fn test_build_block(#[case] test_expectations: TestExpectations) { Some(output_tx_sender), false, abort_receiver, - BLOCK_GENERATION_DEADLINE_SECS, + test_expectations.deadline_secs, ) .await .unwrap(); @@ -677,6 +742,7 @@ async fn test_build_block(#[case] test_expectations: TestExpectations) { result_block_artifacts, output_tx_receiver, test_expectations.expected_full_blocks_metric, + test_expectations.expected_idle_execution_timeout_metric, &recorder.handle().render(), ) .await; diff --git a/crates/apollo_batcher/src/metrics.rs b/crates/apollo_batcher/src/metrics.rs index 17bf589e6b6..d4ca1f68115 100644 --- a/crates/apollo_batcher/src/metrics.rs +++ b/crates/apollo_batcher/src/metrics.rs @@ -58,6 +58,11 @@ pub const LABEL_NAME_BLOCK_CLOSE_REASON: &str = "block_close_reason"; pub enum BlockCloseReason { FullBlock, Deadline, + /// Block building finished because no new transactions are being executed and the minimal + /// timeout ( + /// [`MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS`](crate::block_builder::MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS) + /// ) passed. + IdleExecutionTimeout, } generate_permutation_labels! { From 4e96d9f5c33a1fe5e1897eb5d0d2d4c87ddb7570 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 23 Oct 2025 14:48:32 +0300 Subject: [PATCH 123/313] apollo_consensus_orchestrator: add override for eth-to-strk conversion rate (#9691) (#9734) Co-authored-by: guy-starkware --- config/papyrus/default_config.json | 28 ++-- .../src/config.rs | 40 +++-- .../src/sequencer_consensus_context.rs | 15 +- .../src/sequencer_consensus_context_test.rs | 149 +++++++++++++----- .../src/test_utils.rs | 22 +-- .../src/utils.rs | 28 ++-- .../src/validate_proposal_test.rs | 2 +- .../app_configs/consensus_manager_config.json | 14 +- .../apollo_node/resources/config_schema.json | 28 ++-- ...fig__config_test__dump_default_config.snap | 30 ++-- 10 files changed, 245 insertions(+), 111 deletions(-) diff --git a/config/papyrus/default_config.json b/config/papyrus/default_config.json index 4cbb0b556fa..faced1c73a3 100644 --- a/config/papyrus/default_config.json +++ b/config/papyrus/default_config.json @@ -199,32 +199,42 @@ "privacy": "Public", "value": 1 }, - "context.override_l1_data_gas_price": { - "description": "Replace the L1 data gas price with this value.", + "context.override_eth_to_fri_rate": { + "description": "Replace the Eth-to-Fri conversion rate with this value.", "privacy": "Public", "value": 0 }, - "context.override_l1_data_gas_price.#is_none": { + "context.override_eth_to_fri_rate.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", "value": true }, - "context.override_l1_gas_price": { - "description": "Replace the L1 gas price with this value.", + "context.override_l1_data_gas_price_wei": { + "description": "Replace the L1 data gas price (wei) with this value.", "privacy": "Public", "value": 0 }, - "context.override_l1_gas_price.#is_none": { + "context.override_l1_data_gas_price_wei.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", "value": true }, - "context.override_l2_gas_price": { - "description": "Replace the L2 gas price with this value.", + "context.override_l1_gas_price_wei": { + "description": "Replace the L1 gas price (wei) with this value.", "privacy": "Public", "value": 0 }, - "context.override_l2_gas_price.#is_none": { + "context.override_l1_gas_price_wei.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "context.override_l2_gas_price_fri": { + "description": "Replace the L2 gas price (fri) with this value.", + "privacy": "Public", + "value": 0 + }, + "context.override_l2_gas_price_fri.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", "value": true diff --git a/crates/apollo_consensus_orchestrator/src/config.rs b/crates/apollo_consensus_orchestrator/src/config.rs index a048bc69892..7301cc310ed 100644 --- a/crates/apollo_consensus_orchestrator/src/config.rs +++ b/crates/apollo_consensus_orchestrator/src/config.rs @@ -53,11 +53,13 @@ pub struct ContextConfig { /// This additional gas is added to the L1 gas price. pub l1_gas_tip_wei: u128, /// If given, will override the L2 gas price. - pub override_l2_gas_price: Option, + pub override_l2_gas_price_fri: Option, /// If given, will override the L1 gas price. - pub override_l1_gas_price: Option, + pub override_l1_gas_price_wei: Option, /// If given, will override the L1 data gas price. - pub override_l1_data_gas_price: Option, + pub override_l1_data_gas_price_wei: Option, + /// If given, will override the conversion rate. + pub override_eth_to_fri_rate: Option, } impl SerializeConfig for ContextConfig { @@ -153,24 +155,31 @@ impl SerializeConfig for ContextConfig { ), ]); dump.extend(ser_optional_param( - &self.override_l2_gas_price, + &self.override_l2_gas_price_fri, 0, - "override_l2_gas_price", - "Replace the L2 gas price with this value.", + "override_l2_gas_price_fri", + "Replace the L2 gas price (fri) with this value.", ParamPrivacyInput::Public, )); dump.extend(ser_optional_param( - &self.override_l1_gas_price, + &self.override_l1_gas_price_wei, 0, - "override_l1_gas_price", - "Replace the L1 gas price with this value.", + "override_l1_gas_price_wei", + "Replace the L1 gas price (wei) with this value.", ParamPrivacyInput::Public, )); dump.extend(ser_optional_param( - &self.override_l1_data_gas_price, + &self.override_l1_data_gas_price_wei, 0, - "override_l1_data_gas_price", - "Replace the L1 data gas price with this value.", + "override_l1_data_gas_price_wei", + "Replace the L1 data gas price (wei) with this value.", + ParamPrivacyInput::Public, + )); + dump.extend(ser_optional_param( + &self.override_eth_to_fri_rate, + 0, + "override_eth_to_fri_rate", + "Replace the Eth-to-Fri conversion rate with this value.", ParamPrivacyInput::Public, )); dump @@ -194,9 +203,10 @@ impl Default for ContextConfig { max_l1_data_gas_price_wei: ETH_FACTOR, l1_data_gas_price_multiplier_ppt: 135, l1_gas_tip_wei: GWEI_FACTOR, - override_l2_gas_price: None, - override_l1_gas_price: None, - override_l1_data_gas_price: None, + override_l2_gas_price_fri: None, + override_l1_gas_price_wei: None, + override_l1_data_gas_price_wei: None, + override_eth_to_fri_rate: None, } } } diff --git a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs index 73f8b959653..ab6de793994 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -252,6 +252,11 @@ impl ConsensusContext for SequencerConsensusContext { let cancel_token = CancellationToken::new(); let cancel_token_clone = cancel_token.clone(); let gas_price_params = make_gas_price_params(&self.config); + let mut l2_gas_price = self.l2_gas_price; + if let Some(override_value) = self.config.override_l2_gas_price_fri { + info!("Overriding L2 gas price to {override_value} fri"); + l2_gas_price = GasPrice(override_value); + } let args = ProposalBuildArguments { deps: self.deps.clone(), batcher_timeout: timeout - self.config.build_proposal_margin_millis, @@ -262,7 +267,7 @@ impl ConsensusContext for SequencerConsensusContext { valid_proposals: Arc::clone(&self.valid_proposals), proposal_id, cende_write_success, - l2_gas_price: self.l2_gas_price, + l2_gas_price, builder_address: self.config.builder_address, cancel_token, previous_block_info: self.previous_block_info.clone(), @@ -459,8 +464,12 @@ impl ConsensusContext for SequencerConsensusContext { .collect(); let gas_target = VersionedConstants::latest_constants().gas_target; - if let Some(override_value) = self.config.override_l2_gas_price { - info!("Overriding L2 gas price to {override_value}"); + if let Some(override_value) = self.config.override_l2_gas_price_fri { + info!( + "L2 gas price ({}) is not updated, remains on override value of {override_value} \ + fri", + self.l2_gas_price.0 + ); self.l2_gas_price = GasPrice(override_value); } else { self.l2_gas_price = 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 51d506ff71e..906493a7cee 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context_test.rs @@ -66,7 +66,7 @@ async fn cancelled_proposal_aborts() { #[tokio::test] async fn validate_proposal_success() { let (mut deps, _network) = create_test_and_network_deps(); - deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); let mut context = deps.build_context(); // Initialize the context for a specific height, starting with round 0. @@ -128,7 +128,7 @@ async fn validate_then_repropose(#[case] execute_all_txs: bool) { false => TX_BATCH.iter().take(TX_BATCH.len() - 1).cloned().collect(), }; let final_n_executed_txs = executed_transactions.len(); - deps.setup_deps_for_validate(BlockNumber(0), final_n_executed_txs); + deps.setup_deps_for_validate(BlockNumber(0), final_n_executed_txs, 1); let mut context = deps.build_context(); // Initialize the context for a specific height, starting with round 0. @@ -174,7 +174,7 @@ async fn validate_then_repropose(#[case] execute_all_txs: bool) { #[tokio::test] async fn proposals_from_different_rounds() { let (mut deps, _network) = create_test_and_network_deps(); - deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); let mut context = deps.build_context(); // Initialize the context for a specific height, starting with round 0. context.set_height_and_round(BlockNumber(0), 0).await; @@ -231,7 +231,7 @@ async fn proposals_from_different_rounds() { #[tokio::test] async fn interrupt_active_proposal() { let (mut deps, _network) = create_test_and_network_deps(); - deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); let mut context = deps.build_context(); // Initialize the context for a specific height, starting with round 0. context.set_height_and_round(BlockNumber(0), 0).await; @@ -280,7 +280,7 @@ async fn build_proposal() { let before: u64 = chrono::Utc::now().timestamp().try_into().expect("Timestamp conversion failed"); let (mut deps, mut network) = create_test_and_network_deps(); - deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); let mut context = deps.build_context(); let fin_receiver = context.build_proposal(ProposalInit::default(), TIMEOUT).await; // Test proposal parts. @@ -314,7 +314,7 @@ async fn build_proposal() { #[tokio::test] async fn build_proposal_cende_failure() { let (mut deps, _network) = create_test_and_network_deps(); - deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); let mut mock_cende_context = MockCendeContext::new(); mock_cende_context .expect_write_prev_height_blob() @@ -330,7 +330,7 @@ async fn build_proposal_cende_failure() { #[tokio::test] async fn build_proposal_cende_incomplete() { let (mut deps, _network) = create_test_and_network_deps(); - deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); let mut mock_cende_context = MockCendeContext::new(); mock_cende_context .expect_write_prev_height_blob() @@ -389,7 +389,7 @@ async fn propose_then_repropose(#[case] execute_all_txs: bool) { true => TX_BATCH.to_vec(), false => TX_BATCH.iter().take(TX_BATCH.len() - 1).cloned().collect(), }; - deps.setup_deps_for_build(BlockNumber(0), transactions.len()); + deps.setup_deps_for_build(BlockNumber(0), transactions.len(), 1); let mut context = deps.build_context(); // Build proposal. let fin_receiver = context.build_proposal(ProposalInit::default(), TIMEOUT).await; @@ -454,7 +454,7 @@ async fn eth_to_fri_rate_out_of_range() { #[tokio::test] async fn gas_price_limits(#[case] maximum: bool) { let (mut deps, _network) = create_test_and_network_deps(); - deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); let context_config = ContextConfig::default(); let min_gas_price = context_config.min_l1_gas_price_wei; let min_data_price = context_config.min_l1_data_gas_price_wei; @@ -526,7 +526,7 @@ async fn decision_reached_sends_correct_values() { // We need to create a valid proposal to call decision_reached on. // // 1. Build proposal setup starts. - deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); const BLOCK_TIME_STAMP_SECONDS: u64 = 123456; let mut clock = MockClock::new(); @@ -579,7 +579,7 @@ async fn decision_reached_sends_correct_values() { #[tokio::test] async fn oracle_fails_on_startup(#[case] l1_oracle_failure: bool) { let (mut deps, mut network) = create_test_and_network_deps(); - deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); if l1_oracle_failure { let mut l1_prices_oracle_client = MockL1GasPriceProviderClient::new(); @@ -654,8 +654,8 @@ async fn oracle_fails_on_second_block(#[case] l1_oracle_failure: bool) { let (mut deps, mut network) = create_test_and_network_deps(); // Validate block number 0, call decision_reached to save the previous block info (block 0), and // attempt to build_proposal on block number 1. - deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len()); - deps.setup_deps_for_build(BlockNumber(1), INTERNAL_TX_BATCH.len()); + deps.setup_deps_for_validate(BlockNumber(0), INTERNAL_TX_BATCH.len(), 1); + deps.setup_deps_for_build(BlockNumber(1), INTERNAL_TX_BATCH.len(), 1); // set up batcher decision_reached deps.batcher.expect_decision_reached().times(1).return_once(|_| { @@ -788,34 +788,74 @@ async fn oracle_fails_on_second_block(#[case] l1_oracle_failure: bool) { } // L2 gas is a bit above the minimum gas price. -const ODDLY_SPECIFIC_L2_GAS_PRICE: GasPrice = GasPrice(9999999999); -const ODDLY_SPECIFIC_L1_GAS_PRICE: GasPrice = GasPrice(1234567890); -const ODDLY_SPECIFIC_L1_DATA_GAS_PRICE: GasPrice = GasPrice(987654321); +const ODDLY_SPECIFIC_L2_GAS_PRICE: u128 = 9999999999; +const ODDLY_SPECIFIC_L1_GAS_PRICE: u128 = 1234567890; +const ODDLY_SPECIFIC_L1_DATA_GAS_PRICE: u128 = 987654321; +const ODDLY_SPECIFIC_CONVERSION_RATE: u128 = 12345678901234567890; + +// If we use low numbers for fri/wei we have to make sure the conversion (eth to fri) and eth-to-wei +// factor (wei to eth) don't go below zero in either direction. Typically the gas price (in +// particular the data gas price) can be as low as 1, so the eth-to-fri rate must be above 10^18. +// That also means that the L2 gas (in fri) must be bigger than the ratio of the conversion rate and +// the eth-to-wei factor. Must use a large enough number that conversion to wei works +const LOW_OVERRIDE_L2_GAS_PRICE: u128 = 25; // FRI +// ETH_TO_FRI_RATE must be larger/equal to 10^18 (wei to eth conversion factor) +const LOW_OVERRIDE_CONVERSION_RATE: u128 = u128::pow(10, 19); + +// If we use really low L2 gas price, the block will fail to build. +const LOW_OVERRIDE_L2_GAS_PRICE_FAIL: u128 = 1; // FRI #[rstest] -#[case::dont_override_prices(None, None, None)] -#[case::override_l2_gas_price(Some(ODDLY_SPECIFIC_L2_GAS_PRICE.0), None, None)] -#[case::override_l1_gas_price(None, Some(ODDLY_SPECIFIC_L1_GAS_PRICE.0), None)] -#[case::override_l1_data_gas_price(None, None, Some(ODDLY_SPECIFIC_L1_DATA_GAS_PRICE.0))] -#[case::override_all_prices(Some(ODDLY_SPECIFIC_L2_GAS_PRICE.0), Some(ODDLY_SPECIFIC_L1_GAS_PRICE.0), Some(ODDLY_SPECIFIC_L1_DATA_GAS_PRICE.0))] +#[case::dont_override_prices(None, None, None, None, true)] +#[case::override_l2_gas_price(Some(ODDLY_SPECIFIC_L2_GAS_PRICE), None, None, None, true)] +#[case::override_l1_gas_price(None, Some(ODDLY_SPECIFIC_L1_GAS_PRICE), None, None, true)] +#[case::override_l1_data_gas_price(None, None, Some(ODDLY_SPECIFIC_L1_DATA_GAS_PRICE), None, true)] +#[case::override_all_prices( + Some(ODDLY_SPECIFIC_L2_GAS_PRICE), + Some(ODDLY_SPECIFIC_L1_GAS_PRICE), + Some(ODDLY_SPECIFIC_L1_DATA_GAS_PRICE), + None, + true +)] +#[case::override_everything( + Some(ODDLY_SPECIFIC_L2_GAS_PRICE), + Some(ODDLY_SPECIFIC_L1_GAS_PRICE), + Some(ODDLY_SPECIFIC_L1_DATA_GAS_PRICE), + Some(ODDLY_SPECIFIC_CONVERSION_RATE), + true +)] +#[case::low_overrides( + Some(LOW_OVERRIDE_L2_GAS_PRICE), + Some(1), + Some(1), + Some(LOW_OVERRIDE_CONVERSION_RATE), + true +)] +#[case::low_l2_gas_price_fail( + Some(LOW_OVERRIDE_L2_GAS_PRICE_FAIL), + None, + None, + Some(LOW_OVERRIDE_CONVERSION_RATE), + false +)] #[tokio::test] async fn override_prices_behavior( - #[case] override_l2_gas_price: Option, - #[case] override_l1_gas_price: Option, - #[case] override_l1_data_gas_price: Option, + #[case] override_l2_gas_price_fri: Option, + #[case] override_l1_gas_price_wei: Option, + #[case] override_l1_data_gas_price_wei: Option, + #[case] override_eth_to_fri_rate: Option, + #[case] build_success: bool, ) { // Use high gas usage to ensure the L2 gas price is high. let mock_l2_gas_used = VersionedConstants::latest_constants().max_block_size; let (mut deps, _network) = create_test_and_network_deps(); - let recorder = PrometheusBuilder::new().build_recorder(); - let _recorder_guard = metrics::set_default_local_recorder(&recorder); - // Setup dependencies and mocks. - deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len()); + #[allow(clippy::as_conversions)] + deps.setup_deps_for_build(BlockNumber(0), INTERNAL_TX_BATCH.len(), build_success as usize); deps.l1_gas_price_provider.expect_get_eth_to_fri_rate().returning(|_| Ok(ETH_TO_FRI_RATE)); - deps.batcher.expect_decision_reached().times(1).return_once(move |_| { + deps.batcher.expect_decision_reached().return_once(move |_| { Ok(DecisionReachedResponse { state_diff: ThinStateDiff::default(), l2_gas_used: mock_l2_gas_used, @@ -823,13 +863,14 @@ async fn override_prices_behavior( }) }); - deps.state_sync_client.expect_add_new_block().times(1).return_once(|_| Ok(())); - deps.cende_ambassador.expect_prepare_blob_for_next_height().times(1).return_once(|_| Ok(())); + deps.state_sync_client.expect_add_new_block().return_once(|_| Ok(())); + deps.cende_ambassador.expect_prepare_blob_for_next_height().return_once(|_| Ok(())); let context_config = ContextConfig { - override_l2_gas_price, - override_l1_gas_price, - override_l1_data_gas_price, + override_l2_gas_price_fri, + override_l1_gas_price_wei, + override_l1_data_gas_price_wei, + override_eth_to_fri_rate, ..Default::default() }; let mut context = deps.build_context(); @@ -844,18 +885,27 @@ async fn override_prices_behavior( apply_fee_transformations(&mut expected_l1_prices, &gas_price_params); // Run proposal and decision logic. - let _fin_receiver = context.build_proposal(ProposalInit::default(), TIMEOUT).await.await; + let fin_result = context.build_proposal(ProposalInit::default(), TIMEOUT).await.await; + + // In cases where we expect the batcher to fail the block build. + if !build_success { + assert!(fin_result.is_err()); + return; + } + context .decision_reached(BlockHash(STATE_DIFF_COMMITMENT.0.0), vec![Vote::default()]) .await .unwrap(); let actual_l2_gas_price = context.l2_gas_price.0; - let actual_l1_gas_price = context.previous_block_info.clone().unwrap().l1_gas_price_wei.0; - let actual_l1_data_gas_price = - context.previous_block_info.clone().unwrap().l1_data_gas_price_wei.0; - if let Some(override_l2_gas_price) = override_l2_gas_price { + let previous_block = context.previous_block_info.clone().unwrap(); + let actual_l1_gas_price = previous_block.l1_gas_price_wei.0; + let actual_l1_data_gas_price = previous_block.l1_data_gas_price_wei.0; + let actual_conversion_rate = previous_block.eth_to_fri_rate; + + if let Some(override_l2_gas_price) = override_l2_gas_price_fri { // In this case the L2 gas price must match the given override. assert_eq!( actual_l2_gas_price, override_l2_gas_price, @@ -872,7 +922,7 @@ async fn override_prices_behavior( ); } - if let Some(override_l1_gas_price) = override_l1_gas_price { + if let Some(override_l1_gas_price) = override_l1_gas_price_wei { assert_eq!( actual_l1_gas_price, override_l1_gas_price, "Expected L1 gas price ({}) to match input l1 gas price ({})", @@ -886,7 +936,7 @@ async fn override_prices_behavior( ); } - if let Some(override_l1_data_gas_price) = override_l1_data_gas_price { + if let Some(override_l1_data_gas_price) = override_l1_data_gas_price_wei { assert_eq!( actual_l1_data_gas_price, override_l1_data_gas_price, "Expected L1 data gas price ({}) to match input l1 data gas price ({})", @@ -899,4 +949,21 @@ async fn override_prices_behavior( actual_l1_data_gas_price, expected_l1_prices.blob_fee.0 ); } + + if let Some(override_eth_to_fri_rate) = override_eth_to_fri_rate { + assert_eq!( + actual_conversion_rate, override_eth_to_fri_rate, + "Expected conversion rate ({}) to match input conversion rate ({})", + actual_conversion_rate, override_eth_to_fri_rate + ); + } else { + // Note: the "default eth to fri rate" is actually just 10^18 (eth to wei). + // This is set in the default expectations and is used by many other tests. + // So we'll just assume that this is the "real" conversion rate, unless overriden. + assert_eq!( + actual_conversion_rate, ETH_TO_FRI_RATE, + "Expected conversion rate ({}) to match default conversion rate ({})", + actual_conversion_rate, ETH_TO_FRI_RATE + ); + } } diff --git a/crates/apollo_consensus_orchestrator/src/test_utils.rs b/crates/apollo_consensus_orchestrator/src/test_utils.rs index e2628075207..bca6c50227f 100644 --- a/crates/apollo_consensus_orchestrator/src/test_utils.rs +++ b/crates/apollo_consensus_orchestrator/src/test_utils.rs @@ -121,29 +121,32 @@ impl TestDeps { &mut self, block_number: BlockNumber, final_n_executed_txs: usize, + number_of_times: usize, ) { assert!(final_n_executed_txs <= INTERNAL_TX_BATCH.len()); self.setup_default_expectations(); let proposal_id = Arc::new(OnceLock::new()); let proposal_id_clone = Arc::clone(&proposal_id); - self.batcher.expect_propose_block().times(1).returning(move |input: ProposeBlockInput| { - proposal_id_clone.set(input.proposal_id).unwrap(); - Ok(()) - }); + self.batcher.expect_propose_block().times(number_of_times).returning( + move |input: ProposeBlockInput| { + proposal_id_clone.set(input.proposal_id).unwrap(); + Ok(()) + }, + ); self.batcher .expect_start_height() .times(1) .withf(move |input| input.height == block_number) .return_const(Ok(())); let proposal_id_clone = Arc::clone(&proposal_id); - self.batcher.expect_get_proposal_content().times(1).returning(move |input| { + self.batcher.expect_get_proposal_content().times(number_of_times).returning(move |input| { assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); Ok(GetProposalContentResponse { content: GetProposalContent::Txs(INTERNAL_TX_BATCH.clone()), }) }); let proposal_id_clone = Arc::clone(&proposal_id); - self.batcher.expect_get_proposal_content().times(1).returning(move |input| { + self.batcher.expect_get_proposal_content().times(number_of_times).returning(move |input| { assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); Ok(GetProposalContentResponse { content: GetProposalContent::Finished { @@ -158,12 +161,13 @@ impl TestDeps { &mut self, block_number: BlockNumber, final_n_executed_txs: usize, + number_of_times: usize, ) { assert!(final_n_executed_txs <= INTERNAL_TX_BATCH.len()); self.setup_default_expectations(); let proposal_id = Arc::new(OnceLock::new()); let proposal_id_clone = Arc::clone(&proposal_id); - self.batcher.expect_validate_block().times(1).returning( + self.batcher.expect_validate_block().times(number_of_times).returning( move |input: ValidateBlockInput| { proposal_id_clone.set(input.proposal_id).unwrap(); Ok(()) @@ -174,7 +178,7 @@ impl TestDeps { .withf(move |input| input.height == block_number) .return_const(Ok(())); let proposal_id_clone = Arc::clone(&proposal_id); - self.batcher.expect_send_proposal_content().times(1).returning( + self.batcher.expect_send_proposal_content().times(number_of_times).returning( move |input: SendProposalContentInput| { assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); let SendProposalContent::Txs(txs) = input.content else { @@ -185,7 +189,7 @@ impl TestDeps { }, ); let proposal_id_clone = Arc::clone(&proposal_id); - self.batcher.expect_send_proposal_content().times(1).returning( + self.batcher.expect_send_proposal_content().times(number_of_times).returning( move |input: SendProposalContentInput| { assert_eq!(input.proposal_id, *proposal_id_clone.get().unwrap()); assert_eq!(input.content, SendProposalContent::Finish(final_n_executed_txs)); diff --git a/crates/apollo_consensus_orchestrator/src/utils.rs b/crates/apollo_consensus_orchestrator/src/utils.rs index 3c35231a724..7e0f224ef3c 100644 --- a/crates/apollo_consensus_orchestrator/src/utils.rs +++ b/crates/apollo_consensus_orchestrator/src/utils.rs @@ -50,8 +50,9 @@ pub(crate) struct GasPriceParams { pub min_l1_data_gas_price_wei: GasPrice, pub l1_data_gas_price_multiplier: Ratio, pub l1_gas_tip_wei: GasPrice, - pub override_l1_gas_price: Option, - pub override_l1_data_gas_price: Option, + pub override_l1_gas_price_wei: Option, + pub override_l1_data_gas_price_wei: Option, + pub override_eth_to_fri_rate: Option, } impl From for BuildProposalError { @@ -98,7 +99,10 @@ pub(crate) async fn get_oracle_rate_and_prices( if let (Ok(eth_to_strk_rate), Ok(mut price_info)) = (eth_to_strk_rate, price_info) { // Both L1 prices and rate are Ok, so we can use them. - info!("eth_to_strk_rate: {eth_to_strk_rate}, l1 gas price: {price_info:?}"); + info!( + "raw eth_to_strk_rate (from oracle): {eth_to_strk_rate}, raw l1 gas price wei (from \ + provider): {price_info:?}" + ); apply_fee_transformations(&mut price_info, gas_price_params); return_values = (eth_to_strk_rate, price_info); } else { @@ -132,15 +136,20 @@ pub(crate) async fn get_oracle_rate_and_prices( } // If there is an override to L1 gas price or data gas price, apply it here: - if let Some(override_value) = gas_price_params.override_l1_gas_price { - info!("Overriding L1 gas price to {override_value}"); + if let Some(override_value) = gas_price_params.override_l1_gas_price_wei { + info!("Overriding L1 gas price to {override_value} wei"); return_values.1.base_fee_per_gas = override_value; } - if let Some(override_value) = gas_price_params.override_l1_data_gas_price { - info!("Overriding L1 data gas price to {override_value}"); + if let Some(override_value) = gas_price_params.override_l1_data_gas_price_wei { + info!("Overriding L1 data gas price to {override_value} wei"); return_values.1.blob_fee = override_value; } + if let Some(override_value) = gas_price_params.override_eth_to_fri_rate { + info!("Overriding conversion rate to {override_value}"); + return_values.0 = override_value; + } + return_values } @@ -246,7 +255,8 @@ pub(crate) fn make_gas_price_params(config: &ContextConfig) -> GasPriceParams { max_l1_data_gas_price_wei: GasPrice(config.max_l1_data_gas_price_wei), l1_data_gas_price_multiplier: Ratio::new(config.l1_data_gas_price_multiplier_ppt, 1000), l1_gas_tip_wei: GasPrice(config.l1_gas_tip_wei), - override_l1_gas_price: config.override_l1_gas_price.map(GasPrice), - override_l1_data_gas_price: config.override_l1_data_gas_price.map(GasPrice), + override_l1_gas_price_wei: config.override_l1_gas_price_wei.map(GasPrice), + override_l1_data_gas_price_wei: config.override_l1_data_gas_price_wei.map(GasPrice), + override_eth_to_fri_rate: config.override_eth_to_fri_rate, } } diff --git a/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs b/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs index 0a4b54c15ec..6607bc1e4ea 100644 --- a/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs +++ b/crates/apollo_consensus_orchestrator/src/validate_proposal_test.rs @@ -125,7 +125,7 @@ async fn validate_proposal_success() { let (mut proposal_args, mut content_sender) = create_proposal_validate_arguments(); let n_executed = 1; // Setup deps to validate the block. - proposal_args.deps.setup_deps_for_validate(BlockNumber(0), n_executed); + proposal_args.deps.setup_deps_for_validate(BlockNumber(0), n_executed, 1); // Send a valid block info. let block_info = block_info(BlockNumber(0)); content_sender.send(ProposalPart::BlockInfo(block_info)).await.unwrap(); diff --git a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json index 8a8353953ac..706f2db5fd8 100644 --- a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json +++ b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json @@ -16,12 +16,14 @@ "consensus_manager_config.context_config.block_timestamp_window_seconds": 1, "consensus_manager_config.context_config.build_proposal_margin_millis": 1000, "consensus_manager_config.context_config.builder_address": "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", - "consensus_manager_config.context_config.override_l2_gas_price": 0, - "consensus_manager_config.context_config.override_l1_gas_price": 0, - "consensus_manager_config.context_config.override_l1_data_gas_price": 0, - "consensus_manager_config.context_config.override_l2_gas_price.#is_none": true, - "consensus_manager_config.context_config.override_l1_gas_price.#is_none": true, - "consensus_manager_config.context_config.override_l1_data_gas_price.#is_none": true, + "consensus_manager_config.context_config.override_eth_to_fri_rate": 0, + "consensus_manager_config.context_config.override_eth_to_fri_rate.#is_none": true, + "consensus_manager_config.context_config.override_l1_data_gas_price_wei": 0, + "consensus_manager_config.context_config.override_l1_data_gas_price_wei.#is_none": true, + "consensus_manager_config.context_config.override_l1_gas_price_wei": 0, + "consensus_manager_config.context_config.override_l1_gas_price_wei.#is_none": true, + "consensus_manager_config.context_config.override_l2_gas_price_fri": 0, + "consensus_manager_config.context_config.override_l2_gas_price_fri.#is_none": true, "consensus_manager_config.context_config.l1_da_mode": true, "consensus_manager_config.context_config.l1_data_gas_price_multiplier_ppt": 135, "consensus_manager_config.context_config.l1_gas_tip_wei": 1000000000, diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 08159ced458..15580ec3de2 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -1529,32 +1529,42 @@ "privacy": "Public", "value": 1 }, - "consensus_manager_config.context_config.override_l1_data_gas_price": { - "description": "Replace the L1 data gas price with this value.", + "consensus_manager_config.context_config.override_eth_to_fri_rate": { + "description": "Replace the Eth-to-Fri conversion rate with this value.", "privacy": "Public", "value": 0 }, - "consensus_manager_config.context_config.override_l1_data_gas_price.#is_none": { + "consensus_manager_config.context_config.override_eth_to_fri_rate.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", "value": true }, - "consensus_manager_config.context_config.override_l1_gas_price": { - "description": "Replace the L1 gas price with this value.", + "consensus_manager_config.context_config.override_l1_data_gas_price_wei": { + "description": "Replace the L1 data gas price (wei) with this value.", "privacy": "Public", "value": 0 }, - "consensus_manager_config.context_config.override_l1_gas_price.#is_none": { + "consensus_manager_config.context_config.override_l1_data_gas_price_wei.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", "value": true }, - "consensus_manager_config.context_config.override_l2_gas_price": { - "description": "Replace the L2 gas price with this value.", + "consensus_manager_config.context_config.override_l1_gas_price_wei": { + "description": "Replace the L1 gas price (wei) with this value.", "privacy": "Public", "value": 0 }, - "consensus_manager_config.context_config.override_l2_gas_price.#is_none": { + "consensus_manager_config.context_config.override_l1_gas_price_wei.#is_none": { + "description": "Flag for an optional field.", + "privacy": "TemporaryValue", + "value": true + }, + "consensus_manager_config.context_config.override_l2_gas_price_fri": { + "description": "Replace the L2 gas price (fri) with this value.", + "privacy": "Public", + "value": 0 + }, + "consensus_manager_config.context_config.override_l2_gas_price_fri.#is_none": { "description": "Flag for an optional field.", "privacy": "TemporaryValue", "value": true diff --git a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap index 8135712f321..9e517dfe582 100644 --- a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap +++ b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap @@ -245,38 +245,50 @@ expression: dumped_default_config }, "privacy": "Public" }, - "context.override_l1_data_gas_price": { - "description": "Replace the L1 data gas price with this value.", + "context.override_eth_to_fri_rate": { + "description": "Replace the Eth-to-Fri conversion rate with this value.", "value": { "$serde_json::private::Number": "0" }, "privacy": "Public" }, - "context.override_l1_data_gas_price.#is_none": { + "context.override_eth_to_fri_rate.#is_none": { "description": "Flag for an optional field.", "value": true, "privacy": "TemporaryValue" }, - "context.override_l1_gas_price": { - "description": "Replace the L1 gas price with this value.", + "context.override_l1_data_gas_price_wei": { + "description": "Replace the L1 data gas price (wei) with this value.", "value": { "$serde_json::private::Number": "0" }, "privacy": "Public" }, - "context.override_l1_gas_price.#is_none": { + "context.override_l1_data_gas_price_wei.#is_none": { "description": "Flag for an optional field.", "value": true, "privacy": "TemporaryValue" }, - "context.override_l2_gas_price": { - "description": "Replace the L2 gas price with this value.", + "context.override_l1_gas_price_wei": { + "description": "Replace the L1 gas price (wei) with this value.", "value": { "$serde_json::private::Number": "0" }, "privacy": "Public" }, - "context.override_l2_gas_price.#is_none": { + "context.override_l1_gas_price_wei.#is_none": { + "description": "Flag for an optional field.", + "value": true, + "privacy": "TemporaryValue" + }, + "context.override_l2_gas_price_fri": { + "description": "Replace the L2 gas price (fri) with this value.", + "value": { + "$serde_json::private::Number": "0" + }, + "privacy": "Public" + }, + "context.override_l2_gas_price_fri.#is_none": { "description": "Flag for an optional field.", "value": true, "privacy": "TemporaryValue" From 050880eacde7f002f90267a1e7bebbbd40932578 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 23 Oct 2025 15:01:23 +0300 Subject: [PATCH 124/313] infra: bump workspace version (#9740) --- Cargo.lock | 206 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 30 ++++---- 2 files changed, 118 insertions(+), 118 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6832b59b597..7adf56433f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -799,7 +799,7 @@ checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "apollo_batcher" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_batcher_config", "apollo_batcher_types", @@ -845,7 +845,7 @@ dependencies = [ [[package]] name = "apollo_batcher_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_storage", @@ -857,7 +857,7 @@ dependencies = [ [[package]] name = "apollo_batcher_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -878,7 +878,7 @@ dependencies = [ [[package]] name = "apollo_central_sync" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_central_sync_config", "apollo_class_manager_types", @@ -913,7 +913,7 @@ dependencies = [ [[package]] name = "apollo_central_sync_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_starknet_client", @@ -925,7 +925,7 @@ dependencies = [ [[package]] name = "apollo_class_manager" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_class_manager_config", "apollo_class_manager_types", @@ -948,7 +948,7 @@ dependencies = [ [[package]] name = "apollo_class_manager_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_storage", @@ -959,7 +959,7 @@ dependencies = [ [[package]] name = "apollo_class_manager_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_compile_to_casm_types", "apollo_infra", @@ -982,7 +982,7 @@ dependencies = [ [[package]] name = "apollo_compilation_utils" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra_utils", "assert_matches", @@ -1001,7 +1001,7 @@ dependencies = [ [[package]] name = "apollo_compile_to_casm" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_compilation_utils", "apollo_compile_to_casm_types", @@ -1023,7 +1023,7 @@ dependencies = [ [[package]] name = "apollo_compile_to_casm_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -1042,7 +1042,7 @@ dependencies = [ [[package]] name = "apollo_compile_to_native" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_compilation_utils", "apollo_compile_to_native_types", @@ -1058,7 +1058,7 @@ dependencies = [ [[package]] name = "apollo_compile_to_native_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1067,7 +1067,7 @@ dependencies = [ [[package]] name = "apollo_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra_utils", "apollo_test_utils", @@ -1089,7 +1089,7 @@ dependencies = [ [[package]] name = "apollo_config_manager" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_config_manager_config", @@ -1109,7 +1109,7 @@ dependencies = [ [[package]] name = "apollo_config_manager_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1118,7 +1118,7 @@ dependencies = [ [[package]] name = "apollo_config_manager_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_consensus_config", "apollo_infra", @@ -1136,7 +1136,7 @@ dependencies = [ [[package]] name = "apollo_consensus" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_consensus_config", "apollo_infra_utils", @@ -1167,7 +1167,7 @@ dependencies = [ [[package]] name = "apollo_consensus_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_protobuf", @@ -1178,7 +1178,7 @@ dependencies = [ [[package]] name = "apollo_consensus_manager" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_batcher_types", "apollo_class_manager_types", @@ -1207,7 +1207,7 @@ dependencies = [ [[package]] name = "apollo_consensus_manager_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_consensus_config", @@ -1221,7 +1221,7 @@ dependencies = [ [[package]] name = "apollo_consensus_orchestrator" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_batcher", "apollo_batcher_types", @@ -1280,7 +1280,7 @@ dependencies = [ [[package]] name = "apollo_consensus_orchestrator_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1291,7 +1291,7 @@ dependencies = [ [[package]] name = "apollo_dashboard" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_batcher", "apollo_class_manager", @@ -1325,7 +1325,7 @@ dependencies = [ [[package]] name = "apollo_deployments" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "alloy", "apollo_config", @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "apollo_gateway" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_class_manager_types", "apollo_config", @@ -1400,7 +1400,7 @@ dependencies = [ [[package]] name = "apollo_gateway_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_compilation_utils", "apollo_config", @@ -1415,7 +1415,7 @@ dependencies = [ [[package]] name = "apollo_gateway_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_network_types", @@ -1436,7 +1436,7 @@ dependencies = [ [[package]] name = "apollo_http_server" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_gateway_types", "apollo_http_server_config", @@ -1471,7 +1471,7 @@ dependencies = [ [[package]] name = "apollo_http_server_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1480,7 +1480,7 @@ dependencies = [ [[package]] name = "apollo_infra" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_infra_utils", @@ -1510,7 +1510,7 @@ dependencies = [ [[package]] name = "apollo_infra_utils" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_proc_macros", "assert-json-diff", @@ -1533,7 +1533,7 @@ dependencies = [ [[package]] name = "apollo_integration_tests" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "alloy", "anyhow", @@ -1603,7 +1603,7 @@ dependencies = [ [[package]] name = "apollo_l1_endpoint_monitor" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "alloy", "apollo_infra", @@ -1620,7 +1620,7 @@ dependencies = [ [[package]] name = "apollo_l1_endpoint_monitor_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1630,7 +1630,7 @@ dependencies = [ [[package]] name = "apollo_l1_endpoint_monitor_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -1646,7 +1646,7 @@ dependencies = [ [[package]] name = "apollo_l1_gas_price" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_infra", @@ -1673,7 +1673,7 @@ dependencies = [ [[package]] name = "apollo_l1_gas_price_provider_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1684,7 +1684,7 @@ dependencies = [ [[package]] name = "apollo_l1_gas_price_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -1703,7 +1703,7 @@ dependencies = [ [[package]] name = "apollo_l1_provider" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "alloy", "apollo_batcher_types", @@ -1733,7 +1733,7 @@ dependencies = [ [[package]] name = "apollo_l1_provider_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1743,7 +1743,7 @@ dependencies = [ [[package]] name = "apollo_l1_provider_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -1762,7 +1762,7 @@ dependencies = [ [[package]] name = "apollo_l1_scraper_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1772,7 +1772,7 @@ dependencies = [ [[package]] name = "apollo_mempool" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config_manager_types", "apollo_infra", @@ -1806,7 +1806,7 @@ dependencies = [ [[package]] name = "apollo_mempool_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1815,7 +1815,7 @@ dependencies = [ [[package]] name = "apollo_mempool_p2p" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_class_manager_types", "apollo_gateway_types", @@ -1839,7 +1839,7 @@ dependencies = [ [[package]] name = "apollo_mempool_p2p_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_network", @@ -1849,7 +1849,7 @@ dependencies = [ [[package]] name = "apollo_mempool_p2p_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -1866,7 +1866,7 @@ dependencies = [ [[package]] name = "apollo_mempool_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -1884,7 +1884,7 @@ dependencies = [ [[package]] name = "apollo_metrics" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "indexmap 2.11.0", "metrics 0.24.2", @@ -1899,7 +1899,7 @@ dependencies = [ [[package]] name = "apollo_monitoring_endpoint" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "apollo_infra", @@ -1926,7 +1926,7 @@ dependencies = [ [[package]] name = "apollo_monitoring_endpoint_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -1935,7 +1935,7 @@ dependencies = [ [[package]] name = "apollo_network" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_metrics", @@ -1976,7 +1976,7 @@ dependencies = [ [[package]] name = "apollo_network_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_test_utils", "lazy_static", @@ -1987,7 +1987,7 @@ dependencies = [ [[package]] name = "apollo_node" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "apollo_batcher", @@ -2033,7 +2033,7 @@ dependencies = [ [[package]] name = "apollo_node_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_batcher_config", "apollo_class_manager_config", @@ -2069,7 +2069,7 @@ dependencies = [ [[package]] name = "apollo_p2p_sync" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_class_manager_types", "apollo_network", @@ -2104,7 +2104,7 @@ dependencies = [ [[package]] name = "apollo_p2p_sync_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -2113,7 +2113,7 @@ dependencies = [ [[package]] name = "apollo_proc_macros" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "lazy_static", "proc-macro2", @@ -2123,7 +2123,7 @@ dependencies = [ [[package]] name = "apollo_proc_macros_tests" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_metrics", "apollo_proc_macros", @@ -2137,7 +2137,7 @@ dependencies = [ [[package]] name = "apollo_protobuf" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_test_utils", "bytes", @@ -2162,7 +2162,7 @@ dependencies = [ [[package]] name = "apollo_reverts" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_storage", @@ -2175,7 +2175,7 @@ dependencies = [ [[package]] name = "apollo_rpc" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "apollo_class_manager_types", @@ -2228,7 +2228,7 @@ dependencies = [ [[package]] name = "apollo_rpc_execution" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "apollo_class_manager_types", @@ -2260,7 +2260,7 @@ dependencies = [ [[package]] name = "apollo_sierra_compilation_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "serde", @@ -2269,7 +2269,7 @@ dependencies = [ [[package]] name = "apollo_signature_manager" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -2291,7 +2291,7 @@ dependencies = [ [[package]] name = "apollo_signature_manager_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -2308,7 +2308,7 @@ dependencies = [ [[package]] name = "apollo_staking" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_consensus", "apollo_state_sync_types", @@ -2326,7 +2326,7 @@ dependencies = [ [[package]] name = "apollo_starknet_client" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_test_utils", @@ -2360,7 +2360,7 @@ dependencies = [ [[package]] name = "apollo_starknet_os_program" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra_utils", "blockifier", @@ -2375,7 +2375,7 @@ dependencies = [ [[package]] name = "apollo_state_reader" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_class_manager_types", "apollo_storage", @@ -2392,7 +2392,7 @@ dependencies = [ [[package]] name = "apollo_state_sync" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_central_sync", "apollo_class_manager_types", @@ -2422,7 +2422,7 @@ dependencies = [ [[package]] name = "apollo_state_sync_config" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_central_sync_config", "apollo_config", @@ -2437,7 +2437,7 @@ dependencies = [ [[package]] name = "apollo_state_sync_metrics" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -2450,7 +2450,7 @@ dependencies = [ [[package]] name = "apollo_state_sync_types" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra", "apollo_metrics", @@ -2471,7 +2471,7 @@ dependencies = [ [[package]] name = "apollo_storage" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_metrics", @@ -2524,7 +2524,7 @@ dependencies = [ [[package]] name = "apollo_task_executor" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "futures", "rstest", @@ -2534,7 +2534,7 @@ dependencies = [ [[package]] name = "apollo_test_utils" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "cairo-lang-casm", "cairo-lang-starknet-classes", @@ -2555,7 +2555,7 @@ dependencies = [ [[package]] name = "apollo_time" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "chrono", "mockall", @@ -3322,7 +3322,7 @@ dependencies = [ [[package]] name = "bench_tools" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra_utils", "clap", @@ -3517,7 +3517,7 @@ dependencies = [ [[package]] name = "blockifier" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "apollo_compilation_utils", @@ -3576,7 +3576,7 @@ dependencies = [ [[package]] name = "blockifier_reexecution" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_gateway", "apollo_gateway_config", @@ -3603,7 +3603,7 @@ dependencies = [ [[package]] name = "blockifier_test_utils" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra_utils", "cairo-lang-starknet-classes", @@ -8745,7 +8745,7 @@ dependencies = [ [[package]] name = "mempool_test_utils" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra_utils", "assert_matches", @@ -9066,7 +9066,7 @@ dependencies = [ [[package]] name = "native_blockifier" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_compile_to_native_types", "apollo_state_reader", @@ -9632,7 +9632,7 @@ dependencies = [ [[package]] name = "papyrus_base_layer" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "alloy", "apollo_config", @@ -9660,7 +9660,7 @@ dependencies = [ [[package]] name = "papyrus_common" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_test_utils", "assert_matches", @@ -9676,7 +9676,7 @@ dependencies = [ [[package]] name = "papyrus_load_test" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "assert_matches", @@ -9694,7 +9694,7 @@ dependencies = [ [[package]] name = "papyrus_monitoring_gateway" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_config", "apollo_starknet_client", @@ -9717,7 +9717,7 @@ dependencies = [ [[package]] name = "papyrus_node" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "anyhow", "apollo_central_sync", @@ -12072,7 +12072,7 @@ dependencies = [ [[package]] name = "shared_execution_objects" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "blockifier", "rstest", @@ -12174,7 +12174,7 @@ dependencies = [ [[package]] name = "sizeof" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "size-of", "sizeof_internal", @@ -12184,14 +12184,14 @@ dependencies = [ [[package]] name = "sizeof_internal" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "starknet-types-core", ] [[package]] name = "sizeof_macro" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -12433,7 +12433,7 @@ dependencies = [ [[package]] name = "starknet_api" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra_utils", "assert_matches", @@ -12469,7 +12469,7 @@ dependencies = [ [[package]] name = "starknet_committer" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "hex", "pretty_assertions", @@ -12486,7 +12486,7 @@ dependencies = [ [[package]] name = "starknet_committer_and_os_cli" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_starknet_os_program", "assert_matches", @@ -12522,7 +12522,7 @@ dependencies = [ [[package]] name = "starknet_os" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "apollo_infra_utils", "apollo_starknet_os_program", @@ -12573,7 +12573,7 @@ dependencies = [ [[package]] name = "starknet_os_flow_tests" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "blockifier", "blockifier_test_utils", @@ -12584,7 +12584,7 @@ dependencies = [ [[package]] name = "starknet_patricia" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "async-recursion", "derive_more 0.99.20", @@ -12606,7 +12606,7 @@ dependencies = [ [[package]] name = "starknet_patricia_storage" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "hex", "serde", @@ -13381,7 +13381,7 @@ dependencies = [ [[package]] name = "toml_test_utils" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "serde", "toml 0.8.23", @@ -14637,7 +14637,7 @@ dependencies = [ [[package]] name = "workspace_tests" -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" dependencies = [ "toml_test_utils", ] diff --git a/Cargo.toml b/Cargo.toml index de11081e100..309cbbad2ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,7 +110,7 @@ members = [ ] [workspace.package] -version = "0.16.0-rc.0" +version = "0.16.0-rc.1" edition = "2021" repository = "https://github.com/starkware-libs/sequencer/" license = "Apache-2.0" @@ -127,12 +127,12 @@ apollo_central_sync_config.path = "crates/apollo_central_sync_config" apollo_class_manager.path = "crates/apollo_class_manager" apollo_class_manager_config.path = "crates/apollo_class_manager_config" apollo_class_manager_types.path = "crates/apollo_class_manager_types" -apollo_compilation_utils = { path = "crates/apollo_compilation_utils", version = "0.16.0-rc.0" } +apollo_compilation_utils = { path = "crates/apollo_compilation_utils", version = "0.16.0-rc.1" } apollo_compile_to_casm.path = "crates/apollo_compile_to_casm" apollo_compile_to_casm_types.path = "crates/apollo_compile_to_casm_types" -apollo_compile_to_native = { path = "crates/apollo_compile_to_native", version = "0.16.0-rc.0" } -apollo_compile_to_native_types = { path = "crates/apollo_compile_to_native_types", version = "0.16.0-rc.0" } -apollo_config = { path = "crates/apollo_config", version = "0.16.0-rc.0" } +apollo_compile_to_native = { path = "crates/apollo_compile_to_native", version = "0.16.0-rc.1" } +apollo_compile_to_native_types = { path = "crates/apollo_compile_to_native_types", version = "0.16.0-rc.1" } +apollo_config = { path = "crates/apollo_config", version = "0.16.0-rc.1" } apollo_config_manager.path = "crates/apollo_config_manager" apollo_config_manager_config.path = "crates/apollo_config_manager_config" apollo_config_manager_types.path = "crates/apollo_config_manager_types" @@ -150,7 +150,7 @@ apollo_gateway_types.path = "crates/apollo_gateway_types" apollo_http_server.path = "crates/apollo_http_server" apollo_http_server_config.path = "crates/apollo_http_server_config" apollo_infra.path = "crates/apollo_infra" -apollo_infra_utils = { path = "crates/apollo_infra_utils", version = "0.16.0-rc.0" } +apollo_infra_utils = { path = "crates/apollo_infra_utils", version = "0.16.0-rc.1" } apollo_integration_tests.path = "crates/apollo_integration_tests" apollo_l1_endpoint_monitor.path = "crates/apollo_l1_endpoint_monitor" apollo_l1_endpoint_monitor_config.path = "crates/apollo_l1_endpoint_monitor_config" @@ -168,7 +168,7 @@ apollo_mempool_p2p.path = "crates/apollo_mempool_p2p" apollo_mempool_p2p_config.path = "crates/apollo_mempool_p2p_config" apollo_mempool_p2p_types.path = "crates/apollo_mempool_p2p_types" apollo_mempool_types.path = "crates/apollo_mempool_types" -apollo_metrics = { path = "crates/apollo_metrics", version = "0.16.0-rc.0" } +apollo_metrics = { path = "crates/apollo_metrics", version = "0.16.0-rc.1" } apollo_monitoring_endpoint.path = "crates/apollo_monitoring_endpoint" apollo_monitoring_endpoint_config.path = "crates/apollo_monitoring_endpoint_config" apollo_network.path = "crates/apollo_network" @@ -177,7 +177,7 @@ apollo_node.path = "crates/apollo_node" apollo_node_config.path = "crates/apollo_node_config" apollo_p2p_sync.path = "crates/apollo_p2p_sync" apollo_p2p_sync_config.path = "crates/apollo_p2p_sync_config" -apollo_proc_macros = { path = "crates/apollo_proc_macros", version = "0.16.0-rc.0" } +apollo_proc_macros = { path = "crates/apollo_proc_macros", version = "0.16.0-rc.1" } apollo_proc_macros_tests.path = "crates/apollo_proc_macros_tests" apollo_protobuf.path = "crates/apollo_protobuf" apollo_reverts.path = "crates/apollo_reverts" @@ -188,7 +188,7 @@ apollo_signature_manager.path = "crates/apollo_signature_manager" apollo_signature_manager_types.path = "crates/apollo_signature_manager_types" apollo_staking.path = "crates/apollo_staking" apollo_starknet_client.path = "crates/apollo_starknet_client" -apollo_starknet_os_program = { path = "crates/apollo_starknet_os_program", version = "0.16.0-rc.0" } +apollo_starknet_os_program = { path = "crates/apollo_starknet_os_program", version = "0.16.0-rc.1" } apollo_state_reader.path = "crates/apollo_state_reader" apollo_state_sync.path = "crates/apollo_state_sync" apollo_state_sync_config.path = "crates/apollo_state_sync_config" @@ -217,9 +217,9 @@ bincode = "1.3.3" bisection = "0.1.0" bitvec = "1.0.1" blake2 = "0.10.6" -blockifier = { path = "crates/blockifier", version = "0.16.0-rc.0" } +blockifier = { path = "crates/blockifier", version = "0.16.0-rc.1" } blockifier_reexecution.path = "crates/blockifier_reexecution" -blockifier_test_utils = { path = "crates/blockifier_test_utils", version = "0.16.0-rc.0" } +blockifier_test_utils = { path = "crates/blockifier_test_utils", version = "0.16.0-rc.1" } byteorder = "1.4.3" bytes = "1" c-kzg = "1.0.3" @@ -340,14 +340,14 @@ sha2 = "0.10.8" sha3 = "0.10.8" shared_execution_objects.path = "crates/shared_execution_objects" simple_logger = "4.0.0" -sizeof = { path = "crates/sizeof", version = "0.16.0-rc.0" } -sizeof_internal = { path = "crates/sizeof/sizeof_internal", version = "0.16.0-rc.0" } -sizeof_macro = { path = "crates/sizeof/sizeof_macro", version = "0.16.0-rc.0" } +sizeof = { path = "crates/sizeof", version = "0.16.0-rc.1" } +sizeof_internal = { path = "crates/sizeof/sizeof_internal", version = "0.16.0-rc.1" } +sizeof_macro = { path = "crates/sizeof/sizeof_macro", version = "0.16.0-rc.1" } socket2 = "0.5.8" starknet-core = "0.16.0" starknet-crypto = "0.8.1" starknet-types-core = "=0.2.3" -starknet_api = { path = "crates/starknet_api", version = "0.16.0-rc.0" } +starknet_api = { path = "crates/starknet_api", version = "0.16.0-rc.1" } starknet_committer.path = "crates/starknet_committer" starknet_committer_and_os_cli.path = "crates/starknet_committer_and_os_cli" starknet_os.path = "crates/starknet_os" From 1117aaeccf1df35991e8fab9a9b39ea79ff68a7d Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 23 Oct 2025 15:16:34 +0300 Subject: [PATCH 125/313] apollo_consensus_orchestrator: block info validation override l2 gas price (#9729) (#9737) --- .../src/sequencer_consensus_context.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs index ab6de793994..2fe7aee87ae 100644 --- a/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs +++ b/crates/apollo_consensus_orchestrator/src/sequencer_consensus_context.rs @@ -332,7 +332,11 @@ impl ConsensusContext for SequencerConsensusContext { block_timestamp_window_seconds: self.config.block_timestamp_window_seconds, previous_block_info: self.previous_block_info.clone(), l1_da_mode: self.l1_da_mode, - l2_gas_price_fri: self.l2_gas_price, + l2_gas_price_fri: self + .config + .override_l2_gas_price_fri + .map(GasPrice) + .unwrap_or(self.l2_gas_price), }; self.validate_current_round_proposal( block_info_validation, From 528c205736433a269e8309c77344e4d0a1198b8b Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 23 Oct 2025 15:17:49 +0300 Subject: [PATCH 126/313] apollo_dashboard: add time since last scrape panels and remove last scrape metric (#9642) --- .../resources/dev_grafana.json | 33 ++++++++++++++++--- crates/apollo_dashboard/src/dashboard.rs | 11 +++++++ .../src/panels/l1_gas_price.rs | 28 +++++++++++++++- .../src/panels/l1_provider.rs | 14 +++++--- crates/apollo_l1_provider/src/l1_scraper.rs | 11 ------- crates/apollo_l1_provider/src/metrics.rs | 2 -- 6 files changed, 77 insertions(+), 22 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 787aa28c6ab..c1408a16b73 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -742,13 +742,16 @@ "L1 Provider": { "panels": [ { - "title": "l1_message_scraper_seconds_since_last_successful_scrape", - "description": "Number of seconds since the last successful scrape of the L1 message scraper", + "title": "Seconds since last successful l1 event scrape", + "description": "The number of seconds since the last successful scrape of the L1 message scraper (assuming there was a scrape in the last 12 hours)", "type": "timeseries", "exprs": [ - "l1_message_scraper_seconds_since_last_successful_scrape{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + "time() - max_over_time((timestamp(increase(l1_message_scraper_success_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}[12h])) != 0))[12h:])" ], - "extra_params": {} + "extra_params": { + "unit": "s", + "log_query": "\"BaseLayerError during scraping\"" + } }, { "title": "L1 Message Scraper Success Count", @@ -782,6 +785,28 @@ }, "ETH→STRK Rate & L1 Gas Price": { "panels": [ + { + "title": "Seconds since last successful L1 gas price scrape", + "description": "The number of seconds since the last successful scrape of the L1 gas price scraper (assuming there was a scrape in the last 12 hours)", + "type": "timeseries", + "exprs": [ + "time() - max_over_time((timestamp(increase(l1_gas_price_scraper_success_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}[12h])) != 0))[12h:])" + ], + "extra_params": { + "unit": "s" + } + }, + { + "title": "Seconds since last successful ETH→STRK rate update", + "description": "The number of seconds since the last successful ETH→STRK rate update (assuming there was an update in the last 12 hours)", + "type": "timeseries", + "exprs": [ + "time() - max_over_time((timestamp(increase(eth_to_strk_success_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}[12h])) != 0))[12h:])" + ], + "extra_params": { + "unit": "s" + } + }, { "title": "ETH→STRK Rate Query Success (binary)", "description": "Indicates whether the ETH→STRK rate query succeeded (1m window) \nExpected to be 1 every 15 minutes.", diff --git a/crates/apollo_dashboard/src/dashboard.rs b/crates/apollo_dashboard/src/dashboard.rs index fc17b161958..51a502e3ebd 100644 --- a/crates/apollo_dashboard/src/dashboard.rs +++ b/crates/apollo_dashboard/src/dashboard.rs @@ -586,3 +586,14 @@ pub(crate) fn get_component_infra_row(row_name: &'static str, metrics: &InfraMet Row::new(row_name, panels) } + +/// Returns a PromQL expression that calculates the time since the last increase of the given +/// metric. Assumes there was an increase in the last 12 hours. +pub(crate) fn get_time_since_last_increase_expr(metric_name: &str) -> String { + const TIME_RANGE: &str = "12h"; + format!( + // The max over time is the timestamp of the last increase in the last 12 hours. + "time() - max_over_time((timestamp(increase({metric_name}[{TIME_RANGE}])) != \ + 0))[{TIME_RANGE}:])" + ) +} diff --git a/crates/apollo_dashboard/src/panels/l1_gas_price.rs b/crates/apollo_dashboard/src/panels/l1_gas_price.rs index 89796bb324c..11780251c1b 100644 --- a/crates/apollo_dashboard/src/panels/l1_gas_price.rs +++ b/crates/apollo_dashboard/src/panels/l1_gas_price.rs @@ -12,7 +12,7 @@ use apollo_l1_gas_price::metrics::{ }; use apollo_l1_gas_price_types::DEFAULT_ETH_TO_FRI_RATE; -use crate::dashboard::{Panel, PanelType, Row}; +use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; fn get_panel_eth_to_strk_error_count() -> Panel { Panel::new( @@ -23,6 +23,17 @@ fn get_panel_eth_to_strk_error_count() -> Panel { ) } +fn get_panel_eth_to_strk_seconds_since_last_successful_update() -> Panel { + Panel::new( + "Seconds since last successful ETH→STRK rate update", + "The number of seconds since the last successful ETH→STRK rate update (assuming there was \ + an update in the last 12 hours)", + vec![get_time_since_last_increase_expr(Ð_TO_STRK_SUCCESS_COUNT.get_name_with_filter())], + PanelType::TimeSeries, + ) + .with_unit(Unit::Seconds) +} + fn get_panel_eth_to_strk_success_count() -> Panel { Panel::new( "ETH→STRK Rate Query Success (binary)", @@ -97,6 +108,19 @@ fn get_panel_l1_gas_price_scraper_reorg_detected() -> Panel { ) } +fn get_panel_l1_gas_price_scraper_seconds_since_last_successful_scrape() -> Panel { + Panel::new( + "Seconds since last successful L1 gas price scrape", + "The number of seconds since the last successful scrape of the L1 gas price scraper \ + (assuming there was a scrape in the last 12 hours)", + vec![get_time_since_last_increase_expr( + &L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT.get_name_with_filter(), + )], + PanelType::TimeSeries, + ) + .with_unit(Unit::Seconds) +} + fn get_panel_l1_gas_price_scraper_latest_scraped_block() -> Panel { Panel::new( "L1 Gas Price Scraper Latest Scraped Block", @@ -128,6 +152,8 @@ pub(crate) fn get_l1_gas_price_row() -> Row { Row::new( "ETH→STRK Rate & L1 Gas Price", vec![ + get_panel_l1_gas_price_scraper_seconds_since_last_successful_scrape(), + get_panel_eth_to_strk_seconds_since_last_successful_update(), get_panel_eth_to_strk_success_count(), get_panel_eth_to_strk_error_count(), get_panel_eth_to_strk_rate(), diff --git a/crates/apollo_dashboard/src/panels/l1_provider.rs b/crates/apollo_dashboard/src/panels/l1_provider.rs index 49efa399896..2f202769e05 100644 --- a/crates/apollo_dashboard/src/panels/l1_provider.rs +++ b/crates/apollo_dashboard/src/panels/l1_provider.rs @@ -1,11 +1,10 @@ use apollo_l1_provider::metrics::{ L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT, L1_MESSAGE_SCRAPER_REORG_DETECTED, - L1_MESSAGE_SCRAPER_SECONDS_SINCE_LAST_SUCCESSFUL_SCRAPE, L1_MESSAGE_SCRAPER_SUCCESS_COUNT, }; -use crate::dashboard::{Panel, PanelType, Row}; +use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; fn get_panel_l1_message_scraper_success_count() -> Panel { Panel::new( @@ -40,10 +39,17 @@ fn get_panel_l1_message_scraper_reorg_detected() -> Panel { ) } fn get_panel_l1_message_scraper_seconds_since_last_successful_scrape() -> Panel { - Panel::from_gauge( - &L1_MESSAGE_SCRAPER_SECONDS_SINCE_LAST_SUCCESSFUL_SCRAPE, + Panel::new( + "Seconds since last successful l1 event scrape", + "The number of seconds since the last successful scrape of the L1 message scraper \ + (assuming there was a scrape in the last 12 hours)", + vec![get_time_since_last_increase_expr( + &L1_MESSAGE_SCRAPER_SUCCESS_COUNT.get_name_with_filter(), + )], PanelType::TimeSeries, ) + .with_unit(Unit::Seconds) + .with_log_query("BaseLayerError during scraping") } // TODO(noamsp): rename to l1_event_row diff --git a/crates/apollo_l1_provider/src/l1_scraper.rs b/crates/apollo_l1_provider/src/l1_scraper.rs index 7ee54e9df53..262c73defaa 100644 --- a/crates/apollo_l1_provider/src/l1_scraper.rs +++ b/crates/apollo_l1_provider/src/l1_scraper.rs @@ -21,7 +21,6 @@ use crate::metrics::{ register_scraper_metrics, L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT, L1_MESSAGE_SCRAPER_REORG_DETECTED, - L1_MESSAGE_SCRAPER_SECONDS_SINCE_LAST_SUCCESSFUL_SCRAPE, L1_MESSAGE_SCRAPER_SUCCESS_COUNT, }; @@ -41,7 +40,6 @@ pub struct L1Scraper { pub l1_provider_client: SharedL1ProviderClient, tracked_event_identifiers: Vec, pub clock: Arc, - last_successful_scrape_timestamp: Option, } impl L1Scraper { @@ -59,7 +57,6 @@ impl L1Scraper { config, tracked_event_identifiers: events_identifiers_to_track.to_vec(), clock: Arc::new(DefaultClock), - last_successful_scrape_timestamp: None, }) } @@ -210,18 +207,10 @@ impl L1Scraper { warn!("BaseLayerError during scraping: {e:?}"); } Ok(_) => { - self.last_successful_scrape_timestamp = Some(self.clock.unix_now()); L1_MESSAGE_SCRAPER_SUCCESS_COUNT.increment(1); } Err(e) => return Err(e), } - - // Can reach this if Ok or if baselayer error. Other cases would return Err, crashing - // the node. - if let Some(last_successful_scrape_timestamp) = self.last_successful_scrape_timestamp { - L1_MESSAGE_SCRAPER_SECONDS_SINCE_LAST_SUCCESSFUL_SCRAPE - .set_lossy(self.clock.unix_now() - last_successful_scrape_timestamp); - } } } diff --git a/crates/apollo_l1_provider/src/metrics.rs b/crates/apollo_l1_provider/src/metrics.rs index e95d0e9b5e0..28cea92e910 100644 --- a/crates/apollo_l1_provider/src/metrics.rs +++ b/crates/apollo_l1_provider/src/metrics.rs @@ -15,7 +15,6 @@ define_metrics!( MetricCounter { L1_MESSAGE_SCRAPER_SUCCESS_COUNT, "l1_message_scraper_success_count", "Number of times the L1 message scraper successfully scraped messages and updated the provider", init=0 }, MetricCounter { L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT, "l1_message_scraper_baselayer_error_count", "Number of times the L1 message scraper encountered an error while scraping the base layer", init=0}, MetricCounter { L1_MESSAGE_SCRAPER_REORG_DETECTED, "l1_message_scraper_reorg_detected", "Number of times the L1 message scraper detected a reorganization in the base layer", init=0}, - MetricGauge { L1_MESSAGE_SCRAPER_SECONDS_SINCE_LAST_SUCCESSFUL_SCRAPE, "l1_message_scraper_seconds_since_last_successful_scrape", "Number of seconds since the last successful scrape of the L1 message scraper"}, }, ); @@ -23,5 +22,4 @@ pub(crate) fn register_scraper_metrics() { L1_MESSAGE_SCRAPER_SUCCESS_COUNT.register(); L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT.register(); L1_MESSAGE_SCRAPER_REORG_DETECTED.register(); - L1_MESSAGE_SCRAPER_SECONDS_SINCE_LAST_SUCCESSFUL_SCRAPE.register(); } From 75f8696038b2e8539ed430ad866004493eec073e Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:11:09 +0300 Subject: [PATCH 127/313] apollo_deployments: have 0 retries when core tries to communicate with l1 (#9745) --- crates/apollo_deployments/resources/services/hybrid/core.json | 4 ++-- crates/apollo_deployments/src/deployments.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/apollo_deployments/resources/services/hybrid/core.json b/crates/apollo_deployments/resources/services/hybrid/core.json index df25418f58c..7eda57444f6 100644 --- a/crates/apollo_deployments/resources/services/hybrid/core.json +++ b/crates/apollo_deployments/resources/services/hybrid/core.json @@ -58,7 +58,7 @@ "components.l1_gas_price_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_gas_price_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_gas_price_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_gas_price_provider.remote_client_config.retries": 2, + "components.l1_gas_price_provider.remote_client_config.retries": 0, "components.l1_gas_price_provider.url": "sequencer-l1-service", "components.l1_gas_price_scraper.execution_mode": "Disabled", "components.l1_provider.execution_mode": "Remote", @@ -72,7 +72,7 @@ "components.l1_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_provider.remote_client_config.retries": 2, + "components.l1_provider.remote_client_config.retries": 0, "components.l1_provider.url": "sequencer-l1-service", "components.l1_scraper.execution_mode": "Disabled", "components.mempool.execution_mode": "Remote", diff --git a/crates/apollo_deployments/src/deployments.rs b/crates/apollo_deployments/src/deployments.rs index 634a0673099..a67b821b43a 100644 --- a/crates/apollo_deployments/src/deployments.rs +++ b/crates/apollo_deployments/src/deployments.rs @@ -3,4 +3,4 @@ pub mod distributed; pub mod hybrid; pub(crate) const IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES: usize = 0; -pub(crate) const RETRIES_FOR_L1_SERVICES: usize = 2; +pub(crate) const RETRIES_FOR_L1_SERVICES: usize = 0; From 10ce87b6edbd4a8aa495f14f9ea91e72abe8edc1 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 23 Oct 2025 20:41:41 +0300 Subject: [PATCH 128/313] blockifier: fix the description of max_n_events (#9690) --- crates/apollo_node/resources/config_schema.json | 6 +++--- crates/blockifier/src/blockifier_versioned_constants.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 77eaa6a99ae..f7ddfe8eb9c 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -155,7 +155,7 @@ "privacy": "Public" }, "batcher_config.block_builder_config.versioned_constants_overrides.max_n_events": { - "description": "Maximum number of events that can be emitted from the transation.", + "description": "Maximum number of events that can be emitted from the transaction.", "pointer_target": "versioned_constants_overrides.max_n_events", "privacy": "Public" }, @@ -1865,7 +1865,7 @@ "privacy": "Public" }, "gateway_config.stateful_tx_validator_config.versioned_constants_overrides.max_n_events": { - "description": "Maximum number of events that can be emitted from the transation.", + "description": "Maximum number of events that can be emitted from the transaction.", "pointer_target": "versioned_constants_overrides.max_n_events", "privacy": "Public" }, @@ -2745,7 +2745,7 @@ "value": 10000000 }, "versioned_constants_overrides.max_n_events": { - "description": "Maximum number of events that can be emitted from the transation.", + "description": "Maximum number of events that can be emitted from the transaction.", "privacy": "TemporaryValue", "value": 1000 }, diff --git a/crates/blockifier/src/blockifier_versioned_constants.rs b/crates/blockifier/src/blockifier_versioned_constants.rs index 8e8513257ca..a673a74fe3e 100644 --- a/crates/blockifier/src/blockifier_versioned_constants.rs +++ b/crates/blockifier/src/blockifier_versioned_constants.rs @@ -1392,7 +1392,7 @@ impl SerializeConfig for VersionedConstantsOverrides { ser_param( "max_n_events", &self.max_n_events, - "Maximum number of events that can be emitted from the transation.", + "Maximum number of events that can be emitted from the transaction.", ParamPrivacyInput::Public, ), ]) From 5d93524a7fcd6dfa68a8015c75ec07003d906990 Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Sat, 25 Oct 2025 11:10:54 +0300 Subject: [PATCH 129/313] apollo_dashboard: show as stat and use increase over range for consensus P2P metrics (#9666) --- .../resources/dev_grafana.json | 58 +++--- .../apollo_dashboard/src/panels/consensus.rs | 173 ++++++++++-------- .../src/panels/l1_gas_price.rs | 2 +- 3 files changed, 131 insertions(+), 102 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index c1408a16b73..7f5e4a902f6 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -828,7 +828,7 @@ "extra_params": {} }, { - "title": "eth_to_strk_rate", + "title": "ETH→STRK rate", "description": "ETH→STRK rate (divided by DEFAULT_ETH_TO_FRI_RATE=1000000000000000000000)", "type": "timeseries", "exprs": [ @@ -1010,7 +1010,7 @@ { "title": "Number of Connected Peers", "description": "The number of connected peers in Consensus P2P", - "type": "timeseries", + "type": "stat", "exprs": [ "apollo_consensus_num_connected_peers{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], @@ -1018,73 +1018,73 @@ }, { "title": "Consensus Votes Number of Sent Messages", - "description": "The increase in the number of vote messages sent by consensus p2p (10m window)", - "type": "timeseries", + "description": "The increase in the number of vote messages sent by consensus p2p (over the selected time range)", + "type": "stat", "exprs": [ - "increase(apollo_consensus_votes_num_sent_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + "increase(apollo_consensus_votes_num_sent_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])" ], "extra_params": {} }, { "title": "Consensus Votes Number of Received Messages", - "description": "The increase in the number of vote messages received by consensus p2p (10m window)", - "type": "timeseries", + "description": "The increase in the number of vote messages received by consensus p2p (over the selected time range)", + "type": "stat", "exprs": [ - "increase(apollo_consensus_votes_num_received_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + "increase(apollo_consensus_votes_num_received_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])" ], "extra_params": {} }, { - "title": "apollo_consensus_votes_num_dropped_messages", - "description": "The number of messages dropped by the consensus p2p component over the Votes topic", - "type": "timeseries", + "title": "Consensus Votes Dropped Messages By Reason", + "description": "The number of dropped consensus votes messages, by reason (over the selected time range)", + "type": "stat", "exprs": [ - "sum by (drop_reason) (apollo_consensus_votes_num_dropped_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"})" + "sum by (drop_reason) (increase(apollo_consensus_votes_num_dropped_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) > 0" ], "extra_params": {} }, { "title": "Consensus Conflicting Votes", - "description": "The increase in the number of conflicting votes (12h window)", - "type": "timeseries", + "description": "The increase in the number of conflicting votes (over the selected time range)", + "type": "stat", "exprs": [ - "increase(consensus_conflicting_votes{cluster=~\"$cluster\", namespace=~\"$namespace\"}[12h])" + "increase(consensus_conflicting_votes{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])" ], "extra_params": {} }, { "title": "Consensus Proposals Number of Sent Messages", - "description": "The increase in the number of proposal messages sent by consensus p2p (10m window)", - "type": "timeseries", + "description": "The increase in the number of proposal messages sent by consensus p2p (over the selected time range)", + "type": "stat", "exprs": [ - "increase(apollo_consensus_proposals_num_sent_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + "increase(apollo_consensus_proposals_num_sent_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])" ], "extra_params": {} }, { "title": "Consensus Proposals Number of Received Messages", - "description": "The increase in the number of proposal messages received by consensus p2p (10m window)", - "type": "timeseries", + "description": "The increase in the number of proposal messages received by consensus p2p (over the selected time range)", + "type": "stat", "exprs": [ - "increase(apollo_consensus_proposals_num_received_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + "increase(apollo_consensus_proposals_num_received_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])" ], "extra_params": {} }, { - "title": "apollo_consensus_proposals_num_dropped_messages", - "description": "The number of messages dropped by the consensus p2p component over the Proposals topic", - "type": "timeseries", + "title": "Consensus Proposals Dropped Messages By Reason", + "description": "The number of dropped consensus proposals messages, by reason (over the selected time range)", + "type": "stat", "exprs": [ - "sum by (drop_reason) (apollo_consensus_proposals_num_dropped_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"})" + "sum by (drop_reason) (increase(apollo_consensus_proposals_num_dropped_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) > 0" ], "extra_params": {} }, { - "title": "apollo_consensus_network_events", - "description": "Network events counter by event type for consensus", - "type": "timeseries", + "title": "Consensus Network Events By Type", + "description": "Network events received by consensus p2p, by event type (over the selected time range)", + "type": "stat", "exprs": [ - "sum by (event_type) (apollo_consensus_network_events{cluster=~\"$cluster\", namespace=~\"$namespace\"})" + "sum by (event_type) (increase(apollo_consensus_network_events{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) > 0" ], "extra_params": {} } diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 53ac6220881..b8a84d01fdc 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -77,6 +77,7 @@ pub(crate) fn get_panel_consensus_block_number_diff_from_sync() -> Panel { PanelType::TimeSeries, ) } + pub(crate) fn get_panel_consensus_round() -> Panel { Panel::new( "Consensus Round", @@ -87,6 +88,7 @@ pub(crate) fn get_panel_consensus_round() -> Panel { .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + pub(crate) fn get_panel_consensus_round_advanced() -> Panel { Panel::new( "Consensus Round Advanced", @@ -122,6 +124,7 @@ pub(crate) fn get_panel_consensus_block_time_avg() -> Panel { ) .with_unit(Unit::Seconds) } + fn get_panel_consensus_decisions_reached_by_consensus() -> Panel { Panel::new( "Decisions Reached By Consensus", @@ -135,6 +138,7 @@ fn get_panel_consensus_decisions_reached_by_consensus() -> Panel { .with_log_query("DECISION_REACHED: Decision reached for round") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + fn get_panel_consensus_decisions_reached_by_sync() -> Panel { Panel::new( "Decisions Reached By Sync", @@ -148,6 +152,7 @@ fn get_panel_consensus_decisions_reached_by_sync() -> Panel { .with_log_query("Decision learned via sync protocol.") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + fn get_panel_consensus_proposals_received() -> Panel { Panel::new( "Proposal Validation: Number of Received Proposals", @@ -156,6 +161,7 @@ fn get_panel_consensus_proposals_received() -> Panel { PanelType::TimeSeries, ) } + fn get_panel_consensus_proposals_validated() -> Panel { Panel::new( "Proposal Validation: Number of Validated Proposals", @@ -166,6 +172,7 @@ fn get_panel_consensus_proposals_validated() -> Panel { .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + fn get_panel_consensus_proposals_invalid() -> Panel { Panel::new( "Proposal Validation: Number of Invalid Proposals", @@ -176,6 +183,7 @@ fn get_panel_consensus_proposals_invalid() -> Panel { .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + fn get_panel_validate_proposal_failure() -> Panel { Panel::new( "Proposal Validation: Proposal Failure by Reason", @@ -190,6 +198,7 @@ fn get_panel_validate_proposal_failure() -> Panel { .with_log_query("PROPOSAL_FAILED: Proposal failed as validator") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + fn get_panel_consensus_build_proposal_total() -> Panel { Panel::new( "Proposal Build: Number of Proposals Started", @@ -198,6 +207,7 @@ fn get_panel_consensus_build_proposal_total() -> Panel { PanelType::TimeSeries, ) } + fn get_panel_consensus_build_proposal_failed() -> Panel { Panel::new( "Proposal Build: Number of Proposals Failed", @@ -206,6 +216,7 @@ fn get_panel_consensus_build_proposal_failed() -> Panel { PanelType::TimeSeries, ) } + fn get_panel_build_proposal_failure() -> Panel { Panel::new( "Proposal Build: Proposal Failure by Reason", @@ -220,6 +231,7 @@ fn get_panel_build_proposal_failure() -> Panel { .with_log_query("PROPOSAL_FAILED: Proposal failed as proposer") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + fn get_panel_consensus_timeouts_by_type() -> Panel { Panel::new( "Consensus Timeouts By Type", @@ -239,6 +251,7 @@ fn get_panel_consensus_timeouts_by_type() -> Panel { .with_log_query("Applying Timeout") .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } + fn get_panel_consensus_l2_gas_price() -> Panel { Panel::new( "L2 Gas Price (GFri)", @@ -247,66 +260,7 @@ fn get_panel_consensus_l2_gas_price() -> Panel { PanelType::TimeSeries, ) } -fn get_panel_consensus_num_connected_peers() -> Panel { - Panel::new( - "Number of Connected Peers", - "The number of connected peers in Consensus P2P", - vec![CONSENSUS_NUM_CONNECTED_PEERS.get_name_with_filter().to_string()], - PanelType::TimeSeries, - ) -} -fn get_panel_consensus_votes_num_sent_messages() -> Panel { - Panel::new( - "Consensus Votes Number of Sent Messages", - "The increase in the number of vote messages sent by consensus p2p (10m window)", - vec![format!( - "increase({}[10m])", - CONSENSUS_VOTES_NUM_SENT_MESSAGES.get_name_with_filter() - )], - PanelType::TimeSeries, - ) -} -fn get_panel_consensus_votes_num_received_messages() -> Panel { - Panel::new( - "Consensus Votes Number of Received Messages", - "The increase in the number of vote messages received by consensus p2p (10m window)", - vec![format!( - "increase({}[10m])", - CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES.get_name_with_filter() - )], - PanelType::TimeSeries, - ) -} -fn get_panel_consensus_proposals_num_sent_messages() -> Panel { - Panel::new( - "Consensus Proposals Number of Sent Messages", - "The increase in the number of proposal messages sent by consensus p2p (10m window)", - vec![format!( - "increase({}[10m])", - CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES.get_name_with_filter() - )], - PanelType::TimeSeries, - ) -} -fn get_panel_consensus_proposals_num_received_messages() -> Panel { - Panel::new( - "Consensus Proposals Number of Received Messages", - "The increase in the number of proposal messages received by consensus p2p (10m window)", - vec![format!( - "increase({}[10m])", - CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES.get_name_with_filter() - )], - PanelType::TimeSeries, - ) -} -fn get_panel_consensus_conflicting_votes() -> Panel { - Panel::new( - "Consensus Conflicting Votes", - "The increase in the number of conflicting votes (12h window)", - vec![format!("increase({}[12h])", CONSENSUS_CONFLICTING_VOTES.get_name_with_filter())], - PanelType::TimeSeries, - ) -} + fn get_panel_cende_last_prepared_blob_block_number() -> Panel { Panel::new( "Last Prepared Blob Block Number", @@ -316,6 +270,7 @@ fn get_panel_cende_last_prepared_blob_block_number() -> Panel { ) .with_log_query("Blob for block number") } + fn get_panel_cende_write_prev_height_blob_latency() -> Panel { Panel::from_hist( &CENDE_WRITE_PREV_HEIGHT_BLOB_LATENCY, @@ -324,6 +279,7 @@ fn get_panel_cende_write_prev_height_blob_latency() -> Panel { ) .with_unit(Unit::Seconds) } + fn get_panel_cende_write_blob_success() -> Panel { let query_expression = [ "\"Blob for block number\"", @@ -340,6 +296,7 @@ fn get_panel_cende_write_blob_success() -> Panel { ) .with_log_query(query_expression) } + fn get_panel_cende_write_blob_failure() -> Panel { Panel::new( "Write Blob Failure by Reason", @@ -353,6 +310,7 @@ fn get_panel_cende_write_blob_failure() -> Panel { ) .with_log_query("CENDE_FAILURE") } + fn get_panel_cende_write_preconfirmed_block() -> Panel { Panel::new( "Write Preconfirmed Block Success", @@ -364,42 +322,113 @@ fn get_panel_cende_write_preconfirmed_block() -> Panel { .with_log_query("write_pre_confirmed_block request succeeded.") } +fn get_panel_consensus_num_connected_peers() -> Panel { + Panel::new( + "Number of Connected Peers", + "The number of connected peers in Consensus P2P", + vec![CONSENSUS_NUM_CONNECTED_PEERS.get_name_with_filter().to_string()], + PanelType::Stat, + ) +} + +fn get_panel_consensus_votes_num_sent_messages() -> Panel { + Panel::new( + "Consensus Votes Number of Sent Messages", + "The increase in the number of vote messages sent by consensus p2p (over the selected \ + time range)", + vec![format!( + "increase({}[$__range])", + CONSENSUS_VOTES_NUM_SENT_MESSAGES.get_name_with_filter() + )], + PanelType::Stat, + ) +} + +fn get_panel_consensus_votes_num_received_messages() -> Panel { + Panel::new( + "Consensus Votes Number of Received Messages", + "The increase in the number of vote messages received by consensus p2p (over the selected \ + time range)", + vec![format!( + "increase({}[$__range])", + CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES.get_name_with_filter() + )], + PanelType::Stat, + ) +} + +fn get_panel_consensus_proposals_num_sent_messages() -> Panel { + Panel::new( + "Consensus Proposals Number of Sent Messages", + "The increase in the number of proposal messages sent by consensus p2p (over the selected \ + time range)", + vec![format!( + "increase({}[$__range])", + CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES.get_name_with_filter() + )], + PanelType::Stat, + ) +} + +fn get_panel_consensus_proposals_num_received_messages() -> Panel { + Panel::new( + "Consensus Proposals Number of Received Messages", + "The increase in the number of proposal messages received by consensus p2p (over the \ + selected time range)", + vec![format!( + "increase({}[$__range])", + CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES.get_name_with_filter() + )], + PanelType::Stat, + ) +} + +fn get_panel_consensus_conflicting_votes() -> Panel { + Panel::new( + "Consensus Conflicting Votes", + "The increase in the number of conflicting votes (over the selected time range)", + vec![format!("increase({}[$__range])", CONSENSUS_CONFLICTING_VOTES.get_name_with_filter())], + PanelType::Stat, + ) +} + fn get_panel_consensus_network_events_by_type() -> Panel { Panel::new( - CONSENSUS_NETWORK_EVENTS.get_name(), - CONSENSUS_NETWORK_EVENTS.get_description(), + "Consensus Network Events By Type", + "Network events received by consensus p2p, by event type (over the selected time range)", vec![format!( - "sum by ({}) ({})", + "sum by ({}) (increase({}[$__range])) > 0", LABEL_NAME_EVENT_TYPE, CONSENSUS_NETWORK_EVENTS.get_name_with_filter() )], - PanelType::TimeSeries, + PanelType::Stat, ) } fn get_panel_consensus_votes_dropped_messages_by_reason() -> Panel { Panel::new( - CONSENSUS_VOTES_NUM_DROPPED_MESSAGES.get_name(), - CONSENSUS_VOTES_NUM_DROPPED_MESSAGES.get_description(), + "Consensus Votes Dropped Messages By Reason", + "The number of dropped consensus votes messages, by reason (over the selected time range)", vec![format!( - "sum by ({}) ({})", + "sum by ({}) (increase({}[$__range])) > 0", LABEL_NAME_BROADCAST_DROP_REASON, CONSENSUS_VOTES_NUM_DROPPED_MESSAGES.get_name_with_filter() )], - PanelType::TimeSeries, + PanelType::Stat, ) } fn get_panel_consensus_proposals_dropped_messages_by_reason() -> Panel { Panel::new( - CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES.get_name(), - CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES.get_description(), + "Consensus Proposals Dropped Messages By Reason", + "The number of dropped consensus proposals messages, by reason (over the selected time \ + range)", vec![format!( - "sum by ({}) ({})", + "sum by ({}) (increase({}[$__range])) > 0", LABEL_NAME_BROADCAST_DROP_REASON, CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES.get_name_with_filter() )], - PanelType::TimeSeries, + PanelType::Stat, ) } diff --git a/crates/apollo_dashboard/src/panels/l1_gas_price.rs b/crates/apollo_dashboard/src/panels/l1_gas_price.rs index 11780251c1b..1fc1b87ae03 100644 --- a/crates/apollo_dashboard/src/panels/l1_gas_price.rs +++ b/crates/apollo_dashboard/src/panels/l1_gas_price.rs @@ -47,7 +47,7 @@ fn get_panel_eth_to_strk_success_count() -> Panel { fn get_panel_eth_to_strk_rate() -> Panel { Panel::new( - ETH_TO_STRK_RATE.get_name(), + "ETH→STRK rate", format!("ETH→STRK rate (divided by DEFAULT_ETH_TO_FRI_RATE={DEFAULT_ETH_TO_FRI_RATE})"), vec![format!("{} / {}", ETH_TO_STRK_RATE.get_name_with_filter(), DEFAULT_ETH_TO_FRI_RATE)], PanelType::TimeSeries, From 0bd788ff96886aff7b0b5a7df51aa32c69b2d16a Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Sun, 26 Oct 2025 09:42:20 +0200 Subject: [PATCH 130/313] apollo_batcher: make MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS configurable (#9681) --- crates/apollo_batcher/src/batcher.rs | 8 ++++++ crates/apollo_batcher/src/block_builder.rs | 9 +++---- .../apollo_batcher/src/block_builder_test.rs | 26 ++++++++++++++++++- crates/apollo_batcher/src/metrics.rs | 6 ++--- crates/apollo_batcher_config/src/config.rs | 13 ++++++++++ .../resources/app_configs/batcher_config.json | 1 + .../apollo_node/resources/config_schema.json | 5 ++++ 7 files changed, 57 insertions(+), 11 deletions(-) diff --git a/crates/apollo_batcher/src/batcher.rs b/crates/apollo_batcher/src/batcher.rs index 73da739939f..d084d8db461 100644 --- a/crates/apollo_batcher/src/batcher.rs +++ b/crates/apollo_batcher/src/batcher.rs @@ -279,6 +279,10 @@ impl Batcher { BlockBuilderExecutionParams { deadline: deadline_as_instant(propose_block_input.deadline)?, is_validator: false, + proposer_idle_detection_delay: self + .config + .block_builder_config + .proposer_idle_detection_delay_millis, }, Box::new(tx_provider), Some(output_tx_sender), @@ -362,6 +366,10 @@ impl Batcher { BlockBuilderExecutionParams { deadline: deadline_as_instant(validate_block_input.deadline)?, is_validator: true, + proposer_idle_detection_delay: self + .config + .block_builder_config + .proposer_idle_detection_delay_millis, }, Box::new(tx_provider), None, diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index cd1f286ca44..4c569a087a9 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -55,10 +55,6 @@ use crate::pre_confirmed_block_writer::{CandidateTxSender, PreconfirmedTxSender} use crate::transaction_executor::TransactionExecutorTrait; use crate::transaction_provider::{TransactionProvider, TransactionProviderError}; -/// Minimum timeout for block building before finishing due to timeout without new transactions. -// TODO(dan): Make this configurable and fix the corresponding test. -pub const MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS: u64 = 2; - #[derive(Debug, Error)] pub enum BlockBuilderError { #[error(transparent)] @@ -163,6 +159,7 @@ pub trait BlockBuilderTrait: Send { pub struct BlockBuilderExecutionParams { pub deadline: tokio::time::Instant, pub is_validator: bool, + pub proposer_idle_detection_delay: std::time::Duration, } pub struct BlockBuilder { @@ -263,7 +260,7 @@ impl BlockBuilder { info!( "No transactions are being executed and {:?} passed since block building \ started (timeout is set to {:?}), finishing block building.", - time_since_start, MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS + time_since_start, self.execution_params.proposer_idle_detection_delay, ); // TODO(Dan): extract to a function (as in record_validate_proposal_failure). crate::metrics::BLOCK_CLOSE_REASON.increment( @@ -560,7 +557,7 @@ impl BlockBuilder { }; let now = tokio::time::Instant::now(); let time_since_start = now.duration_since(self.block_building_start); - time_since_start.as_secs() >= MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS + time_since_start >= self.execution_params.proposer_idle_detection_delay } async fn sleep(&mut self) { diff --git a/crates/apollo_batcher/src/block_builder_test.rs b/crates/apollo_batcher/src/block_builder_test.rs index e017bab2bd5..663d70e32a6 100644 --- a/crates/apollo_batcher/src/block_builder_test.rs +++ b/crates/apollo_batcher/src/block_builder_test.rs @@ -59,6 +59,7 @@ const BLOCK_GENERATION_LONG_DEADLINE_SECS: u64 = 5; const TX_CHANNEL_SIZE: usize = 50; const N_CONCURRENT_TXS: usize = 3; const TX_POLLING_INTERVAL: u64 = 100; +const DEFAULT_IDLE_TIMEOUT_MS: std::time::Duration = std::time::Duration::from_millis(2000); struct TestExpectations { mock_transaction_executor: MockTransactionExecutorTrait, @@ -679,6 +680,7 @@ async fn run_build_block( is_validator: bool, abort_receiver: tokio::sync::oneshot::Receiver<()>, deadline_secs: u64, + idle_timeout_duration: std::time::Duration, ) -> BlockBuilderResult { let deadline = tokio::time::Instant::now() + tokio::time::Duration::from_secs(deadline_secs); let transaction_converter = TransactionConverter::new( @@ -695,7 +697,11 @@ async fn run_build_block( transaction_converter, N_CONCURRENT_TXS, TX_POLLING_INTERVAL, - BlockBuilderExecutionParams { deadline, is_validator }, + BlockBuilderExecutionParams { + deadline, + is_validator, + proposer_idle_detection_delay: idle_timeout_duration, + }, ); block_builder.build_block().await @@ -725,6 +731,12 @@ async fn test_build_block(#[case] test_expectations: TestExpectations) { let (output_tx_sender, output_tx_receiver) = output_channel(); let (_abort_sender, abort_receiver) = tokio::sync::oneshot::channel(); + let idle_timeout_duration = if test_expectations.expected_idle_execution_timeout_metric > 0 { + std::time::Duration::from_millis(100) + } else { + DEFAULT_IDLE_TIMEOUT_MS + }; + let result_block_artifacts = run_build_block( test_expectations.mock_transaction_executor, test_expectations.mock_tx_provider, @@ -732,6 +744,7 @@ async fn test_build_block(#[case] test_expectations: TestExpectations) { false, abort_receiver, test_expectations.deadline_secs, + idle_timeout_duration, ) .await .unwrap(); @@ -763,6 +776,7 @@ async fn test_validate_block() { true, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await .unwrap(); @@ -796,6 +810,7 @@ async fn test_validate_block_excluded_txs() { true, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await .unwrap(); @@ -827,6 +842,7 @@ async fn test_validate_block_with_error( true, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await .unwrap_err(); @@ -863,6 +879,7 @@ async fn test_validate_block_l1_handler_validation_error(#[case] status: Invalid true, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await; @@ -912,6 +929,7 @@ async fn test_build_block_abort() { false, abort_receiver, BLOCK_GENERATION_LONG_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await, Err(BlockBuilderError::Aborted) @@ -944,6 +962,7 @@ async fn test_build_block_abort_immediately() { false, abort_receiver, BLOCK_GENERATION_LONG_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await, Err(BlockBuilderError::Aborted) @@ -966,6 +985,7 @@ async fn test_l2_gas_used() { true, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await .unwrap(); @@ -996,6 +1016,7 @@ async fn test_execution_info_order() { false, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await .unwrap(); @@ -1044,6 +1065,7 @@ async fn failed_l1_handler_transaction_consumed() { false, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await .unwrap(); @@ -1107,6 +1129,7 @@ async fn partial_chunk_execution_proposer() { is_validator, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await .unwrap(); @@ -1157,6 +1180,7 @@ async fn partial_chunk_execution_validator(#[case] successful: bool) { is_validator, abort_receiver, BLOCK_GENERATION_DEADLINE_SECS, + DEFAULT_IDLE_TIMEOUT_MS, ) .await; diff --git a/crates/apollo_batcher/src/metrics.rs b/crates/apollo_batcher/src/metrics.rs index d4ca1f68115..0b0f9e6dcd6 100644 --- a/crates/apollo_batcher/src/metrics.rs +++ b/crates/apollo_batcher/src/metrics.rs @@ -58,10 +58,8 @@ pub const LABEL_NAME_BLOCK_CLOSE_REASON: &str = "block_close_reason"; pub enum BlockCloseReason { FullBlock, Deadline, - /// Block building finished because no new transactions are being executed and the minimal - /// timeout ( - /// [`MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS`](crate::block_builder::MIN_BLOCK_BUILDING_NO_NEW_TXS_TIMEOUT_SECS) - /// ) passed. + /// Block building finished because no new transactions are being executed and the configured + /// timeout passed. IdleExecutionTimeout, } diff --git a/crates/apollo_batcher_config/src/config.rs b/crates/apollo_batcher_config/src/config.rs index ad50ba101dd..e4d21402504 100644 --- a/crates/apollo_batcher_config/src/config.rs +++ b/crates/apollo_batcher_config/src/config.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; +use apollo_config::converters::deserialize_milliseconds_to_duration; use apollo_config::dumping::{prepend_sub_config_name, ser_param, SerializeConfig}; use apollo_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use blockifier::blockifier::config::{ContractClassManagerConfig, WorkerPoolConfig}; @@ -18,6 +19,9 @@ pub struct BlockBuilderConfig { pub bouncer_config: BouncerConfig, pub n_concurrent_txs: usize, pub tx_polling_interval_millis: u64, + #[serde(deserialize_with = "deserialize_milliseconds_to_duration")] + // TODO(dan): add validation for this field. Probably should be bounded. + pub proposer_idle_detection_delay_millis: std::time::Duration, pub versioned_constants_overrides: VersionedConstantsOverrides, } @@ -30,6 +34,7 @@ impl Default for BlockBuilderConfig { bouncer_config: BouncerConfig::default(), n_concurrent_txs: 100, tx_polling_interval_millis: 10, + proposer_idle_detection_delay_millis: std::time::Duration::from_millis(2000), versioned_constants_overrides: VersionedConstantsOverrides::default(), } } @@ -53,6 +58,14 @@ impl SerializeConfig for BlockBuilderConfig { request returned no transactions.", ParamPrivacyInput::Public, )])); + dump.append(&mut BTreeMap::from([ser_param( + "proposer_idle_detection_delay_millis", + &self.proposer_idle_detection_delay_millis.as_millis(), + "Minimum time (in milliseconds) that must pass since block creation started before \ + checking for idle state. If this delay has passed AND no transactions are currently \ + being executed, the proposer will finish building the current block.", + ParamPrivacyInput::Public, + )])); dump.append(&mut prepend_sub_config_name( self.versioned_constants_overrides.dump(), "versioned_constants_overrides", diff --git a/crates/apollo_deployments/resources/app_configs/batcher_config.json b/crates/apollo_deployments/resources/app_configs/batcher_config.json index c8ec2c30813..ac6db6f1d61 100644 --- a/crates/apollo_deployments/resources/app_configs/batcher_config.json +++ b/crates/apollo_deployments/resources/app_configs/batcher_config.json @@ -21,6 +21,7 @@ "batcher_config.block_builder_config.execute_config.stack_size": 62914560, "batcher_config.block_builder_config.n_concurrent_txs": 100, "batcher_config.block_builder_config.tx_polling_interval_millis": 10, + "batcher_config.block_builder_config.proposer_idle_detection_delay_millis": 2000, "batcher_config.contract_class_manager_config.cairo_native_run_config.channel_size": 2000, "batcher_config.contract_class_manager_config.cairo_native_run_config.native_classes_whitelist": "All", "batcher_config.contract_class_manager_config.cairo_native_run_config.panic_on_compilation_failure": false, diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index f7ddfe8eb9c..340b3aa5e01 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -144,6 +144,11 @@ "privacy": "Public", "value": 100 }, + "batcher_config.block_builder_config.proposer_idle_detection_delay_millis": { + "description": "Minimum time (in milliseconds) that must pass since block creation started before checking for idle state. If this delay has passed AND no transactions are currently being executed, the proposer will finish building the current block.", + "privacy": "Public", + "value": 2000 + }, "batcher_config.block_builder_config.tx_polling_interval_millis": { "description": "Time to wait (in milliseconds) between transaction requests when the previous request returned no transactions.", "privacy": "Public", From afa3ebb471f18736fb8b3972c4bdd71c6840135f Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 10:03:09 +0200 Subject: [PATCH 131/313] apollo_consensus: Add a metric that counts how many proposals by this node were accepted (#9731) --- crates/apollo_consensus/src/manager.rs | 5 +++++ crates/apollo_consensus/src/metrics.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/crates/apollo_consensus/src/manager.rs b/crates/apollo_consensus/src/manager.rs index 2fcd9ad4a0d..a89599ddcca 100644 --- a/crates/apollo_consensus/src/manager.rs +++ b/crates/apollo_consensus/src/manager.rs @@ -28,6 +28,7 @@ use crate::metrics::{ register_metrics, CONSENSUS_BLOCK_NUMBER, CONSENSUS_CACHED_VOTES, + CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, CONSENSUS_DECISIONS_REACHED_BY_SYNC, CONSENSUS_MAX_CACHED_BLOCK_NUMBER, @@ -112,6 +113,10 @@ where // precommits to print. let round = decision.precommits[0].round; let proposer = context.proposer(current_height, round); + + if proposer == run_consensus_args.validator_id { + CONSENSUS_DECISIONS_REACHED_AS_PROPOSER.increment(1); + } info!( "DECISION_REACHED: Decision reached for round {} with proposer {}. {:?}", round, proposer, decision diff --git a/crates/apollo_consensus/src/metrics.rs b/crates/apollo_consensus/src/metrics.rs index 546e9b15b98..1484f9d84fb 100644 --- a/crates/apollo_consensus/src/metrics.rs +++ b/crates/apollo_consensus/src/metrics.rs @@ -10,6 +10,7 @@ define_metrics!( MetricGauge { CONSENSUS_CACHED_VOTES, "consensus_cached_votes", "How many votes are cached when starting to work on a new block number" }, MetricCounter { CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, "consensus_decisions_reached_by_consensus", "The total number of decisions reached by way of consensus", init=0}, MetricCounter { CONSENSUS_DECISIONS_REACHED_BY_SYNC, "consensus_decisions_reached_by_sync", "The total number of decisions reached by way of sync", init=0}, + MetricCounter { CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, "consensus_decisions_reached_as_proposer", "The total number of rounds with decision reached where this node is the proposer", init=0}, MetricCounter { CONSENSUS_PROPOSALS_RECEIVED, "consensus_proposals_received", "The total number of proposals received", init=0}, MetricCounter { CONSENSUS_PROPOSALS_VALID_INIT, "consensus_proposals_valid_init", "The total number of proposals received with a valid init", init=0}, MetricCounter { CONSENSUS_PROPOSALS_VALIDATED, "consensus_proposals_validated", "The total number of complete, valid proposals received", init=0}, @@ -54,6 +55,7 @@ pub(crate) fn register_metrics() { CONSENSUS_CACHED_VOTES.register(); CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS.register(); CONSENSUS_DECISIONS_REACHED_BY_SYNC.register(); + CONSENSUS_DECISIONS_REACHED_AS_PROPOSER.register(); CONSENSUS_PROPOSALS_RECEIVED.register(); CONSENSUS_PROPOSALS_VALID_INIT.register(); CONSENSUS_PROPOSALS_VALIDATED.register(); From 1e3b46f8fd433f08b08793ff2136775d7b025de2 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 10:32:05 +0200 Subject: [PATCH 132/313] scripts: Modify the script to also support revert + disable revert (#9471) Also support getting the block number from the feeder --- scripts/prod/restart_all_nodes_together.py | 73 ++----- scripts/prod/set_node_revert_mode.py | 189 +++++++++++++----- .../prod/update_config_and_restart_nodes.py | 3 +- .../update_config_and_restart_nodes_lib.py | 100 ++++++--- 4 files changed, 226 insertions(+), 139 deletions(-) diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_nodes_together.py index d2953198eba..c59098b1b5a 100755 --- a/scripts/prod/restart_all_nodes_together.py +++ b/scripts/prod/restart_all_nodes_together.py @@ -1,9 +1,6 @@ #!/usr/bin/env python3 -import argparse -import json import sys -from enum import Enum from typing import Optional import urllib.error @@ -11,9 +8,11 @@ import urllib.request from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, + RestartStrategy, Service, get_configmap, get_context_list_from_args, + get_current_block_number, get_logs_explorer_url, get_namespace_list_from_args, parse_config_from_yaml, @@ -42,28 +41,6 @@ def get_logs_explorer_url_for_proposal( return get_logs_explorer_url(query, project_name) -class RestartStrategy(Enum): - """Strategy for restarting nodes.""" - - ALL_AT_ONCE = "all_at_once" - ONE_BY_ONE = "one_by_one" - - -def restart_strategy_converter(strategy_name: str) -> RestartStrategy: - """Convert string to RestartStrategy enum with informative error message""" - RESTART_STRATEGY_PREFIX = f"{RestartStrategy.__name__}." - if strategy_name.startswith(RESTART_STRATEGY_PREFIX): - strategy_name = strategy_name[len(RESTART_STRATEGY_PREFIX) :] - - try: - return RestartStrategy(strategy_name) - except KeyError: - valid_strategies = ", ".join([strategy.value for strategy in RestartStrategy]) - raise argparse.ArgumentTypeError( - f"Invalid restart strategy '{strategy_name}'. Valid options are: {valid_strategies}" - ) - - def get_validator_id(namespace: str, context: Optional[str]) -> str: # Get current config and normalize it (e.g. " vs ') to ensure not showing bogus diffs. original_config = get_configmap(namespace, context, Service.Core) @@ -76,7 +53,7 @@ def main(): usage_example = """ Examples: # Restart all nodes to at the next block after current feeder block (default: One_By_One strategy) - %(prog)s --namespace-prefix apollo-sepolia-integration --num-nodes 3 --feeder_url feeder.integration-sepolia.starknet.io + %(prog)s --namespace-prefix apollo-sepolia-integration --num-nodes 3 --feeder-url feeder.integration-sepolia.starknet.io %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io # Restart nodes one by one with project name for showing logs link @@ -109,21 +86,12 @@ def main(): args_builder.add_argument( "-f", - "--feeder_url", + "--feeder-url", required=True, type=str, help="The feeder URL to get the current block from", ) - args_builder.add_argument( - "-t", - "--restart-strategy", - type=restart_strategy_converter, - choices=list(RestartStrategy), - default=RestartStrategy.ONE_BY_ONE, - help="Strategy for restarting nodes (default: All_At_Once)", - ) - # TODO(guy.f): Remove this when we rely on metrics for restarting. args_builder.add_argument( "--project-name", @@ -137,29 +105,11 @@ def main(): sys.exit(1) # Get current block number from feeder URL - try: - url = f"https://{args.feeder_url}/feeder_gateway/get_block" - with urllib.request.urlopen(url) as response: - if response.status != 200: - raise urllib.error.HTTPError( - url, response.status, "HTTP Error", response.headers, None - ) - data = json.loads(response.read().decode("utf-8")) - current_block_number = data["block_number"] - next_block_number = current_block_number + 1 - - print_colored(f"Current block number: {current_block_number}") - print_colored(f"Next block number: {next_block_number}") - - except urllib.error.URLError as e: - print_error(f"Failed to fetch block number from feeder URL: {e}") - sys.exit(1) - except KeyError as e: - print_error(f"Unexpected response format from feeder URL: {e}") - sys.exit(1) - except json.JSONDecodeError as e: - print_error(f"Failed to parse JSON response from feeder URL: {e}") - sys.exit(1) + current_block_number = get_current_block_number(args.feeder_url) + next_block_number = current_block_number + 1 + + print_colored(f"Current block number: {current_block_number}") + print_colored(f"Next block number: {next_block_number}") config_overrides = { "consensus_manager_config.immediate_active_height": next_block_number, @@ -187,14 +137,15 @@ def main(): post_restart_instructions.append( f"Please check logs and verify that the node has proposed a block that was accepted. Logs URL: {url}" ) + else: + post_restart_instructions.extend([""] * len(namespace_list)) update_config_and_restart_nodes( config_overrides, namespace_list, Service.Core, context_list, - not args.no_restart, - args.restart_strategy == RestartStrategy.ONE_BY_ONE, + args.restart_strategy, post_restart_instructions, ) diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index 6a0baa72d6c..f7a780cb9b3 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -1,93 +1,190 @@ #!/usr/bin/env python3 import sys +from typing import Optional +import urllib.parse from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, + RestartStrategy, + Service, + get_context_list_from_args, + get_current_block_number, + get_logs_explorer_url, + get_namespace_list_from_args, print_colored, print_error, update_config_and_restart_nodes, ) +# TODO(guy.f): Remove this once we have metrics we use to decide based on. +def get_logs_explorer_url_for_revert( + namespace: str, + block_number: int, + project_name: str, +) -> str: + query = ( + f'resource.labels.namespace_name:"{urllib.parse.quote(namespace)}"\n' + f'resource.labels.container_name="sequencer-core"\n' + f'textPayload =~ "Done reverting.*storage up to height {block_number}"' + ) + return get_logs_explorer_url(query, project_name) + + +def set_revert_mode( + namespace_list: list[str], + context_list: Optional[list[str]], + project_name: str, + should_revert: bool, + revert_up_to_block: int, + restart_strategy: RestartStrategy, +): + config_overrides = { + "revert_config.should_revert": should_revert, + "revert_config.revert_up_to_and_including": revert_up_to_block, + } + + post_restart_instructions = [] + for namespace, context in zip(namespace_list, context_list): + url = get_logs_explorer_url_for_revert(namespace, revert_up_to_block, project_name) + + post_restart_instructions.append( + f"Please check logs and verify that revert has completed (both in the batcher and for sync). Logs URL: {url}" + ) + + update_config_and_restart_nodes( + config_overrides, + namespace_list, + Service.Core, + context_list, + restart_strategy, + post_restart_instructions, + ) + + def main(): usage_example = """ Examples: # Set revert mode up to a specific block - %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 revert --revert_up_to_block 12345 - %(prog)s -n apollo-sepolia-integration -N 3 revert -b 12345 + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --revert-only --revert_up_to_block 12345 + %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -b 12345 + + # Set revert mode using feeder URL to get current block + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --revert-only --feeder-url feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -f feeder.integration-sepolia.starknet.io # Disable revert mode - %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 disable-revert - %(prog)s -n apollo-sepolia-integration -N 3 disable-revert + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --disable-revert-only + %(prog)s -n apollo-sepolia-integration -N 3 --disable-revert-only # Set revert mode with cluster prefix - %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster revert -b 12345 + %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster --revert-only -b 12345 + + # Set revert mode with feeder URL and cluster prefix + %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster --revert-only -f feeder.integration-sepolia.starknet.io # Disable revert mode without restarting nodes - %(prog)s -n apollo-sepolia-integration -N 3 disable-revert --no-restart + %(prog)s -n apollo-sepolia-integration -N 3 --disable-revert-only --no-restart # Set revert mode with explicit restart - %(prog)s -n apollo-sepolia-integration -N 3 revert -b 12345 -r + %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -b 12345 -r + + # Set revert mode with feeder URL and explicit restart + %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -f feeder.integration-sepolia.starknet.io -r # Set revert mode starting from specific node index - %(prog)s -n apollo-sepolia-integration -N 3 -i 5 revert -b 12345 + %(prog)s -n apollo-sepolia-integration -N 3 -i 5 --revert-only -b 12345 + + # Set revert mode with feeder URL starting from specific node index + %(prog)s -n apollo-sepolia-integration -N 3 -i 5 --revert-only -f feeder.integration-sepolia.starknet.io """ args_builder = ApolloArgsParserBuilder( "Sets or unsets the revert mode for the sequencer nodes", usage_example ) - # Create subparsers for revert operations - subparsers = args_builder.parser.add_subparsers( - dest="command", help="Available commands", required=True + revert_group = args_builder.parser.add_mutually_exclusive_group() + revert_group.add_argument("--revert-only", action="store_true", help="Enable revert mode") + revert_group.add_argument( + "--disable-revert-only", action="store_true", help="Disable revert mode" ) - # Revert subcommand - revert_parser = subparsers.add_parser("revert", help="Enable revert mode") - revert_parser.add_argument( + args_builder.add_argument( "-b", - "--revert_up_to_block", + "--revert-up-to-block", type=int, - required=True, - help="Block number up to which to revert. Must be a positive integer.", + help="Block number up to which to revert (inclusive). Must be a positive integer.", ) - # No-revert subcommand - subparsers.add_parser("disable-revert", help="Disable revert mode") + args_builder.add_argument( + "-f", + "--feeder-url", + type=str, + help="The feeder URL to get the current block from. We will revert all blocks above it.", + ) + + # TODO(guy.f): Remove this when we rely on metrics for restarting. + args_builder.add_argument( + "--project-name", + help="The name of the project to get logs from. If One_By_One strategy is used, this is required.", + ) args = args_builder.build() - # Validate block number for revert command - if args.command == "revert": - if args.revert_up_to_block <= 0: - print_error("Error: --revert_up_to_block (-b) must be a positive integer") + + if args.restart_strategy == RestartStrategy.ONE_BY_ONE and args.project_name is None: + print_error("Error: --project-name is required when using One_By_One strategy") + sys.exit(1) + + should_revert = not args.disable_revert_only + if should_revert: + if args.feeder_url is None and args.revert_up_to_block is None: + print_error( + "Error: Either --feeder-url or --revert_up_to_block (-b) are required when reverting is requested." + ) + sys.exit(1) + if args.feeder_url is not None and args.revert_up_to_block is not None: + print_error("Error: Cannot specify both --feeder-url and --revert_up_to_block (-b).") sys.exit(1) - # Add revert-specific configuration based on subcommand - if args.command == "revert": - should_revert = True - revert_up_to_block = args.revert_up_to_block - print_colored( - f"\nEnabling revert mode up to (and including) block {args.revert_up_to_block}" - ) - elif args.command == "disable-revert": - should_revert = False - revert_up_to_block = 18446744073709551615 # Max unit64. - print_colored(f"\nDisabling revert mode") + if args.disable_revert_only: + if args.feeder_url is not None: + print_error("Error: --feeder-url cannot be set when using --disable-revert-only") + sys.exit(1) + if args.revert_up_to_block is not None: + print_error("Error: --revert-up-to-block (-b) cannot be set when disabling revert.") + sys.exit(1) - config_overrides = { - "revert_config.should_revert": should_revert, - "revert_config.revert_up_to_and_including": revert_up_to_block, - } + namespace_list = get_namespace_list_from_args(args) + context_list = get_context_list_from_args(args) - update_config_and_restart_nodes( - config_overrides, - args.namespace, - args.num_nodes, - args.start_index, - args.cluster, - not args.no_restart, - ) + should_disable_revert = not args.revert_only + if should_revert: + revert_up_to_block = ( + args.revert_up_to_block + if args.revert_up_to_block is not None + else get_current_block_number(args.feeder_url) + ) + f"\nEnabling revert mode up to (and including) block {revert_up_to_block}" + set_revert_mode( + namespace_list, + context_list, + args.project_name, + True, + revert_up_to_block, + args.restart_strategy, + ) + if should_disable_revert: + print_colored(f"\nDisabling revert mode") + # Setting to max block to max u64. + set_revert_mode( + namespace_list, + context_list, + args.project_name, + False, + 18446744073709551615, + args.restart_strategy, + ) if __name__ == "__main__": diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index 6b07d612e61..1eed4cc46c1 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -154,7 +154,8 @@ def main(): get_namespace_list_from_args(args), args.service, get_context_list_from_args(args), - not args.no_restart, + args.restart_strategy, + None, ) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 2c4b8c05545..16655ce55d2 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -8,7 +8,9 @@ from typing import Any, Optional import tempfile +import urllib.error import urllib.parse +import urllib.request import yaml from difflib import unified_diff @@ -91,18 +93,13 @@ def _add_common_flags(self): help="Space separated list of cluster names for kubectl contexts", ) - restart_group = self.parser.add_mutually_exclusive_group() - restart_group.add_argument( - "-r", - "--restart-nodes", - action="store_true", - default=None, - help="Restart the pods after updating configuration (default behavior)", - ) - restart_group.add_argument( - "--no-restart", - action="store_true", - help="Do not restart the pods after updating configuration", + self.add_argument( + "-t", + "--restart-strategy", + type=restart_strategy_converter, + choices=list(RestartStrategy), + default=RestartStrategy.ONE_BY_ONE, + help="Strategy for restarting nodes (default: One_By_One)", ) def add_argument(self, *args, **kwargs): @@ -147,6 +144,29 @@ def __init__(self, config_map_name: str, pod_name: str) -> None: self.pod_name = pod_name +class RestartStrategy(Enum): + """Strategy for restarting nodes.""" + + ALL_AT_ONCE = "all_at_once" + ONE_BY_ONE = "one_by_one" + NO_RESTART = "no_restart" + + +def restart_strategy_converter(strategy_name: str) -> RestartStrategy: + """Convert string to RestartStrategy enum with informative error message""" + RESTART_STRATEGY_PREFIX = f"{RestartStrategy.__name__}." + if strategy_name.startswith(RESTART_STRATEGY_PREFIX): + strategy_name = strategy_name[len(RESTART_STRATEGY_PREFIX) :] + + try: + return RestartStrategy(strategy_name) + except KeyError: + valid_strategies = ", ".join([strategy.value for strategy in RestartStrategy]) + raise argparse.ArgumentTypeError( + f"Invalid restart strategy '{strategy_name}'. Valid options are: {valid_strategies}" + ) + + def validate_arguments(args: argparse.Namespace) -> None: if (args.namespace_list and args.cluster_prefix) or ( args.namespace_prefix and args.cluster_list @@ -229,6 +249,30 @@ def get_logs_explorer_url( ) +def get_current_block_number(feeder_url: str) -> int: + """Get the current block number from the feeder URL.""" + try: + url = f"https://{feeder_url}/feeder_gateway/get_block" + with urllib.request.urlopen(url) as response: + if response.status != 200: + raise urllib.error.HTTPError( + url, response.status, "HTTP Error", response.headers, None + ) + data = json.loads(response.read().decode("utf-8")) + current_block_number = data["block_number"] + return current_block_number + + except urllib.error.URLError as e: + print_error(f"Failed to fetch block number from feeder URL: {e}") + sys.exit(1) + except KeyError as e: + print_error(f"Unexpected response format from feeder URL: {e}") + sys.exit(1) + except json.JSONDecodeError as e: + print_error(f"Failed to parse JSON response from feeder URL: {e}") + sys.exit(1) + + def run_kubectl_command(args: list, capture_output: bool = True) -> subprocess.CompletedProcess: full_command = ["kubectl"] + args try: @@ -462,10 +506,9 @@ def update_config_and_restart_nodes( config_overrides: dict[str, Any], namespace_list: list[str], service: Service, - cluster_list: Optional[list[str]] = None, - restart_nodes: bool = True, - # TODO(guy.f): Remove this once we have metrics we use to decide based on. - wait_between_restarts: bool = False, + cluster_list: Optional[list[str]], + restart_strategy: RestartStrategy, + # TODO(guy.f): Add more abstraction to restart strategy so that the instructions are abstracted as part of it. post_restart_instructions: Optional[list[str]] = None, ) -> None: assert config_overrides is not None, "config_overrides must be provided" @@ -474,16 +517,7 @@ def update_config_and_restart_nodes( if post_restart_instructions is not None: assert len(post_restart_instructions) == len( namespace_list - ), f"logs_explorer_urls must have the same length as namespace_list. logs_explorer_urls: {len(post_restart_instructions)}, namespace_list: {len(namespace_list)}" - - if wait_between_restarts: - assert ( - post_restart_instructions is not None - ), "logs_explorer_urls must be provided when wait_between_restarts is True" - else: - assert ( - post_restart_instructions is None - ), "logs_explorer_urls must be None when wait_between_restarts is False" + ), f"post_restart_instructions must have the same length as namespace_list. logs_explorer_urls: {len(post_restart_instructions)}, namespace_list: {len(namespace_list)}" if not cluster_list: print_colored( @@ -532,14 +566,18 @@ def update_config_and_restart_nodes( cluster_list[index] if cluster_list else None, ) - if restart_nodes: + if restart_strategy != RestartStrategy.NO_RESTART: for index, config in enumerate(configs): restart_pod( namespace_list[index], service, index, cluster_list[index] if cluster_list else None ) - if wait_between_restarts: - instructions = post_restart_instructions[index] - print_colored(f"Restarted pod.\n{instructions}. ", Colors.YELLOW) + if restart_strategy == RestartStrategy.ONE_BY_ONE: + instructions = ( + post_restart_instructions[index] if post_restart_instructions else None + ) + print_colored( + f"Restarted pod.\n{instructions if instructions else ''} ", Colors.YELLOW + ) # Don't ask in the case of the last job. if index != len(configs) - 1 and not wait_until_y_or_n( f"Do you want to restart the next pod?" @@ -548,6 +586,6 @@ def update_config_and_restart_nodes( return print_colored("\nAll pods have been successfully restarted!", Colors.GREEN) else: - print_colored("\nSkipping pod restart (--no-restart was specified)") + print_colored("\nSkipping pod restart.") print("\nOperation completed successfully!") From 5fe2ab80e8068805196c7e3bb07d44648252778c Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 11:02:17 +0200 Subject: [PATCH 133/313] scripts: allow not using setting restart strategy flag and always print restart instructions (#9645) --- .../update_config_and_restart_nodes_lib.py | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 16655ce55d2..29a9c23adb4 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -37,7 +37,8 @@ def print_error(message: str) -> None: class ApolloArgsParserBuilder: """Builder class for creating argument parsers with required flags and custom arguments.""" - def __init__(self, description: str, usage_example: str): + # TODO(guy.f): If we need to exclude more than just the restart flag, create a more generic mechanism. + def __init__(self, description: str, usage_example: str, include_restart_strategy: bool = True): """Initialize the builder with usage example for epilog. Args: @@ -50,10 +51,14 @@ def __init__(self, description: str, usage_example: str): epilog=usage_example, ) - self._add_common_flags() + self._add_common_flags(include_restart_strategy) - def _add_common_flags(self): - """Add all common flags.""" + def _add_common_flags(self, include_restart_strategy: bool): + """Add all common flags. + + Args: + include_restart_strategy: Whether to include the restart strategy flag. + """ namespace_group = self.parser.add_mutually_exclusive_group(required=True) namespace_group.add_argument( "-n", @@ -93,14 +98,15 @@ def _add_common_flags(self): help="Space separated list of cluster names for kubectl contexts", ) - self.add_argument( - "-t", - "--restart-strategy", - type=restart_strategy_converter, - choices=list(RestartStrategy), - default=RestartStrategy.ONE_BY_ONE, - help="Strategy for restarting nodes (default: One_By_One)", - ) + if include_restart_strategy: + self.add_argument( + "-t", + "--restart-strategy", + type=restart_strategy_converter, + choices=list(RestartStrategy), + default=RestartStrategy.ONE_BY_ONE, + help="Strategy for restarting nodes (default: One_By_One)", + ) def add_argument(self, *args, **kwargs): """Add a new argument to the parser. @@ -571,13 +577,9 @@ def update_config_and_restart_nodes( restart_pod( namespace_list[index], service, index, cluster_list[index] if cluster_list else None ) + instructions = post_restart_instructions[index] if post_restart_instructions else None + print_colored(f"Restarted pod.\n{instructions if instructions else ''} ", Colors.YELLOW) if restart_strategy == RestartStrategy.ONE_BY_ONE: - instructions = ( - post_restart_instructions[index] if post_restart_instructions else None - ) - print_colored( - f"Restarted pod.\n{instructions if instructions else ''} ", Colors.YELLOW - ) # Don't ask in the case of the last job. if index != len(configs) - 1 and not wait_until_y_or_n( f"Do you want to restart the next pod?" From e670f34b8ac806a0fb217dccbb8c871b8cc230de Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 11:05:46 +0200 Subject: [PATCH 134/313] apollo_consensus_manager: register the metrics so that are actually exported. (#9739) --- .../src/consensus_manager.rs | 2 ++ crates/apollo_consensus_manager/src/metrics.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/crates/apollo_consensus_manager/src/consensus_manager.rs b/crates/apollo_consensus_manager/src/consensus_manager.rs index 11c729b2693..f938226a38b 100644 --- a/crates/apollo_consensus_manager/src/consensus_manager.rs +++ b/crates/apollo_consensus_manager/src/consensus_manager.rs @@ -44,6 +44,7 @@ use starknet_api::block::BlockNumber; use tracing::{info, info_span, Instrument}; use crate::metrics::{ + register_metrics, CONSENSUS_NETWORK_EVENTS, CONSENSUS_NUM_BLACKLISTED_PEERS, CONSENSUS_NUM_CONNECTED_PEERS, @@ -327,6 +328,7 @@ pub fn create_consensus_manager( impl ComponentStarter for ConsensusManager { async fn start(&mut self) { info!("Starting component {}.", short_type_name::()); + register_metrics(); self.run().await; } } diff --git a/crates/apollo_consensus_manager/src/metrics.rs b/crates/apollo_consensus_manager/src/metrics.rs index 8185239c7e7..64e965af061 100644 --- a/crates/apollo_consensus_manager/src/metrics.rs +++ b/crates/apollo_consensus_manager/src/metrics.rs @@ -22,3 +22,15 @@ define_metrics!( }, ); + +pub(crate) fn register_metrics() { + CONSENSUS_NUM_CONNECTED_PEERS.register(); + CONSENSUS_NUM_BLACKLISTED_PEERS.register(); + CONSENSUS_VOTES_NUM_SENT_MESSAGES.register(); + CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES.register(); + CONSENSUS_VOTES_NUM_DROPPED_MESSAGES.register(); + CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES.register(); + CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES.register(); + CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES.register(); + CONSENSUS_NETWORK_EVENTS.register(); +} From 0c7f54348c3de4acfcf4d1f03f51c1e603f6142a Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 11:38:04 +0200 Subject: [PATCH 135/313] scripts: Only support restart all nodes at once (#9567) --- scripts/prod/restart_all_nodes_together.py | 69 +++++++++------------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_nodes_together.py index c59098b1b5a..d7381d8575b 100755 --- a/scripts/prod/restart_all_nodes_together.py +++ b/scripts/prod/restart_all_nodes_together.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import sys from typing import Optional import urllib.error @@ -17,7 +16,6 @@ get_namespace_list_from_args, parse_config_from_yaml, print_colored, - print_error, update_config_and_restart_nodes, ) @@ -52,36 +50,32 @@ def get_validator_id(namespace: str, context: Optional[str]) -> str: def main(): usage_example = """ Examples: - # Restart all nodes to at the next block after current feeder block (default: One_By_One strategy) - %(prog)s --namespace-prefix apollo-sepolia-integration --num-nodes 3 --feeder-url feeder.integration-sepolia.starknet.io - %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io - - # Restart nodes one by one with project name for showing logs link - %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io -t One_By_One --project-name my-gcp-project + # Restart all nodes at once. + %(prog)s --namespace-prefix apollo-sepolia-integration --num-nodes 3 --feeder-url feeder.integration-sepolia.starknet.io --project-name my-gcp-project + %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project # Restart nodes with cluster prefix - %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster -f feeder.integration-sepolia.starknet.io - - # Update configuration without restarting nodes - %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io --no-restart + %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project # Restart nodes starting from specific node index - %(prog)s -n apollo-sepolia-integration -m 3 -s 5 -f feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -m 3 -s 5 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project # Use different feeder URL - %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project # Use namespace list instead of prefix (restart specific namespaces) - %(prog)s --namespace-list apollo-sepolia-integration-0 apollo-sepolia-integration-2 -f feeder.integration-sepolia.starknet.io - %(prog)s -N apollo-sepolia-integration-0 apollo-sepolia-integration-2 -f feeder.integration-sepolia.starknet.io + %(prog)s --namespace-list apollo-sepolia-integration-0 apollo-sepolia-integration-2 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + %(prog)s -N apollo-sepolia-integration-0 apollo-sepolia-integration-2 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project # Use cluster list for multiple clusters (only works with namespace-list, not namespace-prefix) - %(prog)s -N apollo-sepolia-integration-0 apollo-sepolia-integration-1 -C cluster1 cluster2 -f feeder.integration-sepolia.starknet.io - %(prog)s --namespace-list apollo-sepolia-integration-0 apollo-sepolia-integration-1 --cluster-list cluster1 cluster2 -f feeder.integration-sepolia.starknet.io + %(prog)s -N apollo-sepolia-integration-0 apollo-sepolia-integration-1 -C cluster1 cluster2 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + %(prog)s --namespace-list apollo-sepolia-integration-0 apollo-sepolia-integration-1 --cluster-list cluster1 cluster2 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project """ args_builder = ApolloArgsParserBuilder( - "Restart all nodes using the value from the feeder URL", usage_example + "Restart all nodes using the value from the feeder URL", + usage_example, + include_restart_strategy=False, ) args_builder.add_argument( @@ -95,15 +89,12 @@ def main(): # TODO(guy.f): Remove this when we rely on metrics for restarting. args_builder.add_argument( "--project-name", - help="The name of the project to get logs from. If One_By_One strategy is used, this is required.", + required=True, + help="The name of the project to get logs from.", ) args = args_builder.build() - if args.restart_strategy == RestartStrategy.ONE_BY_ONE and args.project_name is None: - print_error("Error: --project-name is required when using One_By_One strategy") - sys.exit(1) - # Get current block number from feeder URL current_block_number = get_current_block_number(args.feeder_url) next_block_number = current_block_number + 1 @@ -112,8 +103,8 @@ def main(): print_colored(f"Next block number: {next_block_number}") config_overrides = { - "consensus_manager_config.immediate_active_height": next_block_number, "consensus_manager_config.cende_config.skip_write_height": next_block_number, + "consensus_manager_config.immediate_active_height": next_block_number, } namespace_list = get_namespace_list_from_args(args) @@ -125,27 +116,25 @@ def main(): # Generate logs explorer URLs if needed post_restart_instructions = [] - if args.restart_strategy == RestartStrategy.ONE_BY_ONE: - for namespace, context in zip(namespace_list, context_list or [None] * len(namespace_list)): - url = get_logs_explorer_url_for_proposal( - namespace, - get_validator_id(namespace, context), - # Feeder could be behind by up to 10 blocks, so we add 10 to the current block number. - current_block_number + 10, - args.project_name, - ) - post_restart_instructions.append( - f"Please check logs and verify that the node has proposed a block that was accepted. Logs URL: {url}" - ) - else: - post_restart_instructions.extend([""] * len(namespace_list)) + + for namespace, context in zip(namespace_list, context_list or [None] * len(namespace_list)): + url = get_logs_explorer_url_for_proposal( + namespace, + get_validator_id(namespace, context), + # Feeder could be behind by up to 10 blocks, so we add 10 to the current block number. + current_block_number + 10, + args.project_name, + ) + post_restart_instructions.append( + f"Please check logs and verify that the node has proposed a block that was accepted. Logs URL: {url}" + ) update_config_and_restart_nodes( config_overrides, namespace_list, Service.Core, context_list, - args.restart_strategy, + RestartStrategy.ALL_AT_ONCE, post_restart_instructions, ) From 351910bef3b676bfc0cb8871586b3c6201bcc21e Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 11:44:06 +0200 Subject: [PATCH 136/313] scripts: Make the RestartStrategy and Service arguments (also) accept the values as in the code (#9568) --- scripts/prod/update_config_and_restart_nodes.py | 2 ++ scripts/prod/update_config_and_restart_nodes_lib.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index 1eed4cc46c1..19ba02ab560 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -70,6 +70,8 @@ def service_type_converter(service_name: str) -> Service: if service_name.startswith("Service."): service_name = service_name[8:] + service_name = service_name.lower() + try: return Service[service_name] except KeyError: diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 29a9c23adb4..bf904d0cf25 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -164,6 +164,8 @@ def restart_strategy_converter(strategy_name: str) -> RestartStrategy: if strategy_name.startswith(RESTART_STRATEGY_PREFIX): strategy_name = strategy_name[len(RESTART_STRATEGY_PREFIX) :] + strategy_name = strategy_name.lower() + try: return RestartStrategy(strategy_name) except KeyError: From 46b7fdc443b4ca0ccfef2d9c54a7d26333dfc82b Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Sun, 26 Oct 2025 11:44:07 +0200 Subject: [PATCH 137/313] apollo_batcher: import std time Duration (#9753) --- crates/apollo_batcher/src/block_builder.rs | 3 ++- crates/apollo_batcher/src/block_builder_test.rs | 7 ++++--- crates/apollo_batcher_config/src/config.rs | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index 4c569a087a9..1d815658c09 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -1,6 +1,7 @@ use std::cmp::min; use std::collections::{HashMap, HashSet}; use std::sync::Arc; +use std::time::Duration; use apollo_batcher_config::config::BlockBuilderConfig; use apollo_batcher_types::batcher_types::ProposalCommitment; @@ -159,7 +160,7 @@ pub trait BlockBuilderTrait: Send { pub struct BlockBuilderExecutionParams { pub deadline: tokio::time::Instant, pub is_validator: bool, - pub proposer_idle_detection_delay: std::time::Duration, + pub proposer_idle_detection_delay: Duration, } pub struct BlockBuilder { diff --git a/crates/apollo_batcher/src/block_builder_test.rs b/crates/apollo_batcher/src/block_builder_test.rs index 663d70e32a6..cc2d1f985e2 100644 --- a/crates/apollo_batcher/src/block_builder_test.rs +++ b/crates/apollo_batcher/src/block_builder_test.rs @@ -1,4 +1,5 @@ use std::sync::Arc; +use std::time::Duration; use apollo_class_manager_types::transaction_converter::TransactionConverter; use apollo_class_manager_types::MockClassManagerClient; @@ -59,7 +60,7 @@ const BLOCK_GENERATION_LONG_DEADLINE_SECS: u64 = 5; const TX_CHANNEL_SIZE: usize = 50; const N_CONCURRENT_TXS: usize = 3; const TX_POLLING_INTERVAL: u64 = 100; -const DEFAULT_IDLE_TIMEOUT_MS: std::time::Duration = std::time::Duration::from_millis(2000); +const DEFAULT_IDLE_TIMEOUT_MS: Duration = Duration::from_millis(2000); struct TestExpectations { mock_transaction_executor: MockTransactionExecutorTrait, @@ -680,7 +681,7 @@ async fn run_build_block( is_validator: bool, abort_receiver: tokio::sync::oneshot::Receiver<()>, deadline_secs: u64, - idle_timeout_duration: std::time::Duration, + idle_timeout_duration: Duration, ) -> BlockBuilderResult { let deadline = tokio::time::Instant::now() + tokio::time::Duration::from_secs(deadline_secs); let transaction_converter = TransactionConverter::new( @@ -732,7 +733,7 @@ async fn test_build_block(#[case] test_expectations: TestExpectations) { let (_abort_sender, abort_receiver) = tokio::sync::oneshot::channel(); let idle_timeout_duration = if test_expectations.expected_idle_execution_timeout_metric > 0 { - std::time::Duration::from_millis(100) + Duration::from_millis(100) } else { DEFAULT_IDLE_TIMEOUT_MS }; diff --git a/crates/apollo_batcher_config/src/config.rs b/crates/apollo_batcher_config/src/config.rs index e4d21402504..836156c903c 100644 --- a/crates/apollo_batcher_config/src/config.rs +++ b/crates/apollo_batcher_config/src/config.rs @@ -1,4 +1,5 @@ use std::collections::BTreeMap; +use std::time::Duration; use apollo_config::converters::deserialize_milliseconds_to_duration; use apollo_config::dumping::{prepend_sub_config_name, ser_param, SerializeConfig}; @@ -21,7 +22,7 @@ pub struct BlockBuilderConfig { pub tx_polling_interval_millis: u64, #[serde(deserialize_with = "deserialize_milliseconds_to_duration")] // TODO(dan): add validation for this field. Probably should be bounded. - pub proposer_idle_detection_delay_millis: std::time::Duration, + pub proposer_idle_detection_delay_millis: Duration, pub versioned_constants_overrides: VersionedConstantsOverrides, } @@ -34,7 +35,7 @@ impl Default for BlockBuilderConfig { bouncer_config: BouncerConfig::default(), n_concurrent_txs: 100, tx_polling_interval_millis: 10, - proposer_idle_detection_delay_millis: std::time::Duration::from_millis(2000), + proposer_idle_detection_delay_millis: Duration::from_millis(2000), versioned_constants_overrides: VersionedConstantsOverrides::default(), } } From dd74c439da0a0db49fac3ccfa176169d6001eb48 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Sun, 26 Oct 2025 11:50:46 +0200 Subject: [PATCH 138/313] apollo_integration_tests: mine enough blocks (#9703) --- Cargo.lock | 1 + crates/apollo_integration_tests/Cargo.toml | 1 + .../src/integration_test_manager.rs | 10 +++++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 7adf56433f5..9150cf83dce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1554,6 +1554,7 @@ dependencies = [ "apollo_http_server_config", "apollo_infra", "apollo_infra_utils", + "apollo_l1_endpoint_monitor", "apollo_l1_endpoint_monitor_config", "apollo_l1_gas_price", "apollo_l1_gas_price_provider_config", diff --git a/crates/apollo_integration_tests/Cargo.toml b/crates/apollo_integration_tests/Cargo.toml index 3437d36ebe6..a309b3709b7 100644 --- a/crates/apollo_integration_tests/Cargo.toml +++ b/crates/apollo_integration_tests/Cargo.toml @@ -31,6 +31,7 @@ apollo_http_server = { workspace = true, features = ["testing"] } apollo_http_server_config.workspace = true apollo_infra = { workspace = true, features = ["testing"] } apollo_infra_utils = { workspace = true, features = ["testing"] } +apollo_l1_endpoint_monitor.workspace = true apollo_l1_endpoint_monitor_config.workspace = true apollo_l1_gas_price.workspace = true apollo_l1_gas_price_provider_config.workspace = true diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index 9992adfc9a6..6d8fef6853e 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -11,6 +11,7 @@ use apollo_http_server_config::config::HttpServerConfig; use apollo_infra_utils::dumping::serialize_to_file; use apollo_infra_utils::test_utils::{AvailablePortsGenerator, TestIdentifier}; use apollo_infra_utils::tracing::{CustomLogger, TraceLevel}; +use apollo_l1_endpoint_monitor::monitor::MIN_EXPECTED_BLOCK_NUMBER; use apollo_l1_gas_price_provider_config::config::{EthToStrkOracleConfig, L1GasPriceScraperConfig}; use apollo_monitoring_endpoint::test_utils::MonitoringClient; use apollo_monitoring_endpoint_config::config::MonitoringEndpointConfig; @@ -324,7 +325,14 @@ impl IntegrationTestManager { let num_blocks_needed_on_l1 = l1_gas_price_scraper_config.number_of_blocks_for_mean + l1_gas_price_scraper_config.finality; - anvil_mine_blocks(base_layer_config.clone(), num_blocks_needed_on_l1, &base_layer_url) + assert!( + num_blocks_needed_on_l1 <= MIN_EXPECTED_BLOCK_NUMBER, + "num_blocks_needed_on_l1 ({}) exceeds MIN_EXPECTED_BLOCK_NUMBER ({})", + num_blocks_needed_on_l1, + MIN_EXPECTED_BLOCK_NUMBER + ); + + anvil_mine_blocks(base_layer_config.clone(), MIN_EXPECTED_BLOCK_NUMBER, &base_layer_url) .await; let idle_nodes = create_map(sequencers_setup, |node| node.get_node_index()); From 9e9c2c527a57ec354a9b192f0d5d1cdde119fcd1 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 12:12:55 +0200 Subject: [PATCH 139/313] scripts: make restart mode required with no default (#9594) --- scripts/prod/set_node_revert_mode.py | 26 ++++++++--------- .../prod/update_config_and_restart_nodes.py | 28 +++++++++---------- .../update_config_and_restart_nodes_lib.py | 4 +-- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index f7a780cb9b3..19ab8bdbefa 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -67,37 +67,37 @@ def main(): usage_example = """ Examples: # Set revert mode up to a specific block - %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --revert-only --revert_up_to_block 12345 - %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -b 12345 + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --revert-only --revert_up_to_block 12345 + %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -b 12345 # Set revert mode using feeder URL to get current block - %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --revert-only --feeder-url feeder.integration-sepolia.starknet.io - %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -f feeder.integration-sepolia.starknet.io + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --revert-only --feeder-url feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io # Disable revert mode - %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --disable-revert-only - %(prog)s -n apollo-sepolia-integration -N 3 --disable-revert-only + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --disable-revert-only + %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --disable-revert-only # Set revert mode with cluster prefix - %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster --revert-only -b 12345 + %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster -t all_at_once --revert-only -b 12345 # Set revert mode with feeder URL and cluster prefix - %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster --revert-only -f feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io # Disable revert mode without restarting nodes - %(prog)s -n apollo-sepolia-integration -N 3 --disable-revert-only --no-restart + %(prog)s -n apollo-sepolia-integration -N 3 -t no_restart --disable-revert-only # Set revert mode with explicit restart - %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -b 12345 -r + %(prog)s -n apollo-sepolia-integration -N 3 -t all_at_once --revert-only -b 12345 # Set revert mode with feeder URL and explicit restart - %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -f feeder.integration-sepolia.starknet.io -r + %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io # Set revert mode starting from specific node index - %(prog)s -n apollo-sepolia-integration -N 3 -i 5 --revert-only -b 12345 + %(prog)s -n apollo-sepolia-integration -N 3 -i 5 -t all_at_once --revert-only -b 12345 # Set revert mode with feeder URL starting from specific node index - %(prog)s -n apollo-sepolia-integration -N 3 -i 5 --revert-only -f feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -N 3 -i 5 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io """ args_builder = ApolloArgsParserBuilder( diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index 19ba02ab560..0f0ccf1b609 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -85,35 +85,35 @@ def main(): usage_example = """ Examples: # Basic usage with namespace prefix and node count - %(prog)s -n apollo-sepolia-integration -m 3 --config-overrides consensus_manager_config.timeout=5000 --config-overrides validator_id=0x42 + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once --config-overrides consensus_manager_config.timeout=5000 --config-overrides validator_id=0x42 # Using namespace list mode (no num-nodes or start-index allowed) - %(prog)s -N apollo-sepolia-test-0 apollo-sepolia-test-1 apollo-sepolia-test-2 --config-overrides consensus_manager_config.timeout=5000 + %(prog)s -N apollo-sepolia-test-0 apollo-sepolia-test-1 apollo-sepolia-test-2 -t one_by_one --config-overrides consensus_manager_config.timeout=5000 # Using cluster prefix with namespace prefix - %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster --config-overrides validator_id=0x42 + %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster -t all_at_once --config-overrides validator_id=0x42 # Using cluster list with namespace list (must have same number of items) - %(prog)s -N apollo-sepolia-test-0 apollo-sepolia-test-2 -C cluster0 cluster2 --config-overrides validator_id=0x42 + %(prog)s -N apollo-sepolia-test-0 apollo-sepolia-test-2 -C cluster0 cluster2 -t one_by_one --config-overrides validator_id=0x42 # Update different service types - %(prog)s -n apollo-sepolia-integration -m 3 -j Gateway --config-overrides gateway_config.port=8080 - %(prog)s -n apollo-sepolia-integration -m 3 -j Mempool --config-overrides mempool_config.max_size=1000 - %(prog)s -n apollo-sepolia-integration -m 3 -j L1 --config-overrides l1_config.endpoint=\"https://eth-mainnet.alchemyapi.io/v2/your-key\" - %(prog)s -n apollo-sepolia-integration -m 3 -j HttpServer --config-overrides http_server_config.port=8081 - %(prog)s -n apollo-sepolia-integration -m 3 -j SierraCompiler --config-overrides sierra_compiler_config.timeout=30000 + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once -j Gateway --config-overrides gateway_config.port=8080 + %(prog)s -n apollo-sepolia-integration -m 3 -t one_by_one -j Mempool --config-overrides mempool_config.max_size=1000 + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once -j L1 --config-overrides l1_config.endpoint=\"https://eth-mainnet.alchemyapi.io/v2/your-key\" + %(prog)s -n apollo-sepolia-integration -m 3 -t one_by_one -j HttpServer --config-overrides http_server_config.port=8081 + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once -j SierraCompiler --config-overrides sierra_compiler_config.timeout=30000 # Update starting from specific node index - %(prog)s -n apollo-sepolia-integration -m 3 -s 5 --config-overrides validator_id=0x42 + %(prog)s -n apollo-sepolia-integration -m 3 -s 5 -t one_by_one --config-overrides validator_id=0x42 # Update without restart - %(prog)s -n apollo-sepolia-integration -m 3 --config-overrides validator_id=0x42 --no-restart + %(prog)s -n apollo-sepolia-integration -m 3 -t no_restart --config-overrides validator_id=0x42 - # Update with explicit restart (default behavior) - %(prog)s -n apollo-sepolia-integration -m 3 --config-overrides validator_id=0x42 -r + # Update with explicit restart (all at once) + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once --config-overrides validator_id=0x42 # Complex example with multiple config overrides - %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster -j Core --config-overrides consensus_manager_config.timeout=5000 --config-overrides validator_id=0x42 --config-overrides components.gateway.url=\"localhost\" + %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster -t one_by_one -j Core --config-overrides consensus_manager_config.timeout=5000 --config-overrides validator_id=0x42 --config-overrides components.gateway.url=\"localhost\" """ diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index bf904d0cf25..43d563da4c7 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -104,8 +104,8 @@ def _add_common_flags(self, include_restart_strategy: bool): "--restart-strategy", type=restart_strategy_converter, choices=list(RestartStrategy), - default=RestartStrategy.ONE_BY_ONE, - help="Strategy for restarting nodes (default: One_By_One)", + required=True, + help="Strategy for restarting nodes", ) def add_argument(self, *args, **kwargs): From b0eaf93e8ce247b3ac397b2273ce0781f4b36230 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 12:14:36 +0200 Subject: [PATCH 140/313] apollo_reverts: Add a metric which shows which block we reverted up to. (#9738) --- Cargo.lock | 1 + .../apollo_consensus_manager/src/consensus_manager.rs | 9 +++++++-- crates/apollo_consensus_manager/src/metrics.rs | 4 +++- crates/apollo_reverts/Cargo.toml | 1 + crates/apollo_reverts/src/lib.rs | 10 +++++++++- crates/apollo_state_sync/src/runner/mod.rs | 9 +++++++-- crates/apollo_state_sync_metrics/src/metrics.rs | 3 +++ 7 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9150cf83dce..a3e7074acb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2166,6 +2166,7 @@ name = "apollo_reverts" version = "0.16.0-rc.1" dependencies = [ "apollo_config", + "apollo_metrics", "apollo_storage", "futures", "serde", diff --git a/crates/apollo_consensus_manager/src/consensus_manager.rs b/crates/apollo_consensus_manager/src/consensus_manager.rs index f938226a38b..27e7e7c500a 100644 --- a/crates/apollo_consensus_manager/src/consensus_manager.rs +++ b/crates/apollo_consensus_manager/src/consensus_manager.rs @@ -34,7 +34,7 @@ use apollo_network::network_manager::{ NetworkManager, }; use apollo_protobuf::consensus::{HeightAndRound, ProposalPart, StreamMessage, Vote}; -use apollo_reverts::revert_blocks_and_eternal_pending; +use apollo_reverts::{revert_blocks_and_eternal_pending, RevertComponentData}; use apollo_signature_manager_types::SharedSignatureManagerClient; use apollo_state_sync_types::communication::SharedStateSyncClient; use apollo_time::time::DefaultClock; @@ -51,6 +51,7 @@ use crate::metrics::{ CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES, CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, + CONSENSUS_REVERTED_BATCHER_UP_TO_AND_INCLUDING, CONSENSUS_VOTES_NUM_DROPPED_MESSAGES, CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, CONSENSUS_VOTES_NUM_SENT_MESSAGES, @@ -294,11 +295,15 @@ impl ConsensusManager { .expect("Failed to revert block at height {height} in the batcher"); }; + const BATCHER_REVERT_COMPONENT_DATA: RevertComponentData = RevertComponentData { + name: "Batcher", + revert_metric: CONSENSUS_REVERTED_BATCHER_UP_TO_AND_INCLUDING, + }; revert_blocks_and_eternal_pending( batcher_height_marker, revert_up_to_and_including, revert_blocks_fn, - "Batcher", + &BATCHER_REVERT_COMPONENT_DATA, ) .await; } diff --git a/crates/apollo_consensus_manager/src/metrics.rs b/crates/apollo_consensus_manager/src/metrics.rs index 64e965af061..a08e792180f 100644 --- a/crates/apollo_consensus_manager/src/metrics.rs +++ b/crates/apollo_consensus_manager/src/metrics.rs @@ -18,8 +18,9 @@ define_metrics!( LabeledMetricCounter { CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES, "apollo_consensus_proposals_num_dropped_messages", "The number of messages dropped by the consensus p2p component over the Proposals topic", init = 0, labels = NETWORK_BROADCAST_DROP_LABELS }, // Network events - LabeledMetricCounter { CONSENSUS_NETWORK_EVENTS, "apollo_consensus_network_events", "Network events counter by event type for consensus", init = 0, labels = EVENT_TYPE_LABELS } + LabeledMetricCounter { CONSENSUS_NETWORK_EVENTS, "apollo_consensus_network_events", "Network events counter by event type for consensus", init = 0, labels = EVENT_TYPE_LABELS }, + MetricGauge { CONSENSUS_REVERTED_BATCHER_UP_TO_AND_INCLUDING, "apollo_consensus_reverted_batcher_up_to_and_including", "The block number up to which the batcher has reverted"}, }, ); @@ -33,4 +34,5 @@ pub(crate) fn register_metrics() { CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES.register(); CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES.register(); CONSENSUS_NETWORK_EVENTS.register(); + CONSENSUS_REVERTED_BATCHER_UP_TO_AND_INCLUDING.register(); } diff --git a/crates/apollo_reverts/Cargo.toml b/crates/apollo_reverts/Cargo.toml index e8aa635356b..5af23f955e7 100644 --- a/crates/apollo_reverts/Cargo.toml +++ b/crates/apollo_reverts/Cargo.toml @@ -10,6 +10,7 @@ workspace = true [dependencies] apollo_config.workspace = true +apollo_metrics.workspace = true apollo_storage.workspace = true futures.workspace = true serde.workspace = true diff --git a/crates/apollo_reverts/src/lib.rs b/crates/apollo_reverts/src/lib.rs index 533353eebbd..1767ef2383d 100644 --- a/crates/apollo_reverts/src/lib.rs +++ b/crates/apollo_reverts/src/lib.rs @@ -3,6 +3,7 @@ use std::future::Future; use apollo_config::dumping::{ser_param, SerializeConfig}; use apollo_config::{ParamPath, ParamPrivacyInput, SerializedParam}; +use apollo_metrics::metrics::MetricGauge; use apollo_storage::base_layer::BaseLayerStorageWriter; use apollo_storage::body::BodyStorageWriter; use apollo_storage::class_manager::ClassManagerStorageWriter; @@ -54,11 +55,16 @@ impl SerializeConfig for RevertConfig { } } +pub struct RevertComponentData { + pub name: &'static str, + pub revert_metric: MetricGauge, +} + pub async fn revert_blocks_and_eternal_pending( mut storage_height_marker: BlockNumber, revert_up_to_and_including: BlockNumber, mut revert_block_fn: impl FnMut(BlockNumber) -> Fut, - component_name: &str, + component: &RevertComponentData, ) -> Never where Fut: Future, @@ -66,6 +72,7 @@ where // If we revert all blocks up to height X (including), the new height marker will be X. let target_height_marker = revert_up_to_and_including; + let RevertComponentData { name: component_name, revert_metric } = component; if storage_height_marker <= target_height_marker { info!( "{component_name}'s storage height marker {storage_height_marker} is not larger than \ @@ -84,6 +91,7 @@ where ); info!("Reverting {component_name}'s storage to height marker {storage_height_marker}."); revert_block_fn(storage_height_marker).await; + revert_metric.set_lossy(storage_height_marker.0); info!( "Successfully reverted {component_name}'s storage to height marker \ {storage_height_marker}." diff --git a/crates/apollo_state_sync/src/runner/mod.rs b/crates/apollo_state_sync/src/runner/mod.rs index ad55ea5fc97..0e061746bf4 100644 --- a/crates/apollo_state_sync/src/runner/mod.rs +++ b/crates/apollo_state_sync/src/runner/mod.rs @@ -19,7 +19,7 @@ use apollo_p2p_sync::client::{P2pSyncClient, P2pSyncClientChannels, P2pSyncClien use apollo_p2p_sync::server::{P2pSyncServer, P2pSyncServerChannels}; use apollo_p2p_sync::{Protocol, BUFFER_SIZE}; use apollo_p2p_sync_config::config::P2pSyncClientConfig; -use apollo_reverts::{revert_block, revert_blocks_and_eternal_pending}; +use apollo_reverts::{revert_block, revert_blocks_and_eternal_pending, RevertComponentData}; use apollo_rpc::{run_server, RpcConfig}; use apollo_starknet_client::reader::objects::pending_data::{ PendingBlock, @@ -35,6 +35,7 @@ use apollo_state_sync_metrics::metrics::{ P2P_SYNC_NUM_BLACKLISTED_PEERS, P2P_SYNC_NUM_CONNECTED_PEERS, STATE_SYNC_REVERTED_TRANSACTIONS, + STATE_SYNC_REVERTED_UP_TO_AND_INCLUDING, }; use apollo_state_sync_types::state_sync_types::SyncBlock; use apollo_storage::body::BodyStorageReader; @@ -183,6 +184,10 @@ impl StateSyncRunner { async {} }; + const STATE_SYNC_REVERT_COMPONENT_DATA: RevertComponentData = RevertComponentData { + name: "State Sync", + revert_metric: STATE_SYNC_REVERTED_UP_TO_AND_INCLUDING, + }; return ( Self { network_future: pending().boxed(), @@ -190,7 +195,7 @@ impl StateSyncRunner { current_header_marker, revert_up_to_and_including, revert_block_fn, - "State Sync", + &STATE_SYNC_REVERT_COMPONENT_DATA, ) .map(|_never| unreachable!("Never should never be constructed")) .boxed(), diff --git a/crates/apollo_state_sync_metrics/src/metrics.rs b/crates/apollo_state_sync_metrics/src/metrics.rs index 3f39b3b37b3..6e128f534bf 100644 --- a/crates/apollo_state_sync_metrics/src/metrics.rs +++ b/crates/apollo_state_sync_metrics/src/metrics.rs @@ -39,6 +39,8 @@ define_metrics!( MetricGauge { STATE_SYNC_HEADER_LATENCY_SEC, "apollo_state_sync_header_latency", "The latency, in seconds, between a block timestamp (as state in its header) and the time the state sync component stores the header" }, MetricCounter { STATE_SYNC_PROCESSED_TRANSACTIONS, "apollo_state_sync_processed_transactions", "The number of transactions processed by the state sync component since its last restart", init = 0 }, MetricCounter { STATE_SYNC_REVERTED_TRANSACTIONS, "apollo_state_sync_reverted_transactions", "The number of transactions reverted by the state sync component", init = 0 }, + + MetricGauge { STATE_SYNC_REVERTED_UP_TO_AND_INCLUDING, "apollo_state_sync_reverted_up_to_and_including", "The block number up to which the state sync has reverted" }, }, ); @@ -55,6 +57,7 @@ pub async fn register_metrics( STATE_SYNC_REVERTED_TRANSACTIONS.register(); CENTRAL_SYNC_CENTRAL_BLOCK_MARKER.register(); CENTRAL_SYNC_FORKS_FROM_FEEDER.register(); + STATE_SYNC_REVERTED_UP_TO_AND_INCLUDING.register(); let txn = storage_reader.begin_ro_txn().unwrap(); update_marker_metrics(&txn); if should_replay_processed_txs_metric { From 905dcd58a7815063fdd663078edd7ea23cf569df Mon Sep 17 00:00:00 2001 From: Meshi Peled <141231558+meship-starkware@users.noreply.github.com> Date: Sun, 26 Oct 2025 13:10:42 +0200 Subject: [PATCH 141/313] blockifier: update cairo native to 0.7.1 (#9687) --- Cargo.lock | 50 +------------------ Cargo.toml | 2 +- crates/apollo_compile_to_native/build.rs | 2 +- .../apollo_compile_to_native/src/constants.rs | 2 +- 4 files changed, 5 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3e7074acb7..c1a55e3954f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4266,34 +4266,6 @@ dependencies = [ "xshell", ] -[[package]] -name = "cairo-lang-test-plugin" -version = "2.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e90cf75528c423cd6b6faaab2dde0c1b23efe36103e1e57f338293552ee16f" -dependencies = [ - "anyhow", - "cairo-lang-compiler", - "cairo-lang-debug", - "cairo-lang-defs", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-parser", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-generator", - "cairo-lang-starknet", - "cairo-lang-starknet-classes", - "cairo-lang-syntax", - "cairo-lang-utils", - "indoc 2.0.6", - "itertools 0.14.0", - "num-bigint 0.4.6", - "num-traits", - "serde", - "starknet-types-core", -] - [[package]] name = "cairo-lang-test-utils" version = "2.12.3" @@ -4326,33 +4298,23 @@ dependencies = [ [[package]] name = "cairo-native" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a1b73479b3b3676bf81d2e3586f7e7d234227d7bdb6d8635b0256af7a41592" +checksum = "4353361398d63962a78dfeada310701dcff26218ee0aee8754354dc81a5b38a0" dependencies = [ - "anyhow", "aquamarine", "ark-ec 0.5.0", "ark-ff 0.5.0", "ark-secp256k1 0.5.0", "ark-secp256r1 0.5.0", "bumpalo", - "cairo-lang-compiler", - "cairo-lang-defs", - "cairo-lang-filesystem", "cairo-lang-runner", - "cairo-lang-semantic", "cairo-lang-sierra", "cairo-lang-sierra-ap-change", "cairo-lang-sierra-gas", "cairo-lang-sierra-to-casm", - "cairo-lang-starknet", "cairo-lang-starknet-classes", - "cairo-lang-test-plugin", "cairo-lang-utils", - "cc", - "clap", - "colored 2.2.0", "educe 0.5.11", "itertools 0.14.0", "keccak", @@ -4371,11 +4333,9 @@ dependencies = [ "sha2", "starknet-curve", "starknet-types-core", - "stats_alloc", "tempfile", "thiserror 2.0.16", "tracing", - "tracing-subscriber", "utf8_iter", ] @@ -12634,12 +12594,6 @@ dependencies = [ "rand 0.6.5", ] -[[package]] -name = "stats_alloc" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0e04424e733e69714ca1bbb9204c1a57f09f5493439520f9f68c132ad25eec" - [[package]] name = "string_cache" version = "0.8.9" diff --git a/Cargo.toml b/Cargo.toml index 309cbbad2ef..177bfcc8bb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -231,7 +231,7 @@ cairo-lang-sierra = "2.12.3" cairo-lang-sierra-to-casm = "2.12.3" cairo-lang-starknet-classes = "2.12.3" cairo-lang-utils = "2.12.3" -cairo-native = "0.6.2" +cairo-native = "0.7.1" cairo-vm = "2.5.0" camelpaste = "0.1.0" chrono = "0.4.26" diff --git a/crates/apollo_compile_to_native/build.rs b/crates/apollo_compile_to_native/build.rs index 679c5001f0b..3fc1bee6148 100644 --- a/crates/apollo_compile_to_native/build.rs +++ b/crates/apollo_compile_to_native/build.rs @@ -16,7 +16,7 @@ fn install_starknet_native_compile() { let binary_name = CAIRO_NATIVE_BINARY_NAME; let required_version = REQUIRED_CAIRO_NATIVE_VERSION; - let cargo_install_args = &["cairo-native", "--version", required_version, "--bin", binary_name]; + let cargo_install_args = &[binary_name, "--version", required_version]; install_compiler_binary(binary_name, required_version, cargo_install_args, &out_dir()); } diff --git a/crates/apollo_compile_to_native/src/constants.rs b/crates/apollo_compile_to_native/src/constants.rs index 02cf2eeaabd..bbb4531b713 100644 --- a/crates/apollo_compile_to_native/src/constants.rs +++ b/crates/apollo_compile_to_native/src/constants.rs @@ -4,4 +4,4 @@ pub(crate) const CAIRO_NATIVE_BINARY_NAME: &str = "starknet-native-compile"; -pub const REQUIRED_CAIRO_NATIVE_VERSION: &str = "0.6.2"; +pub const REQUIRED_CAIRO_NATIVE_VERSION: &str = "0.7.1"; From bb71ed62aaa4bf99cb2f95979e818c3f72a0203b Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 13:59:43 +0200 Subject: [PATCH 142/313] apollo_dashboard: add a row for reverts (#9764) --- .../resources/dev_grafana.json | 23 +++++++++++++++++++ .../src/dashboard_definitions.rs | 2 ++ crates/apollo_dashboard/src/panels.rs | 1 + crates/apollo_dashboard/src/panels/reverts.rs | 16 +++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 crates/apollo_dashboard/src/panels/reverts.rs diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 7f5e4a902f6..755a7771f44 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -1091,6 +1091,29 @@ ], "collapsed": true }, + "Reverts": { + "panels": [ + { + "title": "apollo_consensus_reverted_batcher_up_to_and_including", + "description": "The block number up to which the batcher has reverted", + "type": "stat", + "exprs": [ + "apollo_consensus_reverted_batcher_up_to_and_including{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + ], + "extra_params": {} + }, + { + "title": "apollo_state_sync_reverted_up_to_and_including", + "description": "The block number up to which the state sync has reverted", + "type": "stat", + "exprs": [ + "apollo_state_sync_reverted_up_to_and_including{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + ], + "extra_params": {} + } + ], + "collapsed": true + }, "StateSyncP2p": { "panels": [ { diff --git a/crates/apollo_dashboard/src/dashboard_definitions.rs b/crates/apollo_dashboard/src/dashboard_definitions.rs index 902fadc6026..e642e51056f 100644 --- a/crates/apollo_dashboard/src/dashboard_definitions.rs +++ b/crates/apollo_dashboard/src/dashboard_definitions.rs @@ -30,6 +30,7 @@ use crate::panels::l1_provider::get_l1_provider_row; use crate::panels::mempool::get_mempool_row; use crate::panels::mempool_p2p::get_mempool_p2p_row; use crate::panels::pod_metrics::get_pod_metrics_row; +use crate::panels::reverts::get_reverts_row; use crate::panels::sierra_compiler::get_compile_to_casm_row; use crate::panels::state_sync::{get_state_sync_p2p_row, get_state_sync_row}; use crate::panels::storage::get_storage_row; @@ -73,6 +74,7 @@ pub fn get_apollo_dashboard() -> Dashboard { get_blockifier_row(), get_compile_to_casm_row(), get_consensus_p2p_row(), + get_reverts_row(), get_state_sync_p2p_row(), get_storage_row(), get_mempool_p2p_row(), diff --git a/crates/apollo_dashboard/src/panels.rs b/crates/apollo_dashboard/src/panels.rs index e4c1287da7c..e39b84f2b7e 100644 --- a/crates/apollo_dashboard/src/panels.rs +++ b/crates/apollo_dashboard/src/panels.rs @@ -9,6 +9,7 @@ pub(crate) mod l1_provider; pub(crate) mod mempool; pub(crate) mod mempool_p2p; pub(crate) mod pod_metrics; +pub(crate) mod reverts; pub(crate) mod sierra_compiler; pub(crate) mod state_sync; pub(crate) mod storage; diff --git a/crates/apollo_dashboard/src/panels/reverts.rs b/crates/apollo_dashboard/src/panels/reverts.rs new file mode 100644 index 00000000000..c641a7cfc89 --- /dev/null +++ b/crates/apollo_dashboard/src/panels/reverts.rs @@ -0,0 +1,16 @@ +use apollo_consensus_manager::metrics::CONSENSUS_REVERTED_BATCHER_UP_TO_AND_INCLUDING; +use apollo_state_sync_metrics::metrics::STATE_SYNC_REVERTED_UP_TO_AND_INCLUDING; + +use crate::dashboard::{Panel, PanelType, Row}; + +fn get_panel_consensus_reverts() -> Panel { + Panel::from_gauge(&CONSENSUS_REVERTED_BATCHER_UP_TO_AND_INCLUDING, PanelType::Stat) +} + +fn get_panel_state_sync_reverts() -> Panel { + Panel::from_gauge(&STATE_SYNC_REVERTED_UP_TO_AND_INCLUDING, PanelType::Stat) +} + +pub(crate) fn get_reverts_row() -> Row { + Row::new("Reverts", vec![get_panel_consensus_reverts(), get_panel_state_sync_reverts()]) +} From 985c09544748be2ad9d661ed7422e91dd49e736e Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 14:00:31 +0200 Subject: [PATCH 143/313] apollo_dashboard: add the CONSENSUS_DECISIONS_REACHED_AS_PROPOSER metric to the dashabord (#9760) --- crates/apollo_dashboard/resources/dev_grafana.json | 9 +++++++++ crates/apollo_dashboard/src/panels/consensus.rs | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 755a7771f44..7c0c5b1230d 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -115,6 +115,15 @@ "unit": "s" } }, + { + "title": "consensus_decisions_reached_as_proposer", + "description": "The total number of rounds with decision reached where this node is the proposer", + "type": "timeseries", + "exprs": [ + "consensus_decisions_reached_as_proposer{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + ], + "extra_params": {} + }, { "title": "Consensus Round Above Zero", "description": "Occurances where the consensus round was 1, relative to displayed range", diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index b8a84d01fdc..0017a7bb004 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -4,6 +4,7 @@ use apollo_consensus::metrics::{ CONSENSUS_BUILD_PROPOSAL_FAILED, CONSENSUS_BUILD_PROPOSAL_TOTAL, CONSENSUS_CONFLICTING_VOTES, + CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, CONSENSUS_DECISIONS_REACHED_BY_SYNC, CONSENSUS_PROPOSALS_INVALID, @@ -432,6 +433,10 @@ fn get_panel_consensus_proposals_dropped_messages_by_reason() -> Panel { ) } +fn get_panel_consensus_decisions_reached_as_proposer() -> Panel { + Panel::from_counter(&CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, PanelType::TimeSeries) +} + pub(crate) fn get_consensus_row() -> Row { Row::new( "Consensus", @@ -440,6 +445,7 @@ pub(crate) fn get_consensus_row() -> Row { get_panel_consensus_round(), get_panel_consensus_round_advanced(), get_panel_consensus_block_time_avg(), + get_panel_consensus_decisions_reached_as_proposer(), get_panel_consensus_round_above_zero(), get_panel_consensus_block_number_diff_from_sync(), get_panel_consensus_decisions_reached_by_consensus(), From 255e39c1133f92324fa1b8930568dc1280f6b200 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 14:04:04 +0200 Subject: [PATCH 144/313] scripts: copy prod scripts from 0.14.1 to 0.14.0 (#9763) --- scripts/prod/restart_all_nodes_together.py | 143 +++++ scripts/prod/set_node_revert_mode.py | 191 ++++++ .../prod/update_config_and_restart_nodes.py | 165 +++++ .../update_config_and_restart_nodes_lib.py | 595 ++++++++++++++++++ 4 files changed, 1094 insertions(+) create mode 100755 scripts/prod/restart_all_nodes_together.py create mode 100755 scripts/prod/set_node_revert_mode.py create mode 100755 scripts/prod/update_config_and_restart_nodes.py create mode 100755 scripts/prod/update_config_and_restart_nodes_lib.py diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_nodes_together.py new file mode 100755 index 00000000000..d7381d8575b --- /dev/null +++ b/scripts/prod/restart_all_nodes_together.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +from typing import Optional + +import urllib.error +import urllib.parse +import urllib.request +from update_config_and_restart_nodes_lib import ( + ApolloArgsParserBuilder, + RestartStrategy, + Service, + get_configmap, + get_context_list_from_args, + get_current_block_number, + get_logs_explorer_url, + get_namespace_list_from_args, + parse_config_from_yaml, + print_colored, + update_config_and_restart_nodes, +) + + +# TODO(guy.f): Remove this once we have metrics we use to decide based on. +def get_logs_explorer_url_for_proposal( + namespace: str, + validator_id: str, + min_block_number: int, + project_name: str, +) -> str: + # Remove the 0x prefix from the validator id to get the number. + validator_id = validator_id[2:] + + query = ( + f'resource.labels.namespace_name:"{urllib.parse.quote(namespace)}"\n' + f'resource.labels.container_name="sequencer-core"\n' + f'textPayload =~ "DECISION_REACHED:.*proposer 0x0*{validator_id}"\n' + f'CAST(REGEXP_EXTRACT(textPayload, "height: (\\\\d+)"), "INT64") > {min_block_number}' + ) + return get_logs_explorer_url(query, project_name) + + +def get_validator_id(namespace: str, context: Optional[str]) -> str: + # Get current config and normalize it (e.g. " vs ') to ensure not showing bogus diffs. + original_config = get_configmap(namespace, context, Service.Core) + _, config_data = parse_config_from_yaml(original_config) + + return config_data["validator_id"] + + +def main(): + usage_example = """ +Examples: + # Restart all nodes at once. + %(prog)s --namespace-prefix apollo-sepolia-integration --num-nodes 3 --feeder-url feeder.integration-sepolia.starknet.io --project-name my-gcp-project + %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + + # Restart nodes with cluster prefix + %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + + # Restart nodes starting from specific node index + %(prog)s -n apollo-sepolia-integration -m 3 -s 5 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + + # Use different feeder URL + %(prog)s -n apollo-sepolia-integration -m 3 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + + # Use namespace list instead of prefix (restart specific namespaces) + %(prog)s --namespace-list apollo-sepolia-integration-0 apollo-sepolia-integration-2 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + %(prog)s -N apollo-sepolia-integration-0 apollo-sepolia-integration-2 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + + # Use cluster list for multiple clusters (only works with namespace-list, not namespace-prefix) + %(prog)s -N apollo-sepolia-integration-0 apollo-sepolia-integration-1 -C cluster1 cluster2 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + %(prog)s --namespace-list apollo-sepolia-integration-0 apollo-sepolia-integration-1 --cluster-list cluster1 cluster2 -f feeder.integration-sepolia.starknet.io --project-name my-gcp-project + """ + + args_builder = ApolloArgsParserBuilder( + "Restart all nodes using the value from the feeder URL", + usage_example, + include_restart_strategy=False, + ) + + args_builder.add_argument( + "-f", + "--feeder-url", + required=True, + type=str, + help="The feeder URL to get the current block from", + ) + + # TODO(guy.f): Remove this when we rely on metrics for restarting. + args_builder.add_argument( + "--project-name", + required=True, + help="The name of the project to get logs from.", + ) + + args = args_builder.build() + + # Get current block number from feeder URL + current_block_number = get_current_block_number(args.feeder_url) + next_block_number = current_block_number + 1 + + print_colored(f"Current block number: {current_block_number}") + print_colored(f"Next block number: {next_block_number}") + + config_overrides = { + "consensus_manager_config.cende_config.skip_write_height": next_block_number, + "consensus_manager_config.immediate_active_height": next_block_number, + } + + namespace_list = get_namespace_list_from_args(args) + context_list = get_context_list_from_args(args) + if context_list is not None: + assert len(namespace_list) == len( + context_list + ), "namespace_list and context_list must have the same length" + + # Generate logs explorer URLs if needed + post_restart_instructions = [] + + for namespace, context in zip(namespace_list, context_list or [None] * len(namespace_list)): + url = get_logs_explorer_url_for_proposal( + namespace, + get_validator_id(namespace, context), + # Feeder could be behind by up to 10 blocks, so we add 10 to the current block number. + current_block_number + 10, + args.project_name, + ) + post_restart_instructions.append( + f"Please check logs and verify that the node has proposed a block that was accepted. Logs URL: {url}" + ) + + update_config_and_restart_nodes( + config_overrides, + namespace_list, + Service.Core, + context_list, + RestartStrategy.ALL_AT_ONCE, + post_restart_instructions, + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py new file mode 100755 index 00000000000..19ab8bdbefa --- /dev/null +++ b/scripts/prod/set_node_revert_mode.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 + +import sys +from typing import Optional + +import urllib.parse +from update_config_and_restart_nodes_lib import ( + ApolloArgsParserBuilder, + RestartStrategy, + Service, + get_context_list_from_args, + get_current_block_number, + get_logs_explorer_url, + get_namespace_list_from_args, + print_colored, + print_error, + update_config_and_restart_nodes, +) + + +# TODO(guy.f): Remove this once we have metrics we use to decide based on. +def get_logs_explorer_url_for_revert( + namespace: str, + block_number: int, + project_name: str, +) -> str: + query = ( + f'resource.labels.namespace_name:"{urllib.parse.quote(namespace)}"\n' + f'resource.labels.container_name="sequencer-core"\n' + f'textPayload =~ "Done reverting.*storage up to height {block_number}"' + ) + return get_logs_explorer_url(query, project_name) + + +def set_revert_mode( + namespace_list: list[str], + context_list: Optional[list[str]], + project_name: str, + should_revert: bool, + revert_up_to_block: int, + restart_strategy: RestartStrategy, +): + config_overrides = { + "revert_config.should_revert": should_revert, + "revert_config.revert_up_to_and_including": revert_up_to_block, + } + + post_restart_instructions = [] + for namespace, context in zip(namespace_list, context_list): + url = get_logs_explorer_url_for_revert(namespace, revert_up_to_block, project_name) + + post_restart_instructions.append( + f"Please check logs and verify that revert has completed (both in the batcher and for sync). Logs URL: {url}" + ) + + update_config_and_restart_nodes( + config_overrides, + namespace_list, + Service.Core, + context_list, + restart_strategy, + post_restart_instructions, + ) + + +def main(): + usage_example = """ +Examples: + # Set revert mode up to a specific block + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --revert-only --revert_up_to_block 12345 + %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -b 12345 + + # Set revert mode using feeder URL to get current block + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --revert-only --feeder-url feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io + + # Disable revert mode + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --disable-revert-only + %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --disable-revert-only + + # Set revert mode with cluster prefix + %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster -t all_at_once --revert-only -b 12345 + + # Set revert mode with feeder URL and cluster prefix + %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io + + # Disable revert mode without restarting nodes + %(prog)s -n apollo-sepolia-integration -N 3 -t no_restart --disable-revert-only + + # Set revert mode with explicit restart + %(prog)s -n apollo-sepolia-integration -N 3 -t all_at_once --revert-only -b 12345 + + # Set revert mode with feeder URL and explicit restart + %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io + + # Set revert mode starting from specific node index + %(prog)s -n apollo-sepolia-integration -N 3 -i 5 -t all_at_once --revert-only -b 12345 + + # Set revert mode with feeder URL starting from specific node index + %(prog)s -n apollo-sepolia-integration -N 3 -i 5 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io + """ + + args_builder = ApolloArgsParserBuilder( + "Sets or unsets the revert mode for the sequencer nodes", usage_example + ) + + revert_group = args_builder.parser.add_mutually_exclusive_group() + revert_group.add_argument("--revert-only", action="store_true", help="Enable revert mode") + revert_group.add_argument( + "--disable-revert-only", action="store_true", help="Disable revert mode" + ) + + args_builder.add_argument( + "-b", + "--revert-up-to-block", + type=int, + help="Block number up to which to revert (inclusive). Must be a positive integer.", + ) + + args_builder.add_argument( + "-f", + "--feeder-url", + type=str, + help="The feeder URL to get the current block from. We will revert all blocks above it.", + ) + + # TODO(guy.f): Remove this when we rely on metrics for restarting. + args_builder.add_argument( + "--project-name", + help="The name of the project to get logs from. If One_By_One strategy is used, this is required.", + ) + + args = args_builder.build() + + if args.restart_strategy == RestartStrategy.ONE_BY_ONE and args.project_name is None: + print_error("Error: --project-name is required when using One_By_One strategy") + sys.exit(1) + + should_revert = not args.disable_revert_only + if should_revert: + if args.feeder_url is None and args.revert_up_to_block is None: + print_error( + "Error: Either --feeder-url or --revert_up_to_block (-b) are required when reverting is requested." + ) + sys.exit(1) + if args.feeder_url is not None and args.revert_up_to_block is not None: + print_error("Error: Cannot specify both --feeder-url and --revert_up_to_block (-b).") + sys.exit(1) + + if args.disable_revert_only: + if args.feeder_url is not None: + print_error("Error: --feeder-url cannot be set when using --disable-revert-only") + sys.exit(1) + if args.revert_up_to_block is not None: + print_error("Error: --revert-up-to-block (-b) cannot be set when disabling revert.") + sys.exit(1) + + namespace_list = get_namespace_list_from_args(args) + context_list = get_context_list_from_args(args) + + should_disable_revert = not args.revert_only + if should_revert: + revert_up_to_block = ( + args.revert_up_to_block + if args.revert_up_to_block is not None + else get_current_block_number(args.feeder_url) + ) + f"\nEnabling revert mode up to (and including) block {revert_up_to_block}" + set_revert_mode( + namespace_list, + context_list, + args.project_name, + True, + revert_up_to_block, + args.restart_strategy, + ) + if should_disable_revert: + print_colored(f"\nDisabling revert mode") + # Setting to max block to max u64. + set_revert_mode( + namespace_list, + context_list, + args.project_name, + False, + 18446744073709551615, + args.restart_strategy, + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py new file mode 100755 index 00000000000..0f0ccf1b609 --- /dev/null +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 + +import argparse +import json +import sys +from typing import Any + +from update_config_and_restart_nodes_lib import ( + ApolloArgsParserBuilder, + Colors, + Service, + get_context_list_from_args, + get_namespace_list_from_args, + print_colored, + print_error, + update_config_and_restart_nodes, +) + + +def parse_config_overrides(config_overrides: list[str]) -> dict[str, Any]: + """Parse config override strings in key=value format. + + Args: + config_overrides: List of strings in "key=value" format + + Returns: + dict: Dictionary mapping config keys to their values + """ + if not config_overrides: + return {} + + overrides = {} + for override in config_overrides: + if "=" not in override: + print_colored( + f"Error: Invalid config override format '{override}'. Expected 'key=value'", + Colors.RED, + file=sys.stderr, + ) + sys.exit(1) + + # Split only on first '=' in case value contains '=' + key, value = override.split("=", 1) + key = key.strip() + value = value.strip() + + if not key: + print_error(f"Error: Empty key in config override '{override}'") + sys.exit(1) + + # Try to convert value to appropriate type + try: + overrides[key] = json.loads(value) + except (json.JSONDecodeError, TypeError) as e: + print_error( + f"Error: Invalid value '{value}' for key '{key}': {e}\n" + 'Did you remember to wrap string values in \\" ?' + ) + sys.exit(1) + + if not overrides: + print_error("Error: No valid config overrides found") + sys.exit(1) + + return overrides + + +def service_type_converter(service_name: str) -> Service: + """Convert string to Service enum with informative error message""" + if service_name.startswith("Service."): + service_name = service_name[8:] + + service_name = service_name.lower() + + try: + return Service[service_name] + except KeyError: + valid_services = ", ".join([service.name for service in Service]) + raise argparse.ArgumentTypeError( + f"Invalid service type '{service_name}'. Valid options are: {valid_services}" + ) + + +def main(): + usage_example = """ +Examples: + # Basic usage with namespace prefix and node count + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once --config-overrides consensus_manager_config.timeout=5000 --config-overrides validator_id=0x42 + + # Using namespace list mode (no num-nodes or start-index allowed) + %(prog)s -N apollo-sepolia-test-0 apollo-sepolia-test-1 apollo-sepolia-test-2 -t one_by_one --config-overrides consensus_manager_config.timeout=5000 + + # Using cluster prefix with namespace prefix + %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster -t all_at_once --config-overrides validator_id=0x42 + + # Using cluster list with namespace list (must have same number of items) + %(prog)s -N apollo-sepolia-test-0 apollo-sepolia-test-2 -C cluster0 cluster2 -t one_by_one --config-overrides validator_id=0x42 + + # Update different service types + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once -j Gateway --config-overrides gateway_config.port=8080 + %(prog)s -n apollo-sepolia-integration -m 3 -t one_by_one -j Mempool --config-overrides mempool_config.max_size=1000 + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once -j L1 --config-overrides l1_config.endpoint=\"https://eth-mainnet.alchemyapi.io/v2/your-key\" + %(prog)s -n apollo-sepolia-integration -m 3 -t one_by_one -j HttpServer --config-overrides http_server_config.port=8081 + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once -j SierraCompiler --config-overrides sierra_compiler_config.timeout=30000 + + # Update starting from specific node index + %(prog)s -n apollo-sepolia-integration -m 3 -s 5 -t one_by_one --config-overrides validator_id=0x42 + + # Update without restart + %(prog)s -n apollo-sepolia-integration -m 3 -t no_restart --config-overrides validator_id=0x42 + + # Update with explicit restart (all at once) + %(prog)s -n apollo-sepolia-integration -m 3 -t all_at_once --config-overrides validator_id=0x42 + + # Complex example with multiple config overrides + %(prog)s -n apollo-sepolia-integration -m 3 -c my-cluster -t one_by_one -j Core --config-overrides consensus_manager_config.timeout=5000 --config-overrides validator_id=0x42 --config-overrides components.gateway.url=\"localhost\" + + """ + + args_builder = ApolloArgsParserBuilder( + "Update configuration for Apollo sequencer nodes and (optionally) restart them", + usage_example, + ) + + args_builder.add_argument( + "-o", + "--config-overrides", + action="append", + help="Configuration overrides in key=value format. Can be specified multiple times. " + "Example: --config-overrides consensus_manager_config.timeout=5000 " + '--config-overrides components.gateway.url=\\"localhost\\" (note the escaping of the ")', + ) + + args_builder.add_argument( + "-j", + "--service", + type=service_type_converter, + choices=list(Service), + default=Service.Core, + help="Service type to operate on; determines configmap and pod names (default: Core)", + ) + + args = args_builder.build() + config_overrides = parse_config_overrides(args.config_overrides) + + if config_overrides: + print_colored(f"\nConfig overrides to apply:") + for key, value in config_overrides.items(): + print_colored(f" {key} = {value}") + else: + print_error("No config overrides provided") + sys.exit(1) + + update_config_and_restart_nodes( + config_overrides, + get_namespace_list_from_args(args), + args.service, + get_context_list_from_args(args), + args.restart_strategy, + None, + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py new file mode 100755 index 00000000000..43d563da4c7 --- /dev/null +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -0,0 +1,595 @@ +#!/usr/bin/env python3 + +import argparse +import json +import subprocess +import sys +from enum import Enum +from typing import Any, Optional + +import tempfile +import urllib.error +import urllib.parse +import urllib.request +import yaml +from difflib import unified_diff + + +class Colors(Enum): + """ANSI color codes for terminal output""" + + RED = "\033[1;31m" + GREEN = "\033[1;32m" + YELLOW = "\033[1;33m" + BLUE = "\033[1;34m" + RESET = "\033[0m" + + +def print_colored(message: str, color: Colors = Colors.RESET, file=sys.stdout) -> None: + """Print message with color""" + print(f"{color.value}{message}{Colors.RESET.value}", file=file) + + +def print_error(message: str) -> None: + print_colored(message, color=Colors.RED, file=sys.stderr) + + +class ApolloArgsParserBuilder: + """Builder class for creating argument parsers with required flags and custom arguments.""" + + # TODO(guy.f): If we need to exclude more than just the restart flag, create a more generic mechanism. + def __init__(self, description: str, usage_example: str, include_restart_strategy: bool = True): + """Initialize the builder with usage example for epilog. + + Args: + usage_example: String containing usage examples to be used as epilog + """ + self.usage_example = usage_example + self.parser = argparse.ArgumentParser( + description=description, + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=usage_example, + ) + + self._add_common_flags(include_restart_strategy) + + def _add_common_flags(self, include_restart_strategy: bool): + """Add all common flags. + + Args: + include_restart_strategy: Whether to include the restart strategy flag. + """ + namespace_group = self.parser.add_mutually_exclusive_group(required=True) + namespace_group.add_argument( + "-n", + "--namespace-prefix", + help="The Kubernetes namespace prefix (e.g., apollo-sepolia-integration)", + ) + namespace_group.add_argument( + "-N", + "--namespace-list", + nargs="+", + help="Space separated list of namespaces e.g., '--namespace-list apollo-sepolia-integration-0 apollo-sepolia-integration-2'", + ) + + self.parser.add_argument( + "-m", + "--num-nodes", + type=int, + help="The number of nodes to restart (required when specifying namespace-prefix)", + ) + + self.parser.add_argument( + "-s", + "--start-index", + type=int, + default=0, + help="The starting index for node IDs (default: 0)", + ) + + cluster_group = self.parser.add_mutually_exclusive_group() + cluster_group.add_argument( + "-c", "--cluster-prefix", help="Optional cluster prefix for kubectl context" + ) + cluster_group.add_argument( + "-C", + "--cluster-list", + nargs="+", + help="Space separated list of cluster names for kubectl contexts", + ) + + if include_restart_strategy: + self.add_argument( + "-t", + "--restart-strategy", + type=restart_strategy_converter, + choices=list(RestartStrategy), + required=True, + help="Strategy for restarting nodes", + ) + + def add_argument(self, *args, **kwargs): + """Add a new argument to the parser. + + Args: + *args: Positional arguments passed to parser.add_argument + **kwargs: Keyword arguments passed to parser.add_argument + """ + self.parser.add_argument(*args, **kwargs) + return self + + def build(self) -> argparse.Namespace: + """Build the argument parser, parse arguments, validate them, and return the result. + + Returns: + argparse.Namespace: The parsed and validated arguments + """ + args = self.parser.parse_args() + validate_arguments(args) + return args + + +class Service(Enum): + """Service types mapping to their configmap and pod names.""" + + Core = ("sequencer-core-config", "sequencer-core-statefulset-0") + Gateway = ("sequencer-gateway-config", "sequencer-gateway-deployment") + HttpServer = ( + "sequencer-httpserver-config", + "sequencer-httpserver-deployment", + ) + L1 = ("sequencer-l1-config", "sequencer-l1-deployment") + Mempool = ("sequencer-mempool-config", "sequencer-mempool-deployment") + SierraCompiler = ( + "sequencer-sierracompiler-config", + "sequencer-sierracompiler-deployment", + ) + + def __init__(self, config_map_name: str, pod_name: str) -> None: + self.config_map_name = config_map_name + self.pod_name = pod_name + + +class RestartStrategy(Enum): + """Strategy for restarting nodes.""" + + ALL_AT_ONCE = "all_at_once" + ONE_BY_ONE = "one_by_one" + NO_RESTART = "no_restart" + + +def restart_strategy_converter(strategy_name: str) -> RestartStrategy: + """Convert string to RestartStrategy enum with informative error message""" + RESTART_STRATEGY_PREFIX = f"{RestartStrategy.__name__}." + if strategy_name.startswith(RESTART_STRATEGY_PREFIX): + strategy_name = strategy_name[len(RESTART_STRATEGY_PREFIX) :] + + strategy_name = strategy_name.lower() + + try: + return RestartStrategy(strategy_name) + except KeyError: + valid_strategies = ", ".join([strategy.value for strategy in RestartStrategy]) + raise argparse.ArgumentTypeError( + f"Invalid restart strategy '{strategy_name}'. Valid options are: {valid_strategies}" + ) + + +def validate_arguments(args: argparse.Namespace) -> None: + if (args.namespace_list and args.cluster_prefix) or ( + args.namespace_prefix and args.cluster_list + ): + print_error("Error: Use either list mode or prefix mode. You cannot mix them.") + sys.exit(1) + + if args.namespace_list: + # List mode. + if args.start_index != 0: + print_error("Error: start-index cannot be set when namespace-list is specified.") + sys.exit(1) + if args.num_nodes: + print_error("Error: num-nodes cannot be set when namespace-list is specified.") + sys.exit(1) + if args.cluster_list: + if len(args.cluster_list) != len(args.namespace_list): + print_error( + "Error: cluster-list and namespace-list must have the same number of values." + ) + sys.exit(1) + else: + # Prefix mode. + if args.num_nodes is None: + print_error("Error: num-nodes is required when not in namespace-list mode.") + sys.exit(1) + + if args.num_nodes <= 0: + print_error("Error: num-nodes must be a positive integer.") + sys.exit(1) + + if args.start_index < 0: + print_error("Error: start-index must be a non-negative integer.") + sys.exit(1) + + +def get_namespace_list_from_args( + args: argparse.Namespace, +) -> list[str]: + """Get a list of namespaces based on the arguments""" + if args.namespace_list: + return args.namespace_list + + return [ + f"{args.namespace_prefix}-{i}" + for i in range(args.start_index, args.start_index + args.num_nodes) + ] + + +def get_context_list_from_args( + args: argparse.Namespace, +) -> list[str]: + """Get a list of contexts based on the arguments""" + if args.cluster_list: + return args.cluster_list + + if args.cluster_prefix is None: + return None + + return [ + f"{args.cluster_prefix}-{i}" + for i in range(args.start_index, args.start_index + args.num_nodes) + ] + + +def get_logs_explorer_url( + query: str, + project_name: Optional[str] = None, +) -> str: + # We need to double escape '(' and ')', so first we replace only them with their escaped versions. + query = query.replace("(", urllib.parse.quote("(")).replace(")", urllib.parse.quote(")")) + + # Now "normal" escape everything else + query = urllib.parse.quote(query) + + escaped_project_name = urllib.parse.quote(project_name) + return ( + f"https://console.cloud.google.com/logs/query;query={query}" + f"?project={escaped_project_name}" + ) + + +def get_current_block_number(feeder_url: str) -> int: + """Get the current block number from the feeder URL.""" + try: + url = f"https://{feeder_url}/feeder_gateway/get_block" + with urllib.request.urlopen(url) as response: + if response.status != 200: + raise urllib.error.HTTPError( + url, response.status, "HTTP Error", response.headers, None + ) + data = json.loads(response.read().decode("utf-8")) + current_block_number = data["block_number"] + return current_block_number + + except urllib.error.URLError as e: + print_error(f"Failed to fetch block number from feeder URL: {e}") + sys.exit(1) + except KeyError as e: + print_error(f"Unexpected response format from feeder URL: {e}") + sys.exit(1) + except json.JSONDecodeError as e: + print_error(f"Failed to parse JSON response from feeder URL: {e}") + sys.exit(1) + + +def run_kubectl_command(args: list, capture_output: bool = True) -> subprocess.CompletedProcess: + full_command = ["kubectl"] + args + try: + result = subprocess.run(full_command, capture_output=capture_output, text=True, check=True) + return result + except subprocess.CalledProcessError as e: + print_error(f"kubectl command failed: {' '.join(full_command)}") + print_error(f"Error: {e.stderr}") + sys.exit(1) + + +def get_namespace_args(namespace: str, cluster: Optional[str] = None) -> list[str]: + ret = ["-n", f"{namespace}"] + if cluster: + ret.extend(["--context", f"{cluster}"]) + return ret + + +def get_configmap( + namespace: str, + cluster: Optional[str] = None, + service: Service = Service.Core, +) -> str: + """Get configmap YAML for a specific node""" + kubectl_args = [ + "get", + "cm", + service.config_map_name, + "-o", + "yaml", + ] + kubectl_args.extend(get_namespace_args(namespace, cluster)) + + result = run_kubectl_command(kubectl_args) + return result.stdout + + +def parse_config_from_yaml(config_content: str) -> tuple[dict, dict]: + """Parse YAML config and extract the JSON configuration data. + + Returns: + tuple: (full_config_dict, parsed_json_config_dict) + parsed_json_config_dict: The internal config dictionary, as parsed from the config string. + """ + # Parse YAML + try: + config = yaml.safe_load(config_content) + except yaml.YAMLError as e: + print_error(f"Error parsing YAML: {e}") + sys.exit(1) + + # The actual configuration is stored in the data section as a flattened config string + if "config" not in config.get("data", {}): + print_error("Error: Expected config not found in configmap") + sys.exit(1) + + # Parse the flattened config format + try: + config_str = config["data"]["config"].strip() + # Parse the JSON-like config string + config_data = json.loads(config_str) + except json.JSONDecodeError as e: + print_error(f"Error parsing config JSON: {e}") + sys.exit(1) + + return config, config_data + + +def serialize_config_to_yaml(full_config: dict, config_data: dict) -> str: + """Serialize configuration data back to YAML format. + + Args: + full_config: The full YAML configuration dictionary + config_data: The JSON configuration data to serialize and inject into the YAML config. + + Returns: + str: The serialized YAML content + """ + + def represent_literal_str(dumper, data): + """Custom representer for making sure that multi-line strings are represented as literal strings (using |)""" + if "\n" in data: + return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|") + return dumper.represent_scalar("tag:yaml.org,2002:str", data) + + # Put the updated config back into the YAML + full_config["data"]["config"] = json.dumps(config_data, indent=2) + + # Configure YAML dumper to use literal style for multi-line strings (see represent_literal_str). + yaml.add_representer(str, represent_literal_str) + + # Convert back to YAML + try: + result = yaml.dump(full_config, default_flow_style=False, allow_unicode=True) + finally: + # Clean up the custom representer to avoid affecting other YAML operations + yaml.add_representer(str, yaml.representer.SafeRepresenter.represent_str) + + return result + + +def update_config_values( + config_content: str, + config_overrides: dict[str, Any] = None, +) -> str: + """Update configuration values in the YAML content and return the updated YAML""" + # Parse the configuration + config, config_data = parse_config_from_yaml(config_content) + + for key, value in config_overrides.items(): + print_colored(f" Overriding config: {key} = {value}") + config_data[key] = value + + # Serialize back to YAML + return serialize_config_to_yaml(config, config_data) + + +def normalize_config(config_content: str) -> str: + """Normalize configuration by parsing and re-serializing without changes. + + This ensures consistent formatting for accurate diff comparison. + """ + config, config_data = parse_config_from_yaml(config_content) + return serialize_config_to_yaml(config, config_data) + + +def show_config_diff(old_content: str, new_content: str, index: int) -> None: + print_colored( + f"--------------------- Config changes {index} --------------------", + Colors.YELLOW, + ) + + old_lines = old_content.splitlines(keepends=True) + new_lines = new_content.splitlines(keepends=True) + + diff = unified_diff( + old_lines, + new_lines, + fromfile=f"config{index}.yaml_old", + tofile=f"config{index}.yaml", + lineterm="", + ) + + diff_output = "".join(diff) + if diff_output: + print_colored(diff_output) + else: + print_colored("No changes detected", Colors.BLUE) + + +def ask_for_confirmation() -> bool: + """Ask user for confirmation to proceed""" + response = ( + input(f"{Colors.BLUE.value}Do you approve these changes? (y/n){Colors.RESET.value}") + .strip() + .lower() + ) + return response == "y" + + +def wait_until_y_or_n(question: str) -> bool: + """Wait until user enters y or n. Cotinues asking until user enters y or n.""" + while True: + response = input(f"{Colors.BLUE.value}{question} (y/n){Colors.RESET.value}").strip().lower() + if response == "y" or response == "n": + break + print_error(f"Invalid response: {response}") + return response == "y" + + +def apply_configmap( + config_content: str, + namespace: str, + index: int, + cluster: Optional[str] = None, +) -> None: + """Apply updated configmap""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: + f.write(config_content) + temp_file = f.name + + try: + kubectl_args = ["apply", "-f", temp_file] + kubectl_args.extend(get_namespace_args(namespace, cluster)) + + run_kubectl_command(kubectl_args, capture_output=False) + + except Exception as e: + print_error(f"Failed applying config for index {index}: {e}") + sys.exit(1) + + +def restart_pod( + namespace: str, service: Service, index: int, cluster: Optional[str] = None +) -> None: + """Restart pod by deleting it""" + # Get the list of pods (one string per line). + kubectl_args = [ + "get", + "pods", + "-o", + "name", + ] + pods = run_kubectl_command(kubectl_args, capture_output=True).stdout.splitlines() + + # Filter the list of pods to only include the ones that match the service and extract the pod name. + pods = [pod.split("/")[1] for pod in pods if pod.startswith(f"pod/{service.pod_name}")] + + if not pods: + print_error(f"Could not find pods for service {service.pod_name}.") + sys.exit(1) + + # Go over each pod and delete it. + for pod in pods: + kubectl_args = [ + "delete", + "pod", + pod, + ] + kubectl_args.extend(get_namespace_args(namespace, cluster)) + + try: + run_kubectl_command(kubectl_args, capture_output=False) + print_colored(f"Restarted {pod} for node {index}") + except Exception as e: + print_error(f"Failed restarting {pod} for node {index}: {e}") + sys.exit(1) + + +def update_config_and_restart_nodes( + config_overrides: dict[str, Any], + namespace_list: list[str], + service: Service, + cluster_list: Optional[list[str]], + restart_strategy: RestartStrategy, + # TODO(guy.f): Add more abstraction to restart strategy so that the instructions are abstracted as part of it. + post_restart_instructions: Optional[list[str]] = None, +) -> None: + assert config_overrides is not None, "config_overrides must be provided" + assert namespace_list is not None and len(namespace_list) > 0, "namespaces must be provided" + + if post_restart_instructions is not None: + assert len(post_restart_instructions) == len( + namespace_list + ), f"post_restart_instructions must have the same length as namespace_list. logs_explorer_urls: {len(post_restart_instructions)}, namespace_list: {len(namespace_list)}" + + if not cluster_list: + print_colored( + "cluster-prefix/cluster-list not provided. Assuming all nodes are on the current cluster", + Colors.RED, + ) + else: + assert len(cluster_list) == len( + namespace_list + ), f"cluster_list must have the same number of values as namespace_list. cluster_list: {cluster_list}, namespace_list: {namespace_list}" + + # Store original and updated configs for all nodes + configs = [] + + # Process each node's configuration + for index, namespace in enumerate(namespace_list): + cluster = cluster_list[index] if cluster_list else None + print_colored( + f"\nProcessing node for namespace {namespace} (cluster: {cluster if cluster else 'current cluster'})..." + ) + + # Get current config and normalize it (e.g. " vs ') to ensure not showing bogus diffs. + original_config = normalize_config(get_configmap(namespace, cluster, service)) + + # Update config + updated_config = update_config_values(original_config, config_overrides) + + # Store configs + configs.append({"original": original_config, "updated": updated_config}) + + # Show diff + show_config_diff(original_config, updated_config, index) + + if not ask_for_confirmation(): + print_error("Operation cancelled by user") + sys.exit(1) + + # Apply all configurations + print_colored("\nApplying configurations...") + for index, config in enumerate(configs): + print(f"Applying config {index}...") + apply_configmap( + config["updated"], + namespace_list[index], + index, + cluster_list[index] if cluster_list else None, + ) + + if restart_strategy != RestartStrategy.NO_RESTART: + for index, config in enumerate(configs): + restart_pod( + namespace_list[index], service, index, cluster_list[index] if cluster_list else None + ) + instructions = post_restart_instructions[index] if post_restart_instructions else None + print_colored(f"Restarted pod.\n{instructions if instructions else ''} ", Colors.YELLOW) + if restart_strategy == RestartStrategy.ONE_BY_ONE: + # Don't ask in the case of the last job. + if index != len(configs) - 1 and not wait_until_y_or_n( + f"Do you want to restart the next pod?" + ): + print_colored("\nAborting restart process.") + return + print_colored("\nAll pods have been successfully restarted!", Colors.GREEN) + else: + print_colored("\nSkipping pod restart.") + + print("\nOperation completed successfully!") From 392848a5076497077475770e3eb70d0ea8bbf502 Mon Sep 17 00:00:00 2001 From: Meshi Peled <141231558+meship-starkware@users.noreply.github.com> Date: Sun, 26 Oct 2025 14:46:07 +0200 Subject: [PATCH 145/313] blockifier: move the block of poesidon transactions to declare run_execute (#9649) --- crates/apollo_rpc_execution/src/test_utils.rs | 3 ++ .../src/transaction/account_transaction.rs | 8 ----- .../transaction/account_transactions_test.rs | 33 +++++++++++++------ .../src/transaction/transactions.rs | 16 +++++++-- .../src/transaction/transactions_test.rs | 2 +- .../src/py_block_executor.rs | 5 +++ 6 files changed, 46 insertions(+), 21 deletions(-) diff --git a/crates/apollo_rpc_execution/src/test_utils.rs b/crates/apollo_rpc_execution/src/test_utils.rs index 3c35ca0b47c..14f0cedf6de 100644 --- a/crates/apollo_rpc_execution/src/test_utils.rs +++ b/crates/apollo_rpc_execution/src/test_utils.rs @@ -21,6 +21,7 @@ use starknet_api::block::{ GasPrice, GasPricePerToken, }; +use starknet_api::contract_class::compiled_class_hash::{HashVersion, HashableCompiledClass}; use starknet_api::contract_class::SierraVersion; use starknet_api::core::{ChainId, ClassHash, ContractAddress, Nonce, SequencerContractAddress}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; @@ -294,12 +295,14 @@ impl TxsScenarioBuilder { } pub fn declare_class(mut self, sender_address: ContractAddress) -> TxsScenarioBuilder { + let casm = get_test_casm(); let tx = ExecutableTransactionInput::DeclareV2( DeclareTransactionV2 { max_fee: *MAX_FEE, sender_address, nonce: self.next_nonce(sender_address), class_hash: self.next_class_hash(), + compiled_class_hash: casm.hash(&HashVersion::V2), ..Default::default() }, get_test_casm(), diff --git a/crates/blockifier/src/transaction/account_transaction.rs b/crates/blockifier/src/transaction/account_transaction.rs index 5133541feb0..0e30a4d2a3f 100644 --- a/crates/blockifier/src/transaction/account_transaction.rs +++ b/crates/blockifier/src/transaction/account_transaction.rs @@ -561,14 +561,6 @@ impl AccountTransaction { execute_call_info = self.run_execute(state, &mut execution_context, remaining_gas)?; validate_call_info = self.validate_tx(state, tx_context.clone(), remaining_gas)?; } else { - // TODO(Meshi): Find a better way to handle tests non V3 transactions. - if tx_context.block_context.versioned_constants.block_casm_hash_v1_declares - && self.tx.version() >= TransactionVersion::THREE - { - if let Transaction::Declare(declare_tx) = &self.tx { - declare_tx.check_compile_class_hash_v2_declaration()?; - } - } validate_call_info = self.validate_tx(state, tx_context.clone(), remaining_gas)?; let mut execution_context = EntryPointExecutionContext::new_invoke( tx_context.clone(), diff --git a/crates/blockifier/src/transaction/account_transactions_test.rs b/crates/blockifier/src/transaction/account_transactions_test.rs index 9618a1356ee..8a7b3b956d7 100644 --- a/crates/blockifier/src/transaction/account_transactions_test.rs +++ b/crates/blockifier/src/transaction/account_transactions_test.rs @@ -893,23 +893,30 @@ fn test_fail_declare(block_context: BlockContext, max_fee: Fee) { class_hash: class_hash!(7_u64), compiled_class_hash: CompiledClassHash(8_u64.into()), ..Default::default() -}))] +}), HashVersion::V2)] +#[should_panic(expected = "DeclareTransactionCasmHashMissMatch")] +#[case::poseidon_declare_tx(DeclareTransaction::V3(DeclareTransactionV3 { + sender_address: ApiExecutableDeclareTransaction::bootstrap_address(), + class_hash: class_hash!(7_u64), + compiled_class_hash: CompiledClassHash(8_u64.into()), + ..Default::default() +}), HashVersion::V1)] #[should_panic(expected = "UninitializedStorageAddress")] #[case::wrong_tx_version(DeclareTransaction::V2(DeclareTransactionV2 { sender_address: ApiExecutableDeclareTransaction::bootstrap_address(), ..Default::default() -}))] +}), HashVersion::V2)] #[should_panic(expected = "InvalidNonce")] #[case::wrong_nonce(DeclareTransaction::V3(DeclareTransactionV3 { sender_address: ApiExecutableDeclareTransaction::bootstrap_address(), nonce: Nonce(felt!(1_u64)), ..Default::default() -}))] +}), HashVersion::V2)] #[should_panic(expected = "UninitializedStorageAddress")] #[case::wrong_sender_address(DeclareTransaction::V3(DeclareTransactionV3 { sender_address: ContractAddress(PatriciaKey::from(1_u128)), ..Default::default() -}))] +}), HashVersion::V2)] #[should_panic(expected = "InsufficientResourceBounds")] #[case::non_trivial_resource_bounds(DeclareTransaction::V3(DeclareTransactionV3 { sender_address: ApiExecutableDeclareTransaction::bootstrap_address(), @@ -919,8 +926,12 @@ fn test_fail_declare(block_context: BlockContext, max_fee: Fee) { l1_data_gas: ResourceBounds::default(), }), ..Default::default() -}))] -fn test_bootstrap_declare(block_context: BlockContext, #[case] declare_tx: DeclareTransaction) { +}), HashVersion::V2)] +fn test_bootstrap_declare( + block_context: BlockContext, + #[case] declare_tx: DeclareTransaction, + #[case] hash_version: HashVersion, +) { let class_info = calculate_class_info_for_testing( FeatureContract::Empty(CairoVersion::Cairo1(RunnableCairo1::Casm)).get_class(), ); @@ -930,10 +941,12 @@ fn test_bootstrap_declare(block_context: BlockContext, #[case] declare_tx: Decla tx_hash: TransactionHash::default(), class_info, }; - // If this is a V3 declare, override the compiled_class_hash field with v2 hash. - if let DeclareTransaction::V3(ref mut tx_v3) = executable_declare.tx { - if let ContractClass::V1((casm, _)) = contract_class { - tx_v3.compiled_class_hash = casm.hash(&HashVersion::V2); + + // Update compiled_class_hash in V3 declare txs to match the contract class with the given hash + // version. + if let DeclareTransaction::V3(tx) = &mut executable_declare.tx { + if let ContractClass::V1((casm, _)) = &contract_class { + tx.compiled_class_hash = casm.hash(&hash_version); } } let compiled_class_hash = executable_declare.tx.compiled_class_hash(); diff --git a/crates/blockifier/src/transaction/transactions.rs b/crates/blockifier/src/transaction/transactions.rs index 609d4023406..805686aa769 100644 --- a/crates/blockifier/src/transaction/transactions.rs +++ b/crates/blockifier/src/transaction/transactions.rs @@ -11,7 +11,12 @@ use starknet_api::executable_transaction::{ L1HandlerTransaction, }; use starknet_api::transaction::fields::{AccountDeploymentData, Calldata}; -use starknet_api::transaction::{constants, DeclareTransactionV2, DeclareTransactionV3}; +use starknet_api::transaction::{ + constants, + DeclareTransactionV2, + DeclareTransactionV3, + TransactionVersion, +}; use crate::context::{BlockContext, GasCounter, TransactionContext}; use crate::execution::call_info::CallInfo; @@ -175,7 +180,14 @@ impl Executable for DeclareTransaction { | starknet_api::transaction::DeclareTransaction::V3(DeclareTransactionV3 { compiled_class_hash, .. - }) => try_declare(self, state, class_hash, Some(*compiled_class_hash))?, + }) => { + if context.tx_context.block_context.versioned_constants.block_casm_hash_v1_declares + && self.version() >= TransactionVersion::THREE + { + self.check_compile_class_hash_v2_declaration()? + } + try_declare(self, state, class_hash, Some(*compiled_class_hash))? + } } Ok(None) } diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index 65c6d765183..52c8997d2ab 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -1789,7 +1789,7 @@ fn test_declare_redeposit_amount_regression() { #[apply(cairo_version)] #[case(TransactionVersion::ZERO, CairoVersion::Cairo0, None)] #[case(TransactionVersion::ONE, CairoVersion::Cairo0, None)] -#[case(TransactionVersion::TWO, CairoVersion::Cairo1(RunnableCairo1::Casm), None)] +#[case(TransactionVersion::TWO, CairoVersion::Cairo1(RunnableCairo1::Casm), Some(HashVersion::V2))] #[case( TransactionVersion::THREE, CairoVersion::Cairo1(RunnableCairo1::Casm), diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index 8b147f273c9..c2467475db9 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -339,6 +339,11 @@ impl PyBlockExecutor { self.versioned_constants.enable_casm_hash_migration = enable_casm_hash_migration; } + #[pyo3(signature = (block_casm_hash_v1_declares))] + pub fn set_block_casm_hash_v1_declares_in_vc(&mut self, block_casm_hash_v1_declares: bool) { + self.versioned_constants.block_casm_hash_v1_declares = block_casm_hash_v1_declares; + } + #[pyo3(signature = (concurrency_config, contract_class_manager_config, os_config, path, max_state_diff_size, stack_size, min_sierra_version, enable_casm_hash_migration))] #[staticmethod] #[allow(clippy::too_many_arguments)] From 1b99c240b0208cc679e3df364c8af78c2e731023 Mon Sep 17 00:00:00 2001 From: Yonatan-Starkware Date: Sun, 26 Oct 2025 15:38:28 +0200 Subject: [PATCH 146/313] blockifier: log_transaction execution duration (#9686) --- .../src/concurrency/worker_logic.rs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/blockifier/src/concurrency/worker_logic.rs b/crates/blockifier/src/concurrency/worker_logic.rs index 1f1b3fe2665..1f9a9801ac9 100644 --- a/crates/blockifier/src/concurrency/worker_logic.rs +++ b/crates/blockifier/src/concurrency/worker_logic.rs @@ -41,6 +41,7 @@ pub struct ExecutionTaskOutput { pub reads: StateMaps, pub state_diff: StateMaps, pub contract_classes: ContractClassMapping, + pub run_time: Duration, pub result: TransactionExecutionResult, } @@ -239,8 +240,10 @@ impl WorkerExecutor { TransactionalState::create_transactional(&mut tx_versioned_state); let concurrency_mode = true; let tx = self.tx_at(tx_index); + let execution_start = Instant::now(); let execution_result = tx.execute_raw(&mut transactional_state, &self.block_context, concurrency_mode); + let run_time = execution_start.elapsed(); // Update the versioned state and store the transaction execution output. let execution_output_inner = match execution_result { @@ -253,6 +256,7 @@ impl WorkerExecutor { reads: tx_reads_writes.initial_reads, state_diff, contract_classes, + run_time, result: execution_result, } } @@ -261,6 +265,7 @@ impl WorkerExecutor { // Failed transaction - ignore the writes. state_diff: StateMaps::default(), contract_classes: HashMap::default(), + run_time, result: execution_result, }, }; @@ -321,9 +326,10 @@ impl WorkerExecutor { let mut execution_output_refmut = self.lock_execution_output(tx_index); let execution_output = execution_output_refmut.value_mut(); let mut tx_state_changes_keys = execution_output.state_diff.keys(); + let tx = self.tx_at(tx_index); + let execution_status: &str; if let Ok(tx_execution_info) = execution_output.result.as_mut() { - let tx = self.tx_at(tx_index); let tx_context = self.block_context.to_tx_context(tx.as_ref()); // Add the deleted sequencer balance key to the storage keys. let concurrency_mode = true; @@ -364,10 +370,22 @@ impl WorkerExecutor { &mut tx_versioned_state, tx.as_ref(), ); + + execution_status = + if tx_execution_info.is_reverted() { "reverted" } else { "successfully executed" }; + // Optimization: changing the sequencer balance storage cell does not trigger // (re-)validation of the next transactions. + } else { + execution_status = "rejected"; } + let tx_hash = Transaction::tx_hash(tx.as_ref()); + let run_time = execution_output.run_time.as_millis(); + log::debug!( + "Transaction with tx_hash: {tx_hash} {execution_status}. Execution time: {run_time}ms." + ); + Ok(CommitResult::Success) } From 1d7b4c8b9870be9f565fe00c19fe3f9ff28da83a Mon Sep 17 00:00:00 2001 From: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> Date: Sun, 26 Oct 2025 16:10:37 +0200 Subject: [PATCH 147/313] apollo_consensus: Remove some panics from the `StreamHandler` (#9678) --- crates/apollo_consensus/src/stream_handler.rs | 89 +++++++++++-------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/crates/apollo_consensus/src/stream_handler.rs b/crates/apollo_consensus/src/stream_handler.rs index 37f2489dacc..e4f7aa53dc2 100644 --- a/crates/apollo_consensus/src/stream_handler.rs +++ b/crates/apollo_consensus/src/stream_handler.rs @@ -143,7 +143,7 @@ where // (stream_id, Receiver) pair. Each receiver gets messages that should // be sent out to the network. outbound_channel_receiver: mpsc::Receiver<(StreamId, mpsc::Receiver)>, - // A map where the abovementioned Receivers are stored. + // A map where the above mentioned Receivers are stored. outbound_stream_receivers: StreamMap>, // A network sender that allows sending StreamMessages to peers. outbound_sender: OutboundSenderT, @@ -198,6 +198,8 @@ where /// /// Expects to live forever, returning an Error if the client or network close their sender. pub async fn handle_next_msg(&mut self) -> Result<(), StreamHandlerError> { + // TODO(Dafna): Consider spawning a separate task for each of the three channels to ensure + // they don’t block one another. tokio::select!( // New outbound stream. outbound_stream = self.outbound_channel_receiver.next() => { @@ -245,49 +247,52 @@ where } } + // Returns true if the message was successfully sent. + // If the message was not sent, it is either due to disconnected channel or full channel. fn inbound_send( &mut self, data: &mut StreamData, message: StreamMessage, ) -> bool { - // TODO(guyn): reconsider the "expect" here. let sender = &mut data.sender; if let StreamMessageBody::Content(content) = message.message { - match sender.try_send(content) { - Ok(_) => {} - Err(e) => { + if let Err(e) = sender.try_send(content) { + warn!( + "Error sending inbound message: {e:?}; dropping the message. StreamId: {}, \ + MessageId: {}", + message.stream_id, message.message_id + ); + return false; + } + + // Send the receiver only once the first message has been sent. + if message.message_id == 0 { + // If this is the first message, send the receiver to the application. + // Note: By this point, messages must be unique. Duplicate message IDs should + // have been discarded earlier. + let receiver = data.receiver.take().expect("Receiver should exist"); + + // Send the receiver to the application. + let send_result = self.inbound_channel_sender.try_send(receiver); + if let Err(e) = send_result { if e.is_disconnected() { + panic!("Receiver was unexpectedly dropped"); + } else { + // The channel is full. warn!( - "Sender is disconnected, dropping the message. StreamId: {}, \ - MessageId: {}", + "Failed to send receiver to application: {e:?}; dropping the message. \ + StreamId: {}, MessageId: {}", message.stream_id, message.message_id ); - return true; - } else if e.is_full() { - // TODO(guyn): replace panic with buffering of the message. - panic!( - "Sender is full, dropping the message. StreamId: {}, MessageId: {}", - message.stream_id, message.message_id - ); - } else { - // TODO(guyn): replace panic with more graceful error handling - panic!("Unexpected error: {e:?}"); + return false; } } - }; - // Send the receiver only once the first message has been sent. - if message.message_id == 0 { - // TODO(guyn): consider the expect in both cases. - // If this is the first message, send the receiver to the application. - let receiver = data.receiver.take().expect("Receiver should exist"); - // Send the receiver to the application. - self.inbound_channel_sender.try_send(receiver).expect("Send should succeed"); } data.next_message_id += 1; - return false; + return true; } - // A Fin message is not sent. This is a no-op, can safely return true. - true + // A Fin message is not sent. This is a no-op, can safely return false. + false } // Send the message to the network. @@ -300,7 +305,6 @@ where stream_id: stream_id.clone(), message_id: *self.outbound_stream_number.get(&stream_id).unwrap_or(&0), }; - // TODO(guyn): reconsider the "expect" here. self.outbound_sender.broadcast_message(message).await.expect("Send should succeed"); self.outbound_stream_number.insert( stream_id.clone(), @@ -414,13 +418,19 @@ where // This means we can just send the message without buffering it. match message_id.cmp(&data.next_message_id) { Ordering::Equal => { - let mut receiver_dropped = self.inbound_send(&mut data, message); - if !receiver_dropped { - receiver_dropped = self.process_buffer(&mut data); + let mut message_sent = self.inbound_send(&mut data, message); + if message_sent { + message_sent = self.process_buffer(&mut data); } - if data.message_buffer.is_empty() && data.fin_message_id.is_some() - || receiver_dropped + // We are done with this stream if: + // 1. All messages were sent successfully. + // 2. A send error occurred (receiver dropped or channel full). + // + // A full channel is currently treated as an error, as we expect + // capacity to always be sufficient. + // TODO(Dafna): Consider implementing buffering as a fallback for the 'full' case. + if data.message_buffer.is_empty() && data.fin_message_id.is_some() || !message_sent { data.sender.close_channel(); CONSENSUS_INBOUND_STREAM_FINISHED.increment(1); @@ -469,14 +479,15 @@ where } // Tries to drain as many messages as possible from the buffer (in order), - // DOES NOT guarantee that the buffer will be empty after calling this function. - // Returns true if the receiver for this stream is dropped. + // Returns true if all attempted messages were sent successfully, and false otherwise. + // DOES NOT guarantee that the buffer will be empty after calling this function - only that the + // messages which were tried to send were handled successfully. fn process_buffer(&mut self, data: &mut StreamData) -> bool { while let Some(message) = data.message_buffer.remove(&data.next_message_id) { - if self.inbound_send(data, message) { - return true; + if !self.inbound_send(data, message) { + return false; } } - false + true } } From 670369f346305ba4b20bedd1a782187435e1ee15 Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Sun, 26 Oct 2025 16:21:59 +0200 Subject: [PATCH 148/313] apollo_l1_provider: improve documentation (#9268) --- .../apollo_l1_endpoint_monitor/src/monitor.rs | 1 + crates/apollo_l1_provider/src/bootstrapper.rs | 4 +-- crates/apollo_l1_provider/src/l1_provider.rs | 28 ++++++++++++++++--- crates/apollo_l1_provider/src/l1_scraper.rs | 21 ++++++++++++-- crates/apollo_l1_provider/src/lib.rs | 5 ++++ crates/apollo_node/src/components.rs | 4 +++ .../src/ethereum_base_layer_contract.rs | 1 + 7 files changed, 54 insertions(+), 10 deletions(-) diff --git a/crates/apollo_l1_endpoint_monitor/src/monitor.rs b/crates/apollo_l1_endpoint_monitor/src/monitor.rs index 191ed16c182..59a69886421 100644 --- a/crates/apollo_l1_endpoint_monitor/src/monitor.rs +++ b/crates/apollo_l1_endpoint_monitor/src/monitor.rs @@ -44,6 +44,7 @@ impl L1EndpointMonitor { for offset in 1..n_urls { let idx = (current_l1_endpoint_index + offset) % n_urls; if self.is_operational(idx).await { + // TODO(guyn): print the end point without the API key (use to_safe_string) warn!( "L1 endpoint {} down; switched to {}", to_safe_string(self.get_node_url(current_l1_endpoint_index)), diff --git a/crates/apollo_l1_provider/src/bootstrapper.rs b/crates/apollo_l1_provider/src/bootstrapper.rs index bf1757a43c0..0649c29f82c 100644 --- a/crates/apollo_l1_provider/src/bootstrapper.rs +++ b/crates/apollo_l1_provider/src/bootstrapper.rs @@ -14,7 +14,7 @@ use tracing::{debug, error, info}; pub type LazyCatchUpHeight = Arc>; -/// Cache's commits to be applied later. This flow is only relevant while the node is starting up. +/// Caches commits to be applied later. This flow is only relevant while the node is starting up. #[derive(Clone)] pub struct Bootstrapper { /// The catch-up height for the bootstrapper is the batcher height (unless overridden @@ -153,8 +153,6 @@ impl std::fmt::Debug for Bootstrapper { } } -// TODO(noamsp): fix catch up height to use batcher height and not the latest block number in -// storage. async fn l2_sync_task( l1_provider_client: SharedL1ProviderClient, batcher_client: SharedBatcherClient, diff --git a/crates/apollo_l1_provider/src/l1_provider.rs b/crates/apollo_l1_provider/src/l1_provider.rs index 3f565ddb911..23e71251850 100644 --- a/crates/apollo_l1_provider/src/l1_provider.rs +++ b/crates/apollo_l1_provider/src/l1_provider.rs @@ -77,6 +77,7 @@ impl L1Provider { } /// Retrieves up to `n_txs` transactions that have yet to be proposed or accepted on L2. + /// Used to make new proposals. Must be in Propose state. #[instrument(skip(self), err)] pub fn get_txs( &mut self, @@ -115,7 +116,8 @@ impl L1Provider { } /// Returns true if and only if the given transaction is both not included in an L2 block, and - /// unconsumed on L1. + /// unconsumed on L1. Validator should call validate on each tx during validation. + /// Must be in Validate state. #[instrument(skip(self), err)] pub fn validate( &mut self, @@ -144,6 +146,8 @@ impl L1Provider { // TODO(Gilad): when deciding on consensus, if possible, have commit_block also tell the node if // it's about to [optimistically-]propose or validate the next block. + /// Upon successfully committing a block, commit all committed/rejected transactions, unstage + /// any remaining transactions, and put provider back in Pending state. #[instrument(skip(self), err)] pub fn commit_block( &mut self, @@ -156,6 +160,9 @@ impl L1Provider { return Err(L1ProviderError::Uninitialized); } + // TODO(guyn): this message is misleading, it checks start_height, not current_height. + // TODO(guyn): maybe we should indeed ignore all blocks below current_height? + // See other todo in bootstrap(). if self.is_historical_height(height) { debug!( "Skipping commit block for historical height: {}, current height is higher: {}", @@ -164,6 +171,8 @@ impl L1Provider { return Ok(()); } + // Reroute this block to bootstrapper, either adding it to the backlog, or applying it and + // ending the bootstrap. if self.state.is_bootstrapping() { // Once bootstrap completes it will transition to Pending state by itself. return self.bootstrap(committed_txs, height); @@ -179,12 +188,14 @@ impl L1Provider { Ok(()) } + /// Accept events from the scraper. #[instrument(skip_all, err)] pub fn add_events(&mut self, events: Vec) -> L1ProviderResult<()> { if self.state.uninitialized() { return Err(L1ProviderError::Uninitialized); } + // TODO(guyn): can we remove this "every sec" since the polling interval is rather long? info_every_n_sec!(1, "Adding {} l1 events", events.len()); trace!("Adding events: {events:?}"); @@ -285,6 +296,7 @@ impl L1Provider { } } + /// Commit the given transactions, and increment the current height. fn apply_commit_block( &mut self, consumed_txs: IndexSet, @@ -298,7 +310,11 @@ impl L1Provider { self.current_height = self.current_height.unchecked_next(); } - /// Try to apply commit_block backlog, and if all caught up, drop bootstrapping state. + /// Any commit_block call gets rerouted to this function when in bootstrap state. + /// - If block number is higher than current height, block is backlogged. + /// - If provider gets a block consistent with current_height, apply it and then the rest of the + /// backlog, then transition to Pending state. + /// - Blocks lower than current height are checked for consistency with existing transactions. fn bootstrap( &mut self, committed_txs: IndexSet, @@ -313,6 +329,9 @@ impl L1Provider { match new_height.cmp(¤t_height) { // This is likely a bug in the batcher/sync, it should never be _behind_ the provider. Less => { + // TODO(guyn): check if this is reliable: old blocks can have txs that were + // committed then consumed and deleted. We should probably decide to always log and + // ignore old blocks or always return an error. let diff_from_already_committed: Vec<_> = committed_txs .iter() .copied() @@ -340,6 +359,7 @@ impl L1Provider { })? } } + // TODO(guyn): check what about rejected txs here and in the backlog? Equal => self.apply_commit_block(committed_txs, Default::default()), // We're still syncing, backlog it, it'll get applied later. Greater => { @@ -382,8 +402,8 @@ impl L1Provider { backlog.iter().map(|commit_block| commit_block.height).collect::>() ); - for commit_block in backlog { - self.apply_commit_block(commit_block.committed_txs, Default::default()); + for committed_block in backlog { + self.apply_commit_block(committed_block.committed_txs, Default::default()); } info!( diff --git a/crates/apollo_l1_provider/src/l1_scraper.rs b/crates/apollo_l1_provider/src/l1_scraper.rs index 262c73defaa..7e85658183c 100644 --- a/crates/apollo_l1_provider/src/l1_scraper.rs +++ b/crates/apollo_l1_provider/src/l1_scraper.rs @@ -30,6 +30,7 @@ pub mod l1_scraper_tests; type L1ScraperResult = Result>; +// TODO(guyn): make this a config parameter // Sensible lower bound. const L1_BLOCK_TIME: u64 = 10; @@ -60,6 +61,9 @@ impl L1Scraper { }) } + /// Send an initialize message to the L1 provider, including events scraped on the first + /// iteration. The provider will return an error if it was already initialized (e.g., if the + /// scraper was restarted). #[instrument(skip(self), err)] async fn initialize(&mut self) -> L1ScraperResult<(), B> { let (latest_l1_block, events) = self.fetch_events().await?; @@ -76,16 +80,18 @@ impl L1Scraper { Ok(()) } + /// Scrape recent events and send them to the L1 provider. pub async fn send_events_to_l1_provider(&mut self) -> L1ScraperResult<(), B> { self.assert_no_l1_reorgs().await?; let (latest_l1_block, events) = self.fetch_events().await?; + // TODO(guyn): remove these _every_n_sec because the polling interval is longer. trace!("scraped up to {latest_l1_block:?}"); info_every_n_sec!(1, "scraped up to {latest_l1_block:?}"); // Sending even if there are no events, to keep the flow as simple/debuggable as possible. - // Perf hit is minimal, since the scraper is on the same machine as the provider (no net). - // If this gets spammy, short-circuit on events.empty(). + // Perf hit is minimal, since the scraper is on the same machine as the provider (no + // network). If this gets spammy, short-circuit on events.empty(). let add_events_result = self.l1_provider_client.add_events(events).await; handle_client_error(add_events_result)?; @@ -94,6 +100,7 @@ impl L1Scraper { Ok(()) } + /// Query the L1 base layer for all events since last_l1_block_processed. async fn fetch_events(&self) -> L1ScraperResult<(L1BlockReference, Vec), B> { let scrape_timestamp = self.clock.unix_now(); @@ -146,7 +153,7 @@ impl L1Scraper { }) .collect::, _>>()?; - // Used for debug. Collect the L2 tx hashes. + // Used for debug. Collect the L2 hashes for events that are L1 handler transactions. let l2_hashes = events.iter().filter_map(|event| match event { Event::L1HandlerTransaction { l1_handler_tx, .. } => Some(l1_handler_tx.tx_hash), _ => None, @@ -199,6 +206,7 @@ impl L1Scraper { } loop { + // TODO(guyn): move sleep to the end of the loop. sleep(self.config.polling_interval_seconds).await; match self.send_events_to_l1_provider().await { @@ -214,6 +222,9 @@ impl L1Scraper { } } + /// Fetch last_l1_block_processed again, check it still exists and that its hash is the same. + /// If a reorg occurred up to this block, return an error (existing data in the provider is + /// stale). async fn assert_no_l1_reorgs(&self) -> L1ScraperResult<(), B> { let last_processed_l1_block_number = self.last_l1_block_processed.number; let last_processed_l1_block_hash = self.last_l1_block_processed.hash; @@ -250,6 +261,8 @@ impl L1Scraper { } } +/// Use config.startup_rewind_time_seconds to estimate an L1 block number +/// that is far enough back to start scraping from. pub async fn fetch_start_block( base_layer: &B, config: &L1ScraperConfig, @@ -338,6 +351,8 @@ impl PartialEq for L1ScraperError { // TODO(guyn): get rid of finality_too_high, use a better error. impl L1ScraperError { + /// Pass any base layer errors. In the rare case that the finality is bigger than the latest L1 + /// block number, return FinalityTooHigh. pub async fn finality_too_high(finality: u64, base_layer: &B) -> L1ScraperError { let latest_l1_block_number_no_finality = base_layer.latest_l1_block_number(0).await; diff --git a/crates/apollo_l1_provider/src/lib.rs b/crates/apollo_l1_provider/src/lib.rs index 9a08e6d7403..8a5141b7bbc 100644 --- a/crates/apollo_l1_provider/src/lib.rs +++ b/crates/apollo_l1_provider/src/lib.rs @@ -26,9 +26,14 @@ use crate::transaction_manager::TransactionManagerConfig; /// Current state of the provider, where pending means: idle, between proposal/validation cycles. #[derive(Clone, Debug, Eq, PartialEq)] pub enum ProviderState { + /// Provider is not read for proposing or validating. Use start_block to transition to Propose + /// or Validate. Pending, + /// Provider is ready for proposing. Use commit_block to finish and return to Pending. Propose, + /// Provider is catching up using sync. Only happens on startup. Bootstrap(Bootstrapper), + /// Provider is ready for validating. Use validate to validate a transaction. Validate, } diff --git a/crates/apollo_node/src/components.rs b/crates/apollo_node/src/components.rs index c1810e269d1..236441c8519 100644 --- a/crates/apollo_node/src/components.rs +++ b/crates/apollo_node/src/components.rs @@ -381,6 +381,8 @@ pub async fn create_node_components( clients.get_l1_endpoint_monitor_shared_client().unwrap(); let base_layer = EthereumBaseLayerContract::new(base_layer_config.clone(), initial_node_url.clone()); + // TODO(guyn): figure out how to start in case we can't reach L1 to get the start block. + // TODO(guyn): maybe put the fetch_start_block logic inside the scraper loop? let l1_start_block = fetch_start_block(&base_layer, l1_scraper_config) .await .unwrap_or_else(|err| panic!("Error while initializing the L1 scraper: {err}")); @@ -475,6 +477,8 @@ pub async fn create_node_components( base_layer_config.clone(), initial_node_url.clone(), ); + // Which L2 block is already proved at the L1 height the scraper was initialized on. + // It is safe to start syncing the provider from this height. let scraper_synced_startup_height = base_layer .get_proved_block_at(l1_scraper_start_l1_height) .await diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index a19f5e95383..f89fd5a1655 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -111,6 +111,7 @@ impl EthereumBaseLayerContract { impl BaseLayerContract for EthereumBaseLayerContract { type Error = EthereumBaseLayerError; + /// Get the Starknet block that is proved on the base layer at a specific L1 block number. #[instrument(skip(self), err)] async fn get_proved_block_at( &self, From 2530fe108a6669e97082dd2717be961cb7baad15 Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Sun, 26 Oct 2025 16:58:30 +0200 Subject: [PATCH 149/313] apollo_l1_provider: reorder functions in L1 provider (#9321) --- crates/apollo_l1_provider/src/l1_provider.rs | 252 ++++++++++--------- 1 file changed, 131 insertions(+), 121 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_provider.rs b/crates/apollo_l1_provider/src/l1_provider.rs index 23e71251850..b1f5ef608e0 100644 --- a/crates/apollo_l1_provider/src/l1_provider.rs +++ b/crates/apollo_l1_provider/src/l1_provider.rs @@ -45,6 +45,96 @@ pub struct L1Provider { } impl L1Provider { + // Functions Called by the scraper. + + // Start the provider, get first-scrape events, start L2 sync. + pub async fn initialize(&mut self, events: Vec) -> L1ProviderResult<()> { + info!("Initializing l1 provider"); + let Some(bootstrapper) = self.state.get_bootstrapper() else { + // FIXME: This should be return FatalError or similar, which should trigger a planned + // restart from the infra, since this CAN happen if the scraper recovered from a crash. + // Right now this is effectively a KILL message when called in steady state. + panic!("Called initialize while not in bootstrap state. Restart service."); + }; + bootstrapper.start_l2_sync(self.current_height).await; + self.add_events(events)?; + + Ok(()) + } + + /// Accept new events from the scraper. + #[instrument(skip_all, err)] + pub fn add_events(&mut self, events: Vec) -> L1ProviderResult<()> { + if self.state.uninitialized() { + return Err(L1ProviderError::Uninitialized); + } + + // TODO(guyn): can we remove this "every sec" since the polling interval is rather long? + info_every_n_sec!(1, "Adding {} l1 events", events.len()); + trace!("Adding events: {events:?}"); + + for event in events { + match event { + Event::L1HandlerTransaction { + l1_handler_tx, + block_timestamp, + scrape_timestamp, + } => { + let tx_hash = l1_handler_tx.tx_hash; + let successfully_inserted = + self.tx_manager.add_tx(l1_handler_tx, block_timestamp, scrape_timestamp); + if !successfully_inserted { + debug!( + "Unexpected L1 Handler transaction with hash: {tx_hash}, already \ + known or committed." + ); + } + } + Event::TransactionCancellationStarted { + tx_hash, + cancellation_request_timestamp, + } => { + if !self.tx_manager.exists(tx_hash) { + warn!( + "Dropping cancellation request for old L1 handler transaction \ + {tx_hash}: not in the provider and will never be scraped at this \ + point." + ); + continue; + } + + self.tx_manager + .request_cancellation(tx_hash, cancellation_request_timestamp) + .inspect(|previous_request_timestamp| { + // Re-requesting a cancellation is meaningful for the L1 timelock, but + // for the l2 timelock we only consider the first cancellation + // relevant. + info!( + "Dropping duplicated cancellation request for {tx_hash} at \ + {cancellation_request_timestamp}, previous request block \ + timestamp still stands: {previous_request_timestamp}" + ); + }); + } + Event::TransactionConsumed { tx_hash, timestamp: consumed_at } => { + if let Err(previously_consumed_at) = + self.tx_manager.consume_tx(tx_hash, consumed_at, self.clock.unix_now()) + { + panic!( + "Double consumption of {tx_hash} at {consumed_at}, previously \ + consumed at {previously_consumed_at}." + ); + } + } + _ => return Err(L1ProviderError::unsupported_l1_event(event)), + } + } + Ok(()) + } + + // Functions Called by the batcher. + + /// Start a new block as either proposer or validator. #[instrument(skip(self), err)] pub fn start_block( &mut self, @@ -62,20 +152,6 @@ impl L1Provider { Ok(()) } - pub async fn initialize(&mut self, events: Vec) -> L1ProviderResult<()> { - info!("Initializing l1 provider"); - let Some(bootstrapper) = self.state.get_bootstrapper() else { - // FIXME: This should be return FatalError or similar, which should trigger a planned - // restart from the infra, since this CAN happen if the scraper recovered from a crash. - // Right now this is effectively a KILL message when called in steady state. - panic!("Called initialize while not in bootstrap state. Restart service."); - }; - bootstrapper.start_l2_sync(self.current_height).await; - self.add_events(events)?; - - Ok(()) - } - /// Retrieves up to `n_txs` transactions that have yet to be proposed or accepted on L2. /// Used to make new proposals. Must be in Propose state. #[instrument(skip(self), err)] @@ -188,113 +264,7 @@ impl L1Provider { Ok(()) } - /// Accept events from the scraper. - #[instrument(skip_all, err)] - pub fn add_events(&mut self, events: Vec) -> L1ProviderResult<()> { - if self.state.uninitialized() { - return Err(L1ProviderError::Uninitialized); - } - - // TODO(guyn): can we remove this "every sec" since the polling interval is rather long? - info_every_n_sec!(1, "Adding {} l1 events", events.len()); - trace!("Adding events: {events:?}"); - - for event in events { - match event { - Event::L1HandlerTransaction { - l1_handler_tx, - block_timestamp, - scrape_timestamp, - } => { - let tx_hash = l1_handler_tx.tx_hash; - let successfully_inserted = - self.tx_manager.add_tx(l1_handler_tx, block_timestamp, scrape_timestamp); - if !successfully_inserted { - debug!( - "Unexpected L1 Handler transaction with hash: {tx_hash}, already \ - known or committed." - ); - } - } - Event::TransactionCancellationStarted { - tx_hash, - cancellation_request_timestamp, - } => { - if !self.tx_manager.exists(tx_hash) { - warn!( - "Dropping cancellation request for old L1 handler transaction \ - {tx_hash}: not in the provider and will never be scraped at this \ - point." - ); - continue; - } - - self.tx_manager - .request_cancellation(tx_hash, cancellation_request_timestamp) - .inspect(|previous_request_timestamp| { - // Re-requesting a cancellation is meaningful for the L1 timelock, but - // for the l2 timelock we only consider the first cancellation - // relevant. - info!( - "Dropping duplicated cancellation request for {tx_hash} at \ - {cancellation_request_timestamp}, previous request block \ - timestamp still stands: {previous_request_timestamp}" - ); - }); - } - Event::TransactionConsumed { tx_hash, timestamp: consumed_at } => { - if let Err(previously_consumed_at) = - self.tx_manager.consume_tx(tx_hash, consumed_at, self.clock.unix_now()) - { - panic!( - "Double consumption of {tx_hash} at {consumed_at}, previously \ - consumed at {previously_consumed_at}." - ); - } - } - _ => return Err(L1ProviderError::unsupported_l1_event(event)), - } - } - Ok(()) - } - - pub fn get_l1_provider_snapshot(&self) -> L1ProviderResult { - let txs_snapshot = self.tx_manager.snapshot(); - Ok(L1ProviderSnapshot { - uncommitted_transactions: txs_snapshot.uncommitted, - uncommitted_staged_transactions: txs_snapshot.uncommitted_staged, - rejected_transactions: txs_snapshot.rejected, - rejected_staged_transactions: txs_snapshot.rejected_staged, - committed_transactions: txs_snapshot.committed, - l1_provider_state: self.state.as_str().to_string(), - current_height: self.current_height, - }) - } - - fn check_height_with_error(&mut self, height: BlockNumber) -> L1ProviderResult<()> { - if height != self.current_height { - return Err(L1ProviderError::UnexpectedHeight { - expected_height: self.current_height, - got: height, - }); - } - Ok(()) - } - - fn check_height_with_panic(&mut self, height: BlockNumber) { - if height > self.current_height { - // TODO(shahak): Add a way to move to bootstrap mode from any point and move to - // bootstrap here instead of panicking. - panic!( - "Batcher surpassed l1 provider. Panicking in order to restart the provider and \ - bootstrap again. l1 provider height: {}, batcher height: {}", - self.current_height, height - ); - } - if height < self.current_height { - panic!("Unexpected height: expected >= {}, got {}", self.current_height, height); - } - } + // Functions called internally. /// Commit the given transactions, and increment the current height. fn apply_commit_block( @@ -419,10 +389,50 @@ impl L1Provider { Ok(()) } + fn check_height_with_panic(&mut self, height: BlockNumber) { + if height > self.current_height { + // TODO(shahak): Add a way to move to bootstrap mode from any point and move to + // bootstrap here instead of panicking. + panic!( + "Batcher surpassed l1 provider. Panicking in order to restart the provider and \ + bootstrap again. l1 provider height: {}, batcher height: {}", + self.current_height, height + ); + } + if height < self.current_height { + panic!("Unexpected height: expected >= {}, got {}", self.current_height, height); + } + } + + fn check_height_with_error(&mut self, height: BlockNumber) -> L1ProviderResult<()> { + if height != self.current_height { + return Err(L1ProviderError::UnexpectedHeight { + expected_height: self.current_height, + got: height, + }); + } + Ok(()) + } + /// Checks if the given height appears before the timeline of which the provider is aware of. fn is_historical_height(&self, height: BlockNumber) -> bool { height < self.start_height } + + // Functions used for debugging or testing. + + pub fn get_l1_provider_snapshot(&self) -> L1ProviderResult { + let txs_snapshot = self.tx_manager.snapshot(); + Ok(L1ProviderSnapshot { + uncommitted_transactions: txs_snapshot.uncommitted, + uncommitted_staged_transactions: txs_snapshot.uncommitted_staged, + rejected_transactions: txs_snapshot.rejected, + rejected_staged_transactions: txs_snapshot.rejected_staged, + committed_transactions: txs_snapshot.committed, + l1_provider_state: self.state.as_str().to_string(), + current_height: self.current_height, + }) + } } impl PartialEq for L1Provider { From bab65c6fc63b2af847a5f6fe23cbb47625f95519 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 26 Oct 2025 17:36:26 +0200 Subject: [PATCH 150/313] apollo_mempool_p2p: reduce log level of very chatty message. (#9769) --- crates/apollo_mempool_p2p/src/propagator/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/apollo_mempool_p2p/src/propagator/mod.rs b/crates/apollo_mempool_p2p/src/propagator/mod.rs index 2b409c7cdf5..01e5429956e 100644 --- a/crates/apollo_mempool_p2p/src/propagator/mod.rs +++ b/crates/apollo_mempool_p2p/src/propagator/mod.rs @@ -16,7 +16,7 @@ use apollo_network_types::network_types::BroadcastedMessageMetadata; use apollo_protobuf::mempool::RpcTransactionBatch; use async_trait::async_trait; use starknet_api::rpc_transaction::{InternalRpcTransaction, RpcTransaction}; -use tracing::{debug, warn}; +use tracing::{debug, trace, warn}; use crate::metrics::MEMPOOL_P2P_BROADCASTED_BATCH_SIZE; @@ -63,7 +63,7 @@ impl ComponentRequestHandler { - debug!("Received a request to broadcast queued transactions, broadcasting."); + trace!("Received a request to broadcast queued transactions, broadcasting."); MempoolP2pPropagatorResponse::BroadcastQueuedTransactions( self.broadcast_queued_transactions().await, ) From 2a68c7ba334e903f2d203f3f1fb4c1aca41ae44b Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 07:21:04 +0200 Subject: [PATCH 151/313] apollo_protobuf: align consensus.proto formatting (#9733) --- .../proto/p2p/proto/consensus/consensus.proto | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/crates/apollo_protobuf/src/proto/p2p/proto/consensus/consensus.proto b/crates/apollo_protobuf/src/proto/p2p/proto/consensus/consensus.proto index 467ba4948cb..076ec548935 100644 --- a/crates/apollo_protobuf/src/proto/p2p/proto/consensus/consensus.proto +++ b/crates/apollo_protobuf/src/proto/p2p/proto/consensus/consensus.proto @@ -8,10 +8,10 @@ option go_package = "github.com/starknet-io/starknet-p2pspecs/p2p/proto/consensu // in a new block. message ConsensusTransaction { oneof txn { - DeclareV3WithClass declare_v3 = 1; + DeclareV3WithClass declare_v3 = 1; DeployAccountV3 deploy_account_v3 = 2; - InvokeV3 invoke_v3 = 3; - L1HandlerV0 l1_handler = 4; + InvokeV3 invoke_v3 = 3; + L1HandlerV0 l1_handler = 4; } Hash transaction_hash = 5; } @@ -25,39 +25,39 @@ message Vote { // We use a type field to distinguish between prevotes and precommits instead of different // messages, to make sure the data, and therefore the signatures, are unambiguous between // Prevote and Precommit. - VoteType vote_type = 2; - uint64 height = 3; - uint32 round = 4; + VoteType vote_type = 2; + uint64 height = 3; + uint32 round = 4; // This is optional since a vote can be NIL. optional Hash proposal_commitment = 5; - Address voter = 6; + Address voter = 6; } message StreamMessage { oneof message { bytes content = 1; - Fin fin = 2; + Fin fin = 2; } - bytes stream_id = 3; + bytes stream_id = 3; uint64 message_id = 4; } message ProposalInit { - uint64 height = 1; - uint32 round = 2; + uint64 height = 1; + uint32 round = 2; optional uint32 valid_round = 3; - Address proposer = 4; + Address proposer = 4; } message BlockInfo { - uint64 height = 1; - uint64 timestamp = 2; - Address builder = 3; + uint64 height = 1; + uint64 timestamp = 2; + Address builder = 3; L1DataAvailabilityMode l1_da_mode = 4; - Uint128 l2_gas_price_fri = 5; - Uint128 l1_gas_price_wei = 6; - Uint128 l1_data_gas_price_wei = 7; - Uint128 eth_to_fri_rate = 8; + Uint128 l2_gas_price_fri = 5; + Uint128 l1_gas_price_wei = 6; + Uint128 l1_data_gas_price_wei = 7; + Uint128 eth_to_fri_rate = 8; } message TransactionBatch { @@ -81,10 +81,10 @@ message ProposalFin { // 5. executed_transaction_count is sent once message ProposalPart { oneof message { - ProposalInit init = 1; - ProposalFin fin = 2; - BlockInfo block_info = 3; - TransactionBatch transactions = 4; + ProposalInit init = 1; + ProposalFin fin = 2; + BlockInfo block_info = 3; + TransactionBatch transactions = 4; uint64 executed_transaction_count = 5; } } From 4bed8e2eb5c6bf3f486752eeffd429e8080df06d Mon Sep 17 00:00:00 2001 From: dafnamatsry <92669167+dafnamatsry@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:01:16 +0200 Subject: [PATCH 152/313] apollo_consensus: Use `match` instead of `if let`, and return early on `Fin`. (#9682) * apollo_consensus: Remove some panics from the `StreamHandler` * apollo_consensus: Use `match` instead of `if let`, and return early on `Fin`. --- crates/apollo_consensus/src/stream_handler.rs | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/crates/apollo_consensus/src/stream_handler.rs b/crates/apollo_consensus/src/stream_handler.rs index e4f7aa53dc2..9df303943e6 100644 --- a/crates/apollo_consensus/src/stream_handler.rs +++ b/crates/apollo_consensus/src/stream_handler.rs @@ -254,45 +254,47 @@ where data: &mut StreamData, message: StreamMessage, ) -> bool { + let content = match message.message { + StreamMessageBody::Content(content) => content, + // A Fin message is not sent. This is a no-op, can safely return false. + StreamMessageBody::Fin => return false, + }; + let sender = &mut data.sender; - if let StreamMessageBody::Content(content) = message.message { - if let Err(e) = sender.try_send(content) { - warn!( - "Error sending inbound message: {e:?}; dropping the message. StreamId: {}, \ - MessageId: {}", - message.stream_id, message.message_id - ); - return false; - } + if let Err(e) = sender.try_send(content) { + warn!( + "Error sending inbound message: {e:?}; dropping the message. StreamId: {}, \ + MessageId: {}", + message.stream_id, message.message_id + ); + return false; + } - // Send the receiver only once the first message has been sent. - if message.message_id == 0 { - // If this is the first message, send the receiver to the application. - // Note: By this point, messages must be unique. Duplicate message IDs should - // have been discarded earlier. - let receiver = data.receiver.take().expect("Receiver should exist"); - - // Send the receiver to the application. - let send_result = self.inbound_channel_sender.try_send(receiver); - if let Err(e) = send_result { - if e.is_disconnected() { - panic!("Receiver was unexpectedly dropped"); - } else { - // The channel is full. - warn!( - "Failed to send receiver to application: {e:?}; dropping the message. \ - StreamId: {}, MessageId: {}", - message.stream_id, message.message_id - ); - return false; - } + // Send the receiver only once the first message has been sent. + if message.message_id == 0 { + // If this is the first message, send the receiver to the application. + // Note: By this point, messages must be unique. Duplicate message IDs should + // have been discarded earlier. + let receiver = data.receiver.take().expect("Receiver should exist"); + + // Send the receiver to the application. + let send_result = self.inbound_channel_sender.try_send(receiver); + if let Err(e) = send_result { + if e.is_disconnected() { + panic!("Receiver was unexpectedly dropped"); + } else { + // The channel is full. + warn!( + "Failed to send receiver to application: {e:?}; dropping the message. \ + StreamId: {}, MessageId: {}", + message.stream_id, message.message_id + ); + return false; } } - data.next_message_id += 1; - return true; } - // A Fin message is not sent. This is a no-op, can safely return false. - false + data.next_message_id += 1; + true } // Send the message to the network. From debf37a0c8cb88a43331d978d5d2bdb8a12c18a2 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:14:43 +0200 Subject: [PATCH 153/313] ci: upload benchmark input files (#9627) --- crates/bench_tools/src/gcs.rs | 37 ++++++++++++++++++++++++++++++++++ crates/bench_tools/src/lib.rs | 1 + crates/bench_tools/src/main.rs | 29 +++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 crates/bench_tools/src/gcs.rs diff --git a/crates/bench_tools/src/gcs.rs b/crates/bench_tools/src/gcs.rs new file mode 100644 index 00000000000..551f73269d2 --- /dev/null +++ b/crates/bench_tools/src/gcs.rs @@ -0,0 +1,37 @@ +use std::path::Path; +use std::process::Command; + +/// Default GCS bucket for benchmarks. +pub const BENCHMARKS_BUCKET: &str = "apollo_benchmarks"; + +/// Uploads all files from a local directory to Google Cloud Storage. +/// +/// Uses gcloud CLI to upload files. Before running, authenticate with: +/// `gcloud auth application-default login` +/// +/// Files are uploaded to: `gs://{BENCHMARKS_BUCKET}/{benchmark_name}/input/` +pub fn upload_inputs(benchmark_name: &str, input_dir: &Path) { + println!( + "Uploading inputs from {} to gs://{}/{}/input/", + input_dir.display(), + BENCHMARKS_BUCKET, + benchmark_name + ); + + let source = format!("{}/*", input_dir.display()); + let dest = format!("gs://{}/{}/input/", BENCHMARKS_BUCKET, benchmark_name); + + // Use gcloud storage cp command to upload files. + let output = Command::new("gcloud") + .args(["storage", "cp", "-r", &source, &dest]) + .output() + .expect("Failed to upload inputs to GCS"); + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + panic!("Failed to upload inputs to GCS: {}", stderr); + } + + println!("{}", String::from_utf8_lossy(&output.stdout).trim()); + println!("Input files uploaded successfully!"); +} diff --git a/crates/bench_tools/src/lib.rs b/crates/bench_tools/src/lib.rs index 8f65f43e194..4d4fec63928 100644 --- a/crates/bench_tools/src/lib.rs +++ b/crates/bench_tools/src/lib.rs @@ -1,3 +1,4 @@ #[cfg(test)] pub(crate) mod benches; +pub mod gcs; pub mod types; diff --git a/crates/bench_tools/src/main.rs b/crates/bench_tools/src/main.rs index bb53dd44263..6fa04d8a143 100644 --- a/crates/bench_tools/src/main.rs +++ b/crates/bench_tools/src/main.rs @@ -1,4 +1,11 @@ -use bench_tools::types::benchmark_config::{find_benchmarks_by_package, BENCHMARKS}; +use std::path::PathBuf; + +use bench_tools::gcs; +use bench_tools::types::benchmark_config::{ + find_benchmark_by_name, + find_benchmarks_by_package, + BENCHMARKS, +}; use clap::{Parser, Subcommand}; #[derive(Parser)] @@ -25,6 +32,15 @@ enum Commands { #[arg(short, long)] package: Option, }, + /// Upload benchmark input files to GCS. + UploadInputs { + /// Benchmark name. + #[arg(long)] + benchmark: String, + /// Local directory containing input files. + #[arg(long)] + input_dir: String, + }, } fn main() { @@ -59,5 +75,16 @@ fn main() { } } }, + Commands::UploadInputs { benchmark, input_dir } => { + // Validate benchmark exists. + if find_benchmark_by_name(&benchmark).is_none() { + panic!("Unknown benchmark: {}", benchmark); + } + + let input_path = PathBuf::from(&input_dir); + gcs::upload_inputs(&benchmark, &input_path); + + println!("Input files uploaded successfully!"); + } } } From 0df27278930865ce12b7bb82d44c7ad2b8aaa90d Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:10:38 +0200 Subject: [PATCH 154/313] apollo_dashboard: update http server high transaction failure ratio to 0.5 (#9779) --- .../apollo_dashboard/resources/dev_grafana_alerts_mainnet.json | 2 +- .../apollo_dashboard/resources/dev_grafana_alerts_testnet.json | 2 +- .../src/alert_scenarios/transaction_failures.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json index 8f5426a0b23..ff9efcc069f 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json @@ -793,7 +793,7 @@ { "evaluator": { "params": [ - 0.3 + 0.5 ], "type": "gt" }, diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json index ff60cf18448..5a1e9e88f0b 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json @@ -793,7 +793,7 @@ { "evaluator": { "params": [ - 0.3 + 0.5 ], "type": "gt" }, diff --git a/crates/apollo_dashboard/src/alert_scenarios/transaction_failures.rs b/crates/apollo_dashboard/src/alert_scenarios/transaction_failures.rs index 7c90dbca404..1cba3d44dfb 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/transaction_failures.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/transaction_failures.rs @@ -57,7 +57,7 @@ pub(crate) fn get_http_server_high_transaction_failure_ratio() -> Alert { ), vec![AlertCondition { comparison_op: AlertComparisonOp::GreaterThan, - comparison_value: 0.3, + comparison_value: 0.5, logical_op: AlertLogicalOp::And, }], PENDING_DURATION_DEFAULT, From 1251ad1c466dad6139def17e36559851512f809e Mon Sep 17 00:00:00 2001 From: Yonatan Iluz Date: Mon, 27 Oct 2025 12:54:04 +0200 Subject: [PATCH 155/313] chore: resolve conflicts --- Cargo.lock | 479 ++++++++--------------------------------------------- 1 file changed, 65 insertions(+), 414 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c06800b1d05..726d0efa146 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,9 +93,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17c19591d57add4f0c47922877a48aae1f47074e3433436545f8948353b3bbb" +checksum = "ae62e633fa48b4190af5e841eb05179841bb8b713945103291e2c0867037c0d1" dependencies = [ "alloy-consensus", "alloy-contract", @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "alloy-chains" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf01dd83a1ca5e4807d0ca0223c9615e211ce5db0a9fd1443c2778cacf89b546" +checksum = "0bbb778f50ecb0cebfb5c05580948501927508da7bd628833a8c4bd8545e23e2" dependencies = [ "alloy-primitives", "num_enum", @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a0dd3ed764953a6b20458b2b7abbfdc93d20d14b38babe1a70fe631a443a9f1" +checksum = "b9b151e38e42f1586a01369ec52a6934702731d07e8509a7307331b09f6c46dc" dependencies = [ "alloy-eips", "alloy-primitives", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9556182afa73cddffa91e64a5aa9508d5e8c912b3a15f26998d2388a824d2c7b" +checksum = "6e2d5e8668ef6215efdb7dcca6f22277b4e483a5650e05f5de22b2350971f4b8" dependencies = [ "alloy-consensus", "alloy-eips", @@ -169,9 +169,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19d7092c96defc3d132ee0d8969ca1b79ef512b5eda5c66e3065266b253adf2" +checksum = "630288cf4f3a34a8c6bc75c03dce1dbd47833138f65f37d53a1661eafc96b83f" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -185,14 +185,8 @@ dependencies = [ "alloy-transport", "futures", "futures-util", -<<<<<<< HEAD - "thiserror 2.0.16", -||||||| 7a53ee9e8 - "thiserror 2.0.12", -======= "serde_json", - "thiserror 2.0.12", ->>>>>>> origin/main-v0.14.0 + "thiserror 2.0.16", ] [[package]] @@ -262,9 +256,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fa99b538ca7006b0c03cfed24ec6d82beda67aac857ef4714be24231d15e6" +checksum = "e5434834adaf64fa20a6fb90877bc1d33214c41b055cc49f82189c98614368cc" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -279,14 +273,14 @@ dependencies = [ "serde", "serde_with", "sha2", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "alloy-genesis" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a272533715aefc900f89d51db00c96e6fd4f517ea081a12fea482a352c8c815c" +checksum = "919a8471cfbed7bcd8cf1197a57dda583ce0e10c6385f6ff4e8b41304b223392" dependencies = [ "alloy-eips", "alloy-primitives", @@ -323,13 +317,13 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91676d242c0ced99c0dd6d0096d7337babe9457cc43407d26aa6367fcf90553" +checksum = "d7c69f6c9c68a1287c9d5ff903d0010726934de0dac10989be37b75a29190d55" dependencies = [ "alloy-primitives", "alloy-sol-types", - "http 1.2.0", + "http 1.3.1", "serde", "serde_json", "thiserror 2.0.16", @@ -338,9 +332,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f82150116b30ba92f588b87f08fa97a46a1bd5ffc0d0597efdf0843d36bfda" +checksum = "8eaf2ae05219e73e0979cb2cf55612aafbab191d130f203079805eaf881cca58" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -364,9 +358,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223612259a080160ce839a4e5df0125ca403a1d5e7206cc911cea54af5d769aa" +checksum = "e58f4f345cef483eab7374f2b6056973c7419ffe8ad35e994b7a7f5d8e0c7ba4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -377,9 +371,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3652a65bacfba0a169755090d4ecd7d3c63fa534b21d09b8e604dc2609760da6" +checksum = "61321a0dbc084c2c9f2b07aa34f10db7ac80065c01721e567e5426d882c73de6" dependencies = [ "alloy-genesis", "alloy-hardforks", @@ -407,19 +401,9 @@ dependencies = [ "cfg-if", "const-hex", "derive_more 2.0.1", -<<<<<<< HEAD - "foldhash", - "hashbrown 0.15.5", - "indexmap 2.11.0", -||||||| 7a53ee9e8 - "foldhash", - "hashbrown 0.15.2", - "indexmap 2.9.0", -======= "foldhash 0.2.0", "hashbrown 0.16.0", - "indexmap 2.9.0", ->>>>>>> origin/main-v0.14.0 + "indexmap 2.11.0", "itoa", "k256", "keccak-asm", @@ -435,9 +419,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7283b81b6f136100b152e699171bc7ed8184a58802accbc91a7df4ebb944445" +checksum = "de2597751539b1cc8fe4204e5325f9a9ed83fcacfb212018dfcfa7877e76de21" dependencies = [ "alloy-chains", "alloy-consensus", @@ -498,9 +482,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1154b12d470bef59951c62676e106f4ce5de73b987d86b9faa935acebb138ded" +checksum = "edf8eb8be597cfa8c312934d2566ec4516f066d69164f9212d7a148979fdcfd8" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -521,9 +505,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ab76bf97648a1c6ad8fb00f0d594618942b5a9e008afbfb5c8a8fca800d574" +checksum = "339af7336571dd39ae3a15bde08ae6a647e62f75350bd415832640268af92c06" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -533,9 +517,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456cfc2c1677260edbd7ce3eddb7de419cb46de0e9826c43401f42b0286a779a" +checksum = "83d98fb386a462e143f5efa64350860af39950c49e7c0cbdba419c16793116ef" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -545,9 +529,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cc57ee0c1ac9fb14854195fc249494da7416591dc4a4d981ddfd5dd93b9bce" +checksum = "fbde0801a32d21c5f111f037bee7e22874836fba7add34ed4a6919932dd7cf23" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -556,9 +540,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7d47bca1a2a1541e4404aa38b7e262bb4dffd9ac23b4f178729a4ddc5a5caa" +checksum = "361cd87ead4ba7659bda8127902eda92d17fa7ceb18aba1676f7be10f7222487" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -571,21 +555,15 @@ dependencies = [ "itertools 0.14.0", "serde", "serde_json", -<<<<<<< HEAD - "thiserror 2.0.16", -||||||| 7a53ee9e8 - "thiserror 2.0.12", -======= "serde_with", - "thiserror 2.0.12", ->>>>>>> origin/main-v0.14.0 + "thiserror 2.0.16", ] [[package]] name = "alloy-serde" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8468f1a7f9ee3bae73c24eead0239abea720dbf7779384b9c7e20d51bfb6b0" +checksum = "64600fc6c312b7e0ba76f73a381059af044f4f21f43e07f51f1fa76c868fe302" dependencies = [ "alloy-primitives", "serde", @@ -594,9 +572,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33387c90b0a5021f45a5a77c2ce6c49b8f6980e66a318181468fb24cea771670" +checksum = "5772858492b26f780468ae693405f895d6a27dea6e3eab2c36b6217de47c2647" dependencies = [ "alloy-primitives", "async-trait", @@ -609,9 +587,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55d9e795c85e36dcea08786d2e7ae9b73cb554b6bea6ac4c212def24e1b4d03" +checksum = "f4195b803d0a992d8dbaab2ca1986fc86533d4bc80967c0cce7668b26ad99ef9" dependencies = [ "alloy-consensus", "alloy-network", @@ -698,9 +676,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702002659778d89a94cd4ff2044f6b505460df6c162e2f47d1857573845b0ace" +checksum = "025a940182bddaeb594c26fe3728525ae262d0806fe6a4befdf5d7bc13d54bce" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -722,9 +700,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6bdc0830e5e8f08a4c70a4c791d400a86679c694a3b4b986caf26fad680438" +checksum = "e3b5064d1e1e1aabc918b5954e7fb8154c39e77ec6903a581b973198b26628fa" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -737,21 +715,9 @@ dependencies = [ [[package]] name = "alloy-trie" -<<<<<<< HEAD -version = "0.7.9" -||||||| 7a53ee9e8 -version = "0.7.8" -======= version = "0.9.1" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" -<<<<<<< HEAD -checksum = "d95a94854e420f07e962f7807485856cde359ab99ab6413883e15235ad996e8b" -||||||| 7a53ee9e8 -checksum = "6917c79e837aa7b77b7a6dae9f89cbe15313ac161c4d3cfaf8909ef21f3d22d8" -======= checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" ->>>>>>> origin/main-v0.14.0 dependencies = [ "alloy-primitives", "alloy-rlp", @@ -765,15 +731,15 @@ dependencies = [ [[package]] name = "alloy-tx-macros" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bf39928a5e70c9755d6811a2928131b53ba785ad37c8bf85c90175b5d43b818" +checksum = "f8e52276fdb553d3c11563afad2898f4085165e4093604afe3d78b69afbf408f" dependencies = [ "alloy-primitives", "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.106", ] [[package]] @@ -1843,19 +1809,11 @@ dependencies = [ "apollo_time", "assert_matches", "async-trait", -<<<<<<< HEAD - "derive_more 0.99.20", - "indexmap 2.11.0", -||||||| 7a53ee9e8 - "derive_more 0.99.18", - "indexmap 2.9.0", -======= "blockifier", "blockifier_test_utils", "criterion", - "derive_more 0.99.18", - "indexmap 2.9.0", ->>>>>>> origin/main-v0.14.0 + "derive_more 0.99.20", + "indexmap 2.11.0", "itertools 0.12.1", "mempool_test_utils", "metrics 0.24.2", @@ -3114,13 +3072,7 @@ dependencies = [ "futures-lite", "parking", "polling", -<<<<<<< HEAD "rustix 1.0.8", -||||||| 7a53ee9e8 - "rustix", -======= - "rustix 0.38.43", ->>>>>>> origin/main-v0.14.0 "slab", "windows-sys 0.60.2", ] @@ -3434,13 +3386,7 @@ version = "0.66.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "cexpr", "clang-sys", "lazy_static", @@ -3460,13 +3406,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "cexpr", "clang-sys", "itertools 0.12.1", @@ -3489,13 +3429,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "cexpr", "clang-sys", "itertools 0.13.0", @@ -3513,13 +3447,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "cexpr", "clang-sys", "itertools 0.13.0", @@ -3587,21 +3515,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitflags" -<<<<<<< HEAD version = "2.9.3" -||||||| 7a53ee9e8 -version = "2.6.0" -======= -version = "2.9.4" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" -<<<<<<< HEAD checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" -||||||| 7a53ee9e8 -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -======= -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" ->>>>>>> origin/main-v0.14.0 [[package]] name = "bitvec" @@ -3750,21 +3666,9 @@ dependencies = [ [[package]] name = "blst" -<<<<<<< HEAD version = "0.3.15" -||||||| 7a53ee9e8 -version = "0.3.13" -======= -version = "0.3.16" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" -<<<<<<< HEAD checksum = "4fd49896f12ac9b6dcd7a5998466b9b58263a695a3dd1ecc1aaca2e12a90b080" -||||||| 7a53ee9e8 -checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" -======= -checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" ->>>>>>> origin/main-v0.14.0 dependencies = [ "cc", "glob", @@ -5273,7 +5177,7 @@ dependencies = [ "quote", "serde", "strsim 0.11.1", - "syn 2.0.100", + "syn 2.0.106", ] [[package]] @@ -5306,7 +5210,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.100", + "syn 2.0.106", ] [[package]] @@ -6955,7 +6859,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.1.4", + "foldhash 0.1.5", "serde", ] @@ -7265,7 +7169,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.2", "tower-service", - "webpki-roots 0.26.7", + "webpki-roots 1.0.2", ] [[package]] @@ -7720,13 +7624,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "cfg-if", "libc", ] @@ -8243,13 +8141,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f0bee397dc9a7003e7bd34fffc1dc2d4c4fdc96530a0c439a5f98c9402bc7bf" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "byteorder", "derive_more 0.99.20", "indexmap 1.9.3", @@ -8686,13 +8578,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "libc", "redox_syscall 0.5.17", ] @@ -8713,22 +8599,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] -<<<<<<< HEAD name = "linux-raw-sys" version = "0.9.4" -||||||| 7a53ee9e8 -name = "litemap" -version = "0.7.4" -======= -name = "linux-raw-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - -[[package]] -name = "litemap" -version = "0.7.4" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" @@ -9397,13 +9269,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "cfg-if", "cfg_aliases", "libc", @@ -9669,9 +9535,9 @@ dependencies = [ [[package]] name = "nybbles" -version = "0.4.6" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" +checksum = "bfa11e84403164a9f12982ab728f3c67c6fd4ab5b5f0254ffc217bdbd3b28ab0" dependencies = [ "alloy-rlp", "cfg-if", @@ -9758,13 +9624,7 @@ version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "cfg-if", "foreign-types", "libc", @@ -10328,18 +10188,8 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", -<<<<<<< HEAD "rustix 1.0.8", "windows-sys 0.60.2", -||||||| 7a53ee9e8 - "rustix", - "tracing", - "windows-sys 0.59.0", -======= - "rustix 0.38.43", - "tracing", - "windows-sys 0.59.0", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -10550,23 +10400,11 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "hex", "lazy_static", "procfs-core", -<<<<<<< HEAD "rustix 0.38.44", -||||||| 7a53ee9e8 - "rustix", -======= - "rustix 0.38.43", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -10575,13 +10413,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "hex", ] @@ -10622,35 +10454,13 @@ dependencies = [ [[package]] name = "proptest" -<<<<<<< HEAD version = "1.7.0" -||||||| 7a53ee9e8 -version = "1.5.0" -======= -version = "1.8.0" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" -<<<<<<< HEAD checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" -||||||| 7a53ee9e8 -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" -======= -checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" ->>>>>>> origin/main-v0.14.0 dependencies = [ -<<<<<<< HEAD "bit-set 0.8.0", "bit-vec 0.8.0", "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bit-set 0.5.3", - "bit-vec 0.6.3", - "bitflags 2.6.0", -======= - "bit-set 0.8.0", - "bit-vec 0.8.0", - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "lazy_static", "num-traits", "rand 0.9.2", @@ -11045,14 +10855,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ -<<<<<<< HEAD "getrandom 0.3.3", -||||||| 7a53ee9e8 - "getrandom 0.3.1", -======= - "getrandom 0.3.1", "serde", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -11151,13 +10955,7 @@ version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -11223,13 +11021,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -11400,23 +11192,16 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", -<<<<<<< HEAD - "rustls-pki-types", -||||||| 7a53ee9e8 - "rustls-pemfile 2.2.0", -======= "quinn", - "rustls 0.23.20", - "rustls-pemfile 2.2.0", + "rustls 0.23.31", "rustls-pki-types", ->>>>>>> origin/main-v0.14.0 "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.2", "tokio-util", "tower 0.5.2", "tower-http", @@ -11426,13 +11211,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", -<<<<<<< HEAD -||||||| 7a53ee9e8 - "windows-registry", -======= - "webpki-roots 0.26.7", - "windows-registry", ->>>>>>> origin/main-v0.14.0 + "webpki-roots 1.0.2", ] [[package]] @@ -11653,26 +11432,13 @@ dependencies = [ [[package]] name = "ruint" -<<<<<<< HEAD version = "1.16.0" -||||||| 7a53ee9e8 -version = "1.12.4" -======= -version = "1.17.0" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" -<<<<<<< HEAD checksum = "9ecb38f82477f20c5c3d62ef52d7c4e536e38ea9b73fb570a20c5cae0e14bcf6" -||||||| 7a53ee9e8 -checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" -======= -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" ->>>>>>> origin/main-v0.14.0 dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", - "ark-ff 0.5.0", "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", @@ -11686,7 +11452,7 @@ dependencies = [ "rand 0.9.2", "rlp", "ruint-macro", - "serde_core", + "serde", "valuable", "zeroize", ] @@ -11793,35 +11559,10 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "errno", "libc", -<<<<<<< HEAD "linux-raw-sys 0.4.15", -||||||| 7a53ee9e8 - "linux-raw-sys", -======= - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" -dependencies = [ - "bitflags 2.9.4", - "errno", - "libc", - "linux-raw-sys 0.11.0", ->>>>>>> origin/main-v0.14.0 "windows-sys 0.59.0", ] @@ -12142,13 +11883,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -12161,16 +11896,8 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", "core-foundation 0.10.1", -||||||| 7a53ee9e8 - "bitflags 2.6.0", - "core-foundation 0.10.0", -======= - "bitflags 2.9.4", - "core-foundation 0.10.0", ->>>>>>> origin/main-v0.14.0 "core-foundation-sys", "libc", "security-framework-sys", @@ -12227,19 +11954,8 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -<<<<<<< HEAD -version = "1.0.219" -||||||| 7a53ee9e8 -version = "1.0.217" -======= version = "1.0.228" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" -<<<<<<< HEAD -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -||||||| 7a53ee9e8 -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" -======= checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", @@ -12251,28 +11967,15 @@ name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" ->>>>>>> origin/main-v0.14.0 dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -<<<<<<< HEAD -version = "1.0.219" -||||||| 7a53ee9e8 -version = "1.0.217" -======= version = "1.0.228" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" -<<<<<<< HEAD -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -||||||| 7a53ee9e8 -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" -======= checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" ->>>>>>> origin/main-v0.14.0 dependencies = [ "proc-macro2", "quote", @@ -12758,7 +12461,7 @@ dependencies = [ "base64 0.21.7", "crypto-bigint", "flate2", - "foldhash 0.1.4", + "foldhash 0.1.5", "hex", "indexmap 2.11.0", "num-traits", @@ -13225,13 +12928,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -13305,41 +13002,15 @@ dependencies = [ [[package]] name = "tempfile" -<<<<<<< HEAD version = "3.21.0" -||||||| 7a53ee9e8 -version = "3.15.0" -======= -version = "3.23.0" ->>>>>>> origin/main-v0.14.0 source = "registry+https://github.com/rust-lang/crates.io-index" -<<<<<<< HEAD checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" -||||||| 7a53ee9e8 -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" -======= -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" ->>>>>>> origin/main-v0.14.0 dependencies = [ "fastrand", -<<<<<<< HEAD "getrandom 0.3.3", -||||||| 7a53ee9e8 - "getrandom 0.2.15", -======= - "getrandom 0.3.1", ->>>>>>> origin/main-v0.14.0 "once_cell", -<<<<<<< HEAD "rustix 1.0.8", "windows-sys 0.60.2", -||||||| 7a53ee9e8 - "rustix", - "windows-sys 0.59.0", -======= - "rustix 1.1.2", - "windows-sys 0.59.0", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -14590,13 +14261,7 @@ dependencies = [ "either", "home", "once_cell", -<<<<<<< HEAD "rustix 0.38.44", -||||||| 7a53ee9e8 - "rustix", -======= - "rustix 0.38.43", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -15063,13 +14728,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ -<<<<<<< HEAD "bitflags 2.9.3", -||||||| 7a53ee9e8 - "bitflags 2.6.0", -======= - "bitflags 2.9.4", ->>>>>>> origin/main-v0.14.0 ] [[package]] @@ -15149,15 +14808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" dependencies = [ "libc", -<<<<<<< HEAD "rustix 1.0.8", -||||||| 7a53ee9e8 - "linux-raw-sys", - "rustix", -======= - "linux-raw-sys 0.4.15", - "rustix 0.38.43", ->>>>>>> origin/main-v0.14.0 ] [[package]] From 5bd0705caa1307bdcba5e379882a1ecd189c0256 Mon Sep 17 00:00:00 2001 From: Yonatan Iluz Date: Mon, 27 Oct 2025 12:58:03 +0200 Subject: [PATCH 156/313] chore: resolve conflicts --- crates/apollo_deployments/src/deployments.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/crates/apollo_deployments/src/deployments.rs b/crates/apollo_deployments/src/deployments.rs index 8b49e695e40..110c34ad9bc 100644 --- a/crates/apollo_deployments/src/deployments.rs +++ b/crates/apollo_deployments/src/deployments.rs @@ -1,13 +1,3 @@ pub mod consolidated; pub mod distributed; pub mod hybrid; -<<<<<<< HEAD -||||||| 7a53ee9e8 - -pub(crate) const IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES: usize = 0; -pub(crate) const RETRIES_FOR_L1_SERVICES: usize = 2; -======= - -pub(crate) const IDLE_CONNECTIONS_FOR_AUTOSCALED_SERVICES: usize = 0; -pub(crate) const RETRIES_FOR_L1_SERVICES: usize = 0; ->>>>>>> origin/main-v0.14.0 From c1285fd26de522d205a1ad2f37e2c08e9380deac Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:09:15 +0200 Subject: [PATCH 157/313] apollo_dashboard: cleanup fn names and unused fns (#9778) --- crates/apollo_dashboard/src/dashboard.rs | 29 +++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/crates/apollo_dashboard/src/dashboard.rs b/crates/apollo_dashboard/src/dashboard.rs index 51a502e3ebd..8e841c1dce7 100644 --- a/crates/apollo_dashboard/src/dashboard.rs +++ b/crates/apollo_dashboard/src/dashboard.rs @@ -238,9 +238,10 @@ impl Panel { self.with_thresholds(ThresholdMode::Percentage, steps) } + // TODO(Tsabary): consider deleting. // TODO(Tsabary): unify relevant parts with `from_hist` to avoid code duplication. - // TODO(alonl): remove the _ prefix once the function is used. - pub(crate) fn _from_request_type_labeled_hist( + #[allow(dead_code)] + pub(crate) fn from_request_type_labeled_hist( metric: &LabeledMetricHistogram, panel_type: PanelType, request_label: &str, @@ -368,7 +369,7 @@ pub fn traffic_light_thresholds(yellow: f64, red: f64) -> Vec<(&'static str, Opt // There is no equivalent for LabeledPanels because they are less straightforward than // UnlabeledPanels and require an aggregation of metrics more often, for example the panels created -// using `get_multi_metric_panel`. +// using [`get_multi_metric_panel`]. /// A struct that contains all unlabeled panels for a given metrics struct. struct UnlabeledPanels(Vec); @@ -428,7 +429,9 @@ impl From<&RemoteServerMetrics> for UnlabeledPanels { } } -pub(crate) fn _create_request_type_labeled_hist_panels( +// TODO(Tsabary): consider deleting. +#[allow(dead_code)] +pub(crate) fn create_request_type_labeled_hist_panels( metric: &LabeledMetricHistogram, panel_type: PanelType, ) -> Vec { @@ -436,14 +439,14 @@ pub(crate) fn _create_request_type_labeled_hist_panels( .get_flat_label_values() .into_iter() .map(|request_label| { - Panel::_from_request_type_labeled_hist(metric, panel_type, request_label) + Panel::from_request_type_labeled_hist(metric, panel_type, request_label) }) .collect() } // For a given request label and vector of labeled histogram metrics, create a panel with multiple // expressions. -pub(crate) fn get_multi_metric_panel( +fn get_multi_metric_panel( panel_name: &str, panel_description: &str, request_label: &str, @@ -520,7 +523,7 @@ impl Serialize for Row { } // This function assumes that all metrics share the same labels. -fn get_request_type_labeled_panels( +fn get_request_type_panels( labeled_metrics: &Vec<&LabeledMetricHistogram>, panel_class_name: &str, ) -> Vec { @@ -546,32 +549,32 @@ fn get_request_type_labeled_panels( panels } -pub(crate) fn get_labeled_client_panels( +fn get_infra_client_panels( local_client_metrics: &LocalClientMetrics, remote_client_metrics: &RemoteClientMetrics, ) -> Vec { let mut labeled_metrics: Vec<&LabeledMetricHistogram> = local_client_metrics.get_all_labeled_metrics(); labeled_metrics.extend(remote_client_metrics.get_all_labeled_metrics()); - get_request_type_labeled_panels(&labeled_metrics, "client") + get_request_type_panels(&labeled_metrics, "client") } -pub(crate) fn get_labeled_server_panels( +fn get_infra_server_panels( local_server_metrics: &LocalServerMetrics, remote_server_metrics: &RemoteServerMetrics, ) -> Vec { let mut labeled_metrics: Vec<&LabeledMetricHistogram> = local_server_metrics.get_all_labeled_metrics(); labeled_metrics.extend(remote_server_metrics.get_all_labeled_metrics()); - get_request_type_labeled_panels(&labeled_metrics, "server") + get_request_type_panels(&labeled_metrics, "server") } pub(crate) fn get_component_infra_row(row_name: &'static str, metrics: &InfraMetrics) -> Row { - let labeled_client_panels = get_labeled_client_panels( + let labeled_client_panels = get_infra_client_panels( metrics.get_local_client_metrics(), metrics.get_remote_client_metrics(), ); - let labeled_server_panels = get_labeled_server_panels( + let labeled_server_panels = get_infra_server_panels( metrics.get_local_server_metrics(), metrics.get_remote_server_metrics(), ); From 5e72118594ead3867bc12fd531fdd36fc94522a0 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:10:36 +0200 Subject: [PATCH 158/313] apollo_deployments: add testnet nodes 10-13 (#9783) --- .../deployment_inputs/sepolia_testnet.json | 2 +- .../deployment_config_hybrid_10.json | 281 ++++++++++++++++++ .../deployment_config_hybrid_11.json | 281 ++++++++++++++++++ .../deployment_config_hybrid_12.json | 281 ++++++++++++++++++ .../deployment_config_hybrid_13.json | 281 ++++++++++++++++++ .../deployment_config_override.json | 4 +- .../sepolia_testnet/hybrid_10.json | 7 + .../sepolia_testnet/hybrid_11.json | 7 + .../sepolia_testnet/hybrid_12.json | 7 + .../sepolia_testnet/hybrid_13.json | 7 + 10 files changed, 1155 insertions(+), 3 deletions(-) create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_10.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_11.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_12.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_13.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_10.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_11.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_12.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_13.json diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json index 9a869887218..8a8c3a5f5bf 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json @@ -1,5 +1,5 @@ { - "node_and_validator_ids": [[0, "0x1"], [1,"0x64"], [2,"0x65"], [3,"0x66"]], + "node_and_validator_ids": [[0, "0x1"], [1,"0x64"], [2,"0x65"], [3,"0x66"],[10,"0x1"], [11,"0x1"], [12,"0x1"], [13,"0x1"]], "num_validators": 3, "http_server_ingress_alternative_name": "alpha-sepolia.starknet.io", "ingress_domain": "starknet.io", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_10.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_10.json new file mode 100644 index 00000000000..5695f2b0a02 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_10.json @@ -0,0 +1,281 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_10.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-core-service.apollo-sepolia-alpha-10.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service-c2d-56", + "resources": { + "requests": { + "cpu": 50, + "memory": 200 + }, + "limits": { + "cpu": 50, + "memory": 220 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-10" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_10.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "alpha-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_10.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_10.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-10" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_10.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-mempool-service.apollo-sepolia-alpha-10.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-10" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_10.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_11.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_11.json new file mode 100644 index 00000000000..04c45d639f7 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_11.json @@ -0,0 +1,281 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_11.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-core-service.apollo-sepolia-alpha-11.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service-c2d-56", + "resources": { + "requests": { + "cpu": 50, + "memory": 200 + }, + "limits": { + "cpu": 50, + "memory": 220 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-11" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_11.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "alpha-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_11.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_11.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-11" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_11.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-mempool-service.apollo-sepolia-alpha-11.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-11" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_11.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_12.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_12.json new file mode 100644 index 00000000000..40f59e2141b --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_12.json @@ -0,0 +1,281 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_12.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-core-service.apollo-sepolia-alpha-12.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service-c2d-56", + "resources": { + "requests": { + "cpu": 50, + "memory": 200 + }, + "limits": { + "cpu": 50, + "memory": 220 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-12" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_12.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "alpha-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-12" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_12.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-12" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_12.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-12" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_12.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-mempool-service.apollo-sepolia-alpha-12.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-12" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_12.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-12" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_13.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_13.json new file mode 100644 index 00000000000..1d45beff533 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_13.json @@ -0,0 +1,281 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_13.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-core-service.apollo-sepolia-alpha-13.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service-c2d-56", + "resources": { + "requests": { + "cpu": 50, + "memory": 200 + }, + "limits": { + "cpu": 50, + "memory": 220 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-13" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_13.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "alpha-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-13" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_13.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-13" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_13.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-13" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_13.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-mempool-service.apollo-sepolia-alpha-13.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-13" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_13.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-13" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json index 8d7ad7dd994..f247510a584 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json @@ -2,12 +2,12 @@ "base_layer_config.starknet_contract_address": "0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057", "chain_id": "SN_SEPOLIA", "consensus_manager_config.context_config.num_validators": 3, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-alpha-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-alpha-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-alpha-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-alpha-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-alpha-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-alpha-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-sepolia-alpha-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-alpha-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-alpha-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-sepolia-alpha-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-alpha-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-alpha-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-alpha-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-alpha-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-sepolia-alpha-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-alpha-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-sepolia-alpha-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_10.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_10.json new file mode 100644 index 00000000000..2f3cb90f689 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_10.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_11.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_11.json new file mode 100644 index 00000000000..f9d593b1bb9 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_11.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_12.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_12.json new file mode 100644 index 00000000000..58ff9545cc8 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_12.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_13.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_13.json new file mode 100644 index 00000000000..6d38c96b0f5 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_13.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, + "validator_id": "0x1" +} From a3385fab7854eac931fb96ebf476ed68ff23fd8a Mon Sep 17 00:00:00 2001 From: victorkstarkware <160594433+victorkstarkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:50:51 +0200 Subject: [PATCH 159/313] apollo_integration_tests: remove executable index API in NodeSetup (#9786) --- .../src/executable_setup.rs | 1 + .../src/integration_test_manager.rs | 38 ++++++++++--------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/crates/apollo_integration_tests/src/executable_setup.rs b/crates/apollo_integration_tests/src/executable_setup.rs index dca6e25770b..293a625fa14 100644 --- a/crates/apollo_integration_tests/src/executable_setup.rs +++ b/crates/apollo_integration_tests/src/executable_setup.rs @@ -29,6 +29,7 @@ impl NodeExecutionId { self.executable_index } + // TODO(victork): remove path dependency on executable index pub fn build_path(&self, base: &Path) -> PathBuf { base.join(format!("node_{}", self.node_index)) .join(format!("executable_{}", self.executable_index)) diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index 6d8fef6853e..ac3087d381f 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -153,15 +153,15 @@ impl NodeSetup { } pub fn batcher_monitoring_client(&self) -> &MonitoringClient { - &self.executables[self.batcher_index].monitoring_client + &self.get_batcher().monitoring_client } pub fn state_sync_monitoring_client(&self) -> &MonitoringClient { - &self.executables[self.state_sync_index].monitoring_client + &self.get_state_sync().monitoring_client } pub fn consensus_manager_monitoring_client(&self) -> &MonitoringClient { - &self.executables[self.consensus_manager_index].monitoring_client + &self.get_consensus_manager().monitoring_client } pub fn get_executables(&self) -> &Vec { @@ -183,22 +183,26 @@ impl NodeSetup { pub fn generate_simulator_ports_json(&self, path: &str) { let json_data = serde_json::json!({ - HTTP_PORT_ARG: self.executables[self.http_server_index].get_config().http_server_config.as_ref().expect("Should have http server config").port, - MONITORING_PORT_ARG: self.executables[self.batcher_index].get_config().monitoring_endpoint_config.as_ref().expect("Should have monitoring endpoint config").port + HTTP_PORT_ARG: self.get_http_server().get_config().http_server_config.as_ref().expect("Should have http server config").port, + MONITORING_PORT_ARG: self.get_batcher().get_config().monitoring_endpoint_config.as_ref().expect("Should have monitoring endpoint config").port }); serialize_to_file(json_data, path); } - pub fn get_batcher_index(&self) -> usize { - self.batcher_index + pub fn get_batcher(&self) -> &ExecutableSetup { + &self.executables[self.batcher_index] } - pub fn get_http_server_index(&self) -> usize { - self.http_server_index + pub fn get_http_server(&self) -> &ExecutableSetup { + &self.executables[self.http_server_index] } - pub fn get_state_sync_index(&self) -> usize { - self.state_sync_index + pub fn get_state_sync(&self) -> &ExecutableSetup { + &self.executables[self.state_sync_index] + } + + pub fn get_consensus_manager(&self) -> &ExecutableSetup { + &self.executables[self.consensus_manager_index] } pub fn run(self) -> RunningNode { @@ -444,7 +448,7 @@ impl IntegrationTestManager { "Waiting for batcher to reach block {expected_block_number} in sequencer {} \ executable {}.", running_node_setup.get_node_index().unwrap(), - running_node_setup.get_batcher_index(), + running_node_setup.batcher_index, )), ); @@ -456,7 +460,7 @@ impl IntegrationTestManager { "Waiting for state sync to reach block {expected_block_number} in sequencer \ {} executable {}.", running_node_setup.get_node_index().unwrap(), - running_node_setup.get_state_sync_index(), + running_node_setup.state_sync_index, )), ); @@ -728,14 +732,12 @@ impl IntegrationTestManager { self.perform_action_on_all_running_nodes(|sequencer_idx, running_node| { let node_setup = &running_node.node_setup; let batcher_monitoring_client = node_setup.batcher_monitoring_client(); - let batcher_index = node_setup.get_batcher_index(); let state_sync_monitoring_client = node_setup.state_sync_monitoring_client(); - let state_sync_index = node_setup.get_state_sync_index(); await_block( batcher_monitoring_client, - batcher_index, + node_setup.batcher_index, state_sync_monitoring_client, - state_sync_index, + node_setup.state_sync_index, expected_block_number, sequencer_idx, ) @@ -761,7 +763,7 @@ impl IntegrationTestManager { self.perform_action_on_all_running_nodes(|sequencer_idx, running_node| async move { let node_setup = &running_node.node_setup; let monitoring_client = node_setup.batcher_monitoring_client(); - let batcher_index = node_setup.get_batcher_index(); + let batcher_index = node_setup.batcher_index; let expected_height = expected_block_number.unchecked_next(); let logger = CustomLogger::new( From e3ef81195aa4b7dac6dbe458fdad6636429688fe Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:52:07 +0200 Subject: [PATCH 160/313] apollo_infra_utils: make serialize_ti_file fns take ref instead of ownership (#9774) --- crates/apollo_config/src/dumping.rs | 2 +- .../src/bin/sequencer_dashboard_generator.rs | 4 ++-- crates/apollo_dashboard/src/dashboard_definitions_test.rs | 4 ++-- crates/apollo_deployments/src/config_override.rs | 8 ++++---- .../apollo_deployments/src/deployment_definitions_test.rs | 2 +- crates/apollo_infra_utils/src/dumping.rs | 8 ++++---- .../src/integration_test_manager.rs | 2 +- .../src/bin/update_apollo_node_config_schema.rs | 2 +- crates/apollo_node_config/src/config_test.rs | 2 +- crates/apollo_node_config/src/config_utils.rs | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/crates/apollo_config/src/dumping.rs b/crates/apollo_config/src/dumping.rs index 96e2960869a..06457369ade 100644 --- a/crates/apollo_config/src/dumping.rs +++ b/crates/apollo_config/src/dumping.rs @@ -173,7 +173,7 @@ pub trait SerializeConfig { ) -> Result<(), ConfigError> { let combined_map = combine_config_map_and_pointers(self.dump(), config_pointers, non_pointer_params)?; - serialize_to_file(combined_map, file_path); + serialize_to_file(&combined_map, file_path); Ok(()) } } diff --git a/crates/apollo_dashboard/src/bin/sequencer_dashboard_generator.rs b/crates/apollo_dashboard/src/bin/sequencer_dashboard_generator.rs index 1169baa2160..f066fef1936 100644 --- a/crates/apollo_dashboard/src/bin/sequencer_dashboard_generator.rs +++ b/crates/apollo_dashboard/src/bin/sequencer_dashboard_generator.rs @@ -6,13 +6,13 @@ use strum::IntoEnumIterator; /// Creates the dashboard and alerts json files. fn main() { - serialize_to_file(get_apollo_dashboard(), DEV_JSON_PATH); + serialize_to_file(&get_apollo_dashboard(), DEV_JSON_PATH); for alert_env_filtering in AlertEnvFiltering::iter() { if alert_env_filtering == AlertEnvFiltering::All { continue; // Skip the 'All' variant, as it used to cover all other options. } serialize_to_file( - get_apollo_alerts(alert_env_filtering), + &get_apollo_alerts(alert_env_filtering), &get_dev_alerts_json_path(alert_env_filtering), ); } diff --git a/crates/apollo_dashboard/src/dashboard_definitions_test.rs b/crates/apollo_dashboard/src/dashboard_definitions_test.rs index 0101bfcefd8..8fec5ed45cd 100644 --- a/crates/apollo_dashboard/src/dashboard_definitions_test.rs +++ b/crates/apollo_dashboard/src/dashboard_definitions_test.rs @@ -11,13 +11,13 @@ const FIX_BINARY_NAME: &str = "sequencer_dashboard_generator"; // file, run: cargo run --bin sequencer_dashboard_generator -q #[test] fn default_dev_grafana_dashboard() { - serialize_to_file_test(get_apollo_dashboard(), DEV_JSON_PATH, FIX_BINARY_NAME); + serialize_to_file_test(&get_apollo_dashboard(), DEV_JSON_PATH, FIX_BINARY_NAME); for alert_env_filtering in AlertEnvFiltering::iter() { if alert_env_filtering == AlertEnvFiltering::All { continue; // Skip the 'All' variant, as it used to cover all other options. } serialize_to_file_test( - get_apollo_alerts(alert_env_filtering), + &get_apollo_alerts(alert_env_filtering), &get_dev_alerts_json_path(alert_env_filtering), FIX_BINARY_NAME, ); diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index bb0a24b40d3..a0f82eed1d9 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -46,12 +46,12 @@ impl ConfigOverride { if create { serialize_to_file( - to_value(&self.deployment_config_override).unwrap(), + &to_value(&self.deployment_config_override).unwrap(), deployment_path.to_str().unwrap(), ); serialize_to_file( - to_value(&self.instance_config_override).unwrap(), + &to_value(&self.instance_config_override).unwrap(), instance_path.to_str().unwrap(), ); } @@ -96,13 +96,13 @@ impl ConfigOverride { self.config_files(deployment_config_override_dir, instance_name, false); serialize_to_file_test( - to_value(config_override_with_paths.deployment_config_override).unwrap(), + &to_value(config_override_with_paths.deployment_config_override).unwrap(), &config_override_with_paths.deployment_path, FIX_BINARY_NAME, ); serialize_to_file_test( - to_value(config_override_with_paths.instance_config_override).unwrap(), + &to_value(config_override_with_paths.instance_config_override).unwrap(), &config_override_with_paths.instance_path, FIX_BINARY_NAME, ); diff --git a/crates/apollo_deployments/src/deployment_definitions_test.rs b/crates/apollo_deployments/src/deployment_definitions_test.rs index 52cec098d8c..6ed64d4576b 100644 --- a/crates/apollo_deployments/src/deployment_definitions_test.rs +++ b/crates/apollo_deployments/src/deployment_definitions_test.rs @@ -51,7 +51,7 @@ fn load_and_process_service_config_files() { let temp_file = NamedTempFile::new().unwrap(); let temp_file_path = temp_file.path().to_str().unwrap(); let secrets_config_override = SecretsConfigOverride::default(); - serialize_to_file(to_value(&secrets_config_override).unwrap(), temp_file_path); + serialize_to_file(&to_value(&secrets_config_override).unwrap(), temp_file_path); for deployment in DEPLOYMENTS.iter().flat_map(|f| f()) { for mut service_config_paths in deployment.get_all_services_config_paths().into_iter() { diff --git a/crates/apollo_infra_utils/src/dumping.rs b/crates/apollo_infra_utils/src/dumping.rs index 517721c886c..8f78d74b7d7 100644 --- a/crates/apollo_infra_utils/src/dumping.rs +++ b/crates/apollo_infra_utils/src/dumping.rs @@ -15,14 +15,14 @@ use crate::path::resolve_project_relative_path; use crate::test_utils::assert_json_eq; #[cfg(any(feature = "testing", test))] -pub fn serialize_to_file_test(data: T, file_path: &str, fix_binary_name: &str) { +pub fn serialize_to_file_test(data: &T, file_path: &str, fix_binary_name: &str) { let file_path = resolve_project_relative_path("").unwrap().join(file_path); let file = File::open(&file_path).unwrap_or_else(|err| { panic!("Failed to open file '{}': {}", file_path.display(), err); }); let loaded_data: Value = from_reader(file).unwrap(); let serialized_data = - to_value(&data).expect("Should have been able to serialize the data to JSON"); + to_value(data).expect("Should have been able to serialize the data to JSON"); let error_message = format!( "{}{}{}\n{}", @@ -36,7 +36,7 @@ pub fn serialize_to_file_test(data: T, file_path: &str, fix_binary assert_json_eq(&loaded_data, &serialized_data, error_message); } -pub fn serialize_to_file(data: T, file_path: &str) { +pub fn serialize_to_file(data: &T, file_path: &str) { // Ensure the parent directory exists if let Some(parent) = PathBuf::from(file_path).parent() { create_dir_all(parent).unwrap_or_else(|err| { @@ -51,7 +51,7 @@ pub fn serialize_to_file(data: T, file_path: &str) { let mut writer = BufWriter::new(file); // Add config as JSON content to writer. - to_writer_pretty(&mut writer, &data) + to_writer_pretty(&mut writer, data) .expect("Should have been able to serialize input data to JSON."); // Add an extra newline after the JSON content. diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index ac3087d381f..56e2db85908 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -186,7 +186,7 @@ impl NodeSetup { HTTP_PORT_ARG: self.get_http_server().get_config().http_server_config.as_ref().expect("Should have http server config").port, MONITORING_PORT_ARG: self.get_batcher().get_config().monitoring_endpoint_config.as_ref().expect("Should have monitoring endpoint config").port }); - serialize_to_file(json_data, path); + serialize_to_file(&json_data, path); } pub fn get_batcher(&self) -> &ExecutableSetup { diff --git a/crates/apollo_node/src/bin/update_apollo_node_config_schema.rs b/crates/apollo_node/src/bin/update_apollo_node_config_schema.rs index 99d134ea16b..3a95ed88b1b 100644 --- a/crates/apollo_node/src/bin/update_apollo_node_config_schema.rs +++ b/crates/apollo_node/src/bin/update_apollo_node_config_schema.rs @@ -15,5 +15,5 @@ fn main() { .dump_to_file(&CONFIG_POINTERS, &CONFIG_NON_POINTERS_WHITELIST, CONFIG_SCHEMA_PATH) .expect("dump to file error"); - serialize_to_file(private_parameters(), CONFIG_SECRETS_SCHEMA_PATH); + serialize_to_file(&private_parameters(), CONFIG_SECRETS_SCHEMA_PATH); } diff --git a/crates/apollo_node_config/src/config_test.rs b/crates/apollo_node_config/src/config_test.rs index c2e04555dfa..18d8b4255b1 100644 --- a/crates/apollo_node_config/src/config_test.rs +++ b/crates/apollo_node_config/src/config_test.rs @@ -99,7 +99,7 @@ fn default_config_file_is_up_to_date() { .unwrap(); serialize_to_file_test(&combined_map, CONFIG_SCHEMA_PATH, FIX_BINARY_NAME); - serialize_to_file_test(private_parameters(), CONFIG_SECRETS_SCHEMA_PATH, FIX_BINARY_NAME); + serialize_to_file_test(&private_parameters(), CONFIG_SECRETS_SCHEMA_PATH, FIX_BINARY_NAME); } #[test] diff --git a/crates/apollo_node_config/src/config_utils.rs b/crates/apollo_node_config/src/config_utils.rs index 4b820a5e744..bb1a69c2d34 100644 --- a/crates/apollo_node_config/src/config_utils.rs +++ b/crates/apollo_node_config/src/config_utils.rs @@ -213,7 +213,7 @@ impl DeploymentBaseAppConfig { pub fn dump_config_file(&self, config_path: &Path) { let value = self.as_value(); serialize_to_file( - value, + &value, config_path.to_str().expect("Should be able to convert path to string"), ); } From 4b26a804a3f75f2f3eb71c8ef236f078a2281ca3 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Mon, 27 Oct 2025 13:56:45 +0200 Subject: [PATCH 161/313] apollo_dashboard: prettify CONSENSUS_DECISIONS_REACHED_AS_PROPOSER panel (#9777) --- .../resources/dev_grafana.json | 21 +++++++++++-------- .../apollo_dashboard/src/panels/consensus.rs | 14 +++++++++++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 7c0c5b1230d..8827911eb67 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -115,15 +115,6 @@ "unit": "s" } }, - { - "title": "consensus_decisions_reached_as_proposer", - "description": "The total number of rounds with decision reached where this node is the proposer", - "type": "timeseries", - "exprs": [ - "consensus_decisions_reached_as_proposer{cluster=~\"$cluster\", namespace=~\"$namespace\"}" - ], - "extra_params": {} - }, { "title": "Consensus Round Above Zero", "description": "Occurances where the consensus round was 1, relative to displayed range", @@ -145,6 +136,18 @@ ], "extra_params": {} }, + { + "title": "Consensus Decisions Reached As Proposer", + "description": "The number of rounds with decision reached where this node is the proposer (10m window)", + "type": "timeseries", + "exprs": [ + "increase(consensus_decisions_reached_as_proposer{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])" + ], + "extra_params": { + "log_query": "\"Building proposal\" OR \"BATCHER_FIN_PROPOSER\"", + "log_comment": "-- \"START_HEIGHT:\" OR \"START_ROUND\" OR textPayload=~\"DECISION_REACHED\" OR \"PROPOSAL_FAILED\" OR \"Proposal succeeded\" OR \"Applying Timeout\" OR \"Accepting\" OR \"Broadcasting\"" + } + }, { "title": "Decisions Reached By Consensus", "description": "The number of decisions reached by way of consensus (10m window)", diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 0017a7bb004..283670c0955 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -434,7 +434,17 @@ fn get_panel_consensus_proposals_dropped_messages_by_reason() -> Panel { } fn get_panel_consensus_decisions_reached_as_proposer() -> Panel { - Panel::from_counter(&CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, PanelType::TimeSeries) + Panel::new( + "Consensus Decisions Reached As Proposer", + "The number of rounds with decision reached where this node is the proposer (10m window)", + vec![format!( + "increase({}[10m])", + CONSENSUS_DECISIONS_REACHED_AS_PROPOSER.get_name_with_filter() + )], + PanelType::TimeSeries, + ) + .with_log_query("\"Building proposal\" OR \"BATCHER_FIN_PROPOSER\"") + .with_log_comment(CONSENSUS_KEY_EVENTS_LOG_QUERY) } pub(crate) fn get_consensus_row() -> Row { @@ -445,9 +455,9 @@ pub(crate) fn get_consensus_row() -> Row { get_panel_consensus_round(), get_panel_consensus_round_advanced(), get_panel_consensus_block_time_avg(), - get_panel_consensus_decisions_reached_as_proposer(), get_panel_consensus_round_above_zero(), get_panel_consensus_block_number_diff_from_sync(), + get_panel_consensus_decisions_reached_as_proposer(), get_panel_consensus_decisions_reached_by_consensus(), get_panel_consensus_decisions_reached_by_sync(), get_panel_consensus_build_proposal_total(), From e54b8d324be043f1acbf8aafb111ea3cd8237d6a Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 14:24:44 +0200 Subject: [PATCH 162/313] ci: Add CODEOWNERS for Cargo.toml (#9486) --- .github/CODEOWNERS | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..77da16e319d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,6 @@ +# GitHub CODEOWNERS file +# This file defines who must review and approve changes to specific files or directories +# For more information, see: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +# Require approval from the sequencer-cargo-owners team for workspace dependency changes +Cargo.toml @starkware-libs/sequencer-cargo-owners From 276ed3572f42f2f2cc2eed204e76e162b5bc95d3 Mon Sep 17 00:00:00 2001 From: Yonatan-Starkware Date: Mon, 27 Oct 2025 14:27:29 +0200 Subject: [PATCH 163/313] blockifier: update sierra_gas (#9768) --- .../resources/orchestrator_versioned_constants_0_14_1.json | 4 ++-- .../resources/app_configs/batcher_config.json | 2 +- crates/apollo_node/resources/config_schema.json | 2 +- crates/blockifier/src/bouncer.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/apollo_consensus_orchestrator/resources/orchestrator_versioned_constants_0_14_1.json b/crates/apollo_consensus_orchestrator/resources/orchestrator_versioned_constants_0_14_1.json index f06fc906940..858127a72ab 100644 --- a/crates/apollo_consensus_orchestrator/resources/orchestrator_versioned_constants_0_14_1.json +++ b/crates/apollo_consensus_orchestrator/resources/orchestrator_versioned_constants_0_14_1.json @@ -1,7 +1,7 @@ { "gas_price_max_change_denominator": 48, - "gas_target": 4000000000, - "max_block_size": 5000000000, + "gas_target": 4800000000, + "max_block_size": 6000000000, "min_gas_price": "0x186a0", "l1_gas_price_margin_percent": 10 } \ No newline at end of file diff --git a/crates/apollo_deployments/resources/app_configs/batcher_config.json b/crates/apollo_deployments/resources/app_configs/batcher_config.json index ac6db6f1d61..1155cab4afe 100644 --- a/crates/apollo_deployments/resources/app_configs/batcher_config.json +++ b/crates/apollo_deployments/resources/app_configs/batcher_config.json @@ -3,7 +3,7 @@ "batcher_config.block_builder_config.bouncer_config.block_max_capacity.message_segment_length": 3700, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_events": 5000, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.n_txs": 500, - "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 5000000000, + "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": 6000000000, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.proving_gas": 6000000000, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": 4000, "batcher_config.block_builder_config.bouncer_config.builtin_weights.gas_costs.pedersen": 5722, diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 340b3aa5e01..fcd8dd03e86 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -57,7 +57,7 @@ "batcher_config.block_builder_config.bouncer_config.block_max_capacity.sierra_gas": { "description": "An upper bound on the total sierra_gas used in a block.", "privacy": "Public", - "value": 5000000000 + "value": 6000000000 }, "batcher_config.block_builder_config.bouncer_config.block_max_capacity.state_diff_size": { "description": "An upper bound on the total state diff size in a block.", diff --git a/crates/blockifier/src/bouncer.rs b/crates/blockifier/src/bouncer.rs index c107961627d..0ed1ccdf258 100644 --- a/crates/blockifier/src/bouncer.rs +++ b/crates/blockifier/src/bouncer.rs @@ -196,7 +196,7 @@ impl Default for BouncerWeights { n_txs: 600, state_diff_size: 4000, // NOTE: Must stay in sync with orchestrator_versioned_constants' max_block_size. - sierra_gas: GasAmount(5000000000), + sierra_gas: GasAmount(6000000000), proving_gas: GasAmount(6000000000), } } From 46537ba24698b60908322cce05f11f74e1241be3 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 14:31:19 +0200 Subject: [PATCH 164/313] apollo_deployments: add nodes 14,15 to testnet and mainnet (#9790) --- .../resources/deployment_inputs/mainnet.json | 2 +- .../deployment_inputs/sepolia_testnet.json | 2 +- .../mainnet/deployment_config_hybrid_14.json | 281 ++++++++++++++++++ .../mainnet/deployment_config_hybrid_15.json | 281 ++++++++++++++++++ .../mainnet/deployment_config_override.json | 4 +- .../deployments/mainnet/hybrid_14.json | 7 + .../deployments/mainnet/hybrid_15.json | 7 + .../deployment_config_hybrid_14.json | 281 ++++++++++++++++++ .../deployment_config_hybrid_15.json | 281 ++++++++++++++++++ .../deployment_config_override.json | 4 +- .../sepolia_testnet/hybrid_14.json | 7 + .../sepolia_testnet/hybrid_15.json | 7 + 12 files changed, 1158 insertions(+), 6 deletions(-) create mode 100644 crates/apollo_deployments/resources/deployments/mainnet/deployment_config_hybrid_14.json create mode 100644 crates/apollo_deployments/resources/deployments/mainnet/deployment_config_hybrid_15.json create mode 100644 crates/apollo_deployments/resources/deployments/mainnet/hybrid_14.json create mode 100644 crates/apollo_deployments/resources/deployments/mainnet/hybrid_15.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_14.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_15.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_14.json create mode 100644 crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_15.json diff --git a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json index 66948b03a4a..65ecae98bb3 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json @@ -1,5 +1,5 @@ { - "node_and_validator_ids": [[0, "0x1"], [1,"0x64"], [2,"0x65"], [3,"0x66"], [10,"0x1"], [11,"0x1"], [12,"0x1"], [13,"0x1"]], + "node_and_validator_ids": [[0, "0x1"], [1,"0x64"], [2,"0x65"], [3,"0x66"], [10,"0x1"], [11,"0x1"], [12,"0x1"], [13,"0x1"], [14,"0x1"], [15,"0x1"]], "num_validators": 3, "http_server_ingress_alternative_name": "alpha-mainnet.starknet.io", "ingress_domain": "starknet.io", diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json index 8a8c3a5f5bf..01f9861050d 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json @@ -1,5 +1,5 @@ { - "node_and_validator_ids": [[0, "0x1"], [1,"0x64"], [2,"0x65"], [3,"0x66"],[10,"0x1"], [11,"0x1"], [12,"0x1"], [13,"0x1"]], + "node_and_validator_ids": [[0, "0x1"], [1,"0x64"], [2,"0x65"], [3,"0x66"],[10,"0x1"], [11,"0x1"], [12,"0x1"], [13,"0x1"], [14,"0x1"], [15,"0x1"]], "num_validators": 3, "http_server_ingress_alternative_name": "alpha-sepolia.starknet.io", "ingress_domain": "starknet.io", diff --git a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_hybrid_14.json b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_hybrid_14.json new file mode 100644 index 00000000000..34db1953da0 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_hybrid_14.json @@ -0,0 +1,281 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_14.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-core-service.apollo-mainnet-14.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service-c2d-56", + "resources": { + "requests": { + "cpu": 50, + "memory": 200 + }, + "limits": { + "cpu": 50, + "memory": 220 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-14" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_14.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "alpha-mainnet.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-14" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_14.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-14" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_14.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-14" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_14.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-mempool-service.apollo-mainnet-14.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-14" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_14.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-14" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_hybrid_15.json b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_hybrid_15.json new file mode 100644 index 00000000000..a6d9504c3cf --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_hybrid_15.json @@ -0,0 +1,281 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_15.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-core-service.apollo-mainnet-15.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service-c2d-56", + "resources": { + "requests": { + "cpu": 50, + "memory": 200 + }, + "limits": { + "cpu": 50, + "memory": 220 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-15" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_15.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "alpha-mainnet.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-15" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_15.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-15" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_15.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-15" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_15.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-mempool-service.apollo-mainnet-15.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-15" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/mainnet/deployment_config_override.json", + "deployments/mainnet/hybrid_15.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-mainnet-15" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json index 9a3443d574a..0e649748b25 100644 --- a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json @@ -2,12 +2,12 @@ "base_layer_config.starknet_contract_address": "0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4", "chain_id": "SN_MAIN", "consensus_manager_config.context_config.num_validators": 3, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-mainnet-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-mainnet-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-mainnet-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-mainnet-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-mainnet-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-mainnet-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-mainnet-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-mainnet-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-mainnet-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-mainnet-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-mainnet-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-mainnet-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-mainnet-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-mainnet-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-mainnet-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-mainnet-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-core-service.apollo-mainnet-14.starknet.io/tcp/53080/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-core-service.apollo-mainnet-15.starknet.io/tcp/53080/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-mainnet-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-mainnet-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-mainnet-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-mainnet-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-mempool-service.apollo-mainnet-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-mempool-service.apollo-mainnet-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-mainnet.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/mainnet/hybrid_14.json b/crates/apollo_deployments/resources/deployments/mainnet/hybrid_14.json new file mode 100644 index 00000000000..067798e3131 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/mainnet/hybrid_14.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.apollo-mainnet-14.starknet.io/tcp/53080/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/mainnet/hybrid_15.json b/crates/apollo_deployments/resources/deployments/mainnet/hybrid_15.json new file mode 100644 index 00000000000..739d625ae9a --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/mainnet/hybrid_15.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.apollo-mainnet-15.starknet.io/tcp/53080/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_14.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_14.json new file mode 100644 index 00000000000..0df9d5f301a --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_14.json @@ -0,0 +1,281 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_14.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-core-service.apollo-sepolia-alpha-14.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service-c2d-56", + "resources": { + "requests": { + "cpu": 50, + "memory": 200 + }, + "limits": { + "cpu": 50, + "memory": 220 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-14" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_14.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "alpha-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-14" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_14.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-14" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_14.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-14" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_14.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-mempool-service.apollo-sepolia-alpha-14.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-14" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_14.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-14" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_15.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_15.json new file mode 100644 index 00000000000..6991bcbd937 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_hybrid_15.json @@ -0,0 +1,281 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_15.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-core-service.apollo-sepolia-alpha-15.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "apollo-core-service-c2d-56", + "resources": { + "requests": { + "cpu": 50, + "memory": 200 + }, + "limits": { + "cpu": 50, + "memory": 220 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-15" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_15.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "alpha-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-15" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_15.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-15" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_15.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-15" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_15.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": { + "type": "LoadBalancer", + "external_dns_name": "sequencer-mempool-service.apollo-sepolia-alpha-15.starknet.io", + "internal": true + }, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 3, + "memory": 12 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-15" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/sepolia_testnet/deployment_config_override.json", + "deployments/sepolia_testnet/hybrid_15.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-sepolia-alpha-15" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json index f247510a584..188ef217d3b 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json @@ -2,12 +2,12 @@ "base_layer_config.starknet_contract_address": "0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057", "chain_id": "SN_SEPOLIA", "consensus_manager_config.context_config.num_validators": 3, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-alpha-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-alpha-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-alpha-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-sepolia-alpha-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-alpha-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-alpha-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-sepolia-alpha-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-alpha-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-alpha-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-alpha-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-sepolia-alpha-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-alpha-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-alpha-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-sepolia-alpha-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-core-service.apollo-sepolia-alpha-14.starknet.io/tcp/53080/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-core-service.apollo-sepolia-alpha-15.starknet.io/tcp/53080/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-alpha-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-alpha-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-sepolia-alpha-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-alpha-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-sepolia-alpha-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-alpha-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-alpha-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-sepolia-alpha-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-alpha-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-sepolia-alpha-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-mempool-service.apollo-sepolia-alpha-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_14.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_14.json new file mode 100644 index 00000000000..320ace7fcb5 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_14.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-14.starknet.io/tcp/53080/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_15.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_15.json new file mode 100644 index 00000000000..a4f76ab5528 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/hybrid_15.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-15.starknet.io/tcp/53080/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, + "validator_id": "0x1" +} From 819772a6aa76f1f58297cc3bfac13371d58dacd3 Mon Sep 17 00:00:00 2001 From: Lev Roitman Date: Mon, 27 Oct 2025 16:59:26 +0200 Subject: [PATCH 165/313] chore: fix apollo_mempool benchmark --- crates/apollo_mempool/benches/main.rs | 2 +- crates/apollo_mempool/benches/utils.rs | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/crates/apollo_mempool/benches/main.rs b/crates/apollo_mempool/benches/main.rs index 431d12eeb5f..a78b40b5910 100644 --- a/crates/apollo_mempool/benches/main.rs +++ b/crates/apollo_mempool/benches/main.rs @@ -10,7 +10,7 @@ /// import the Mempool test utilities. mod utils; -use apollo_mempool::config::MempoolConfig; +use apollo_mempool_config::config::MempoolConfig; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use utils::{BenchTestSetup, BenchTestSetupConfig}; diff --git a/crates/apollo_mempool/benches/utils.rs b/crates/apollo_mempool/benches/utils.rs index eb6b18c1745..1f98ce35b44 100644 --- a/crates/apollo_mempool/benches/utils.rs +++ b/crates/apollo_mempool/benches/utils.rs @@ -1,9 +1,10 @@ use std::sync::Arc; +use apollo_config_manager_types::communication::MockConfigManagerClient; use apollo_infra::component_server::{ComponentServerStarter, LocalServerConfig}; use apollo_infra::metrics::{LocalClientMetrics, LocalServerMetrics}; use apollo_mempool::communication::{create_mempool, LocalMempoolServer}; -use apollo_mempool::config::MempoolConfig; +use apollo_mempool_config::config::MempoolConfig; use apollo_mempool_p2p_types::communication::{ MempoolP2pPropagatorClient, MempoolP2pPropagatorClientResult, @@ -135,7 +136,7 @@ impl TransactionGenerator { fn generate_invoke(&mut self, index: usize) -> AddTransactionArgs { let RpcTransaction::Invoke(invoke_tx) = - self.multi_tx_generator.account_with_id_mut(0).generate_invoke_with_tip(0) + self.multi_tx_generator.account_with_id_mut(0).generate_trivial_rpc_invoke_tx(0) else { panic!("Expected RpcTransaction::Invoke") }; @@ -193,9 +194,20 @@ impl BenchTestSetup { // Create minimal overhead P2P client for benchmark let bench_p2p_client = Arc::new(BenchMempoolP2pPropagator); + // Create mock config manager client for benchmark + let mut mock_config_manager = MockConfigManagerClient::new(); + let dynamic_config = self.config.mempool_config.dynamic_config.clone(); + mock_config_manager + .expect_get_mempool_dynamic_config() + .returning(move || Ok(dynamic_config.clone())); + let mock_config_manager = Arc::new(mock_config_manager); + // Create the mempool component - let mempool_component = - create_mempool(self.config.mempool_config.clone(), bench_p2p_client); + let mempool_component = create_mempool( + self.config.mempool_config.clone(), + bench_p2p_client, + mock_config_manager, + ); // Use static metrics for benchmark let server_metrics = &BENCH_LOCAL_SERVER_METRICS; From b7833c4da3472bb5681e7edf4bb29fce9e55e7b4 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:26:48 +0200 Subject: [PATCH 166/313] ci: fix Sequencer-Docker-Publish triggers (#9754) --- .../workflows/sequencer_docker-publish.yml | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/.github/workflows/sequencer_docker-publish.yml b/.github/workflows/sequencer_docker-publish.yml index 37d3045a66f..09a36295757 100644 --- a/.github/workflows/sequencer_docker-publish.yml +++ b/.github/workflows/sequencer_docker-publish.yml @@ -3,30 +3,14 @@ name: Sequencer-Docker-Publish on: workflow_dispatch: push: - branches: - - main - - main-v*.*.* # e.g. main-v0.14.0 - - v*.*.*-integration # e.g. v0.14.0-integration tags: - "v*.*.*" - "APOLLO-*" - paths: - - ".github/workflows/sequencer_docker-publish.yml" - - "crates/**" - - "scripts/dependencies.sh" - - "scripts/install_build_tools.sh" - - "deployments/images/base/Dockerfile" - - "deployments/images/sequencer/Dockerfile" permissions: contents: read packages: write -# On PR events, cancel existing CI runs on this same PR for this workflow. -concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - env: REGISTRY: ghcr.io REPO_NAME: ${{ github.repository }} @@ -43,7 +27,6 @@ jobs: # Login to a Docker registry except on PR # https://github.com/docker/login-action - name: Login to registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' uses: docker/login-action@v2.1.0 with: registry: ${{ env.REGISTRY }} @@ -59,15 +42,12 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/sequencer tags: | + # Tag-based releases type=raw,enable=${{ startsWith(github.ref, 'refs/tags/') && 'true' || 'false' }},value={{tag}} type=semver,pattern={{raw}} type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - type=ref,event=pr - # set `dev` tag for the default branch (`main`). - type=raw,value=dev,enable={{is_default_branch}} - # set `dev-{{branch}}-{{sha}}` additional tag for the default branch (`main`). - type=raw,value=dev-{{branch}}{{tag}}-{{sha}},enable={{is_default_branch}} + # Manual workflow dispatch type=raw,value={{branch}}{{tag}}-{{sha}},enable=${{ github.event_name == 'workflow_dispatch' }} # Build and push Docker image with Buildx @@ -77,7 +57,7 @@ jobs: with: context: . file: deployments/images/sequencer/Dockerfile - push: ${{ github.event_name != 'pull_request' }} + push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: BUILD_MODE=release From c08bbb215ee6d180986bbbfe5ea2a0d7b0c626d9 Mon Sep 17 00:00:00 2001 From: Yonatan Iluz Date: Mon, 27 Oct 2025 17:33:16 +0200 Subject: [PATCH 167/313] chore: fix deployment --- crates/apollo_deployments/resources/services/hybrid/core.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/apollo_deployments/resources/services/hybrid/core.json b/crates/apollo_deployments/resources/services/hybrid/core.json index 64947ab51e2..6e4ba841090 100644 --- a/crates/apollo_deployments/resources/services/hybrid/core.json +++ b/crates/apollo_deployments/resources/services/hybrid/core.json @@ -68,7 +68,7 @@ "components.l1_gas_price_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_gas_price_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_gas_price_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_gas_price_provider.remote_client_config.retries": 0, + "components.l1_gas_price_provider.remote_client_config.retries": 2, "components.l1_gas_price_provider.url": "sequencer-l1-service", "components.l1_gas_price_scraper.execution_mode": "Disabled", "components.l1_provider.execution_mode": "Remote", @@ -82,7 +82,7 @@ "components.l1_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_provider.remote_client_config.retries": 0, + "components.l1_provider.remote_client_config.retries": 2, "components.l1_provider.url": "sequencer-l1-service", "components.l1_scraper.execution_mode": "Disabled", "components.mempool.execution_mode": "Remote", From d165c66925c95feec2ea0585273e56a3a76199fd Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Mon, 27 Oct 2025 21:56:30 +0200 Subject: [PATCH 168/313] apollo_deployments: reapply PR 9745 - have 0 retries when core tries to communicate with l1 (#9801) --- .../resources/services/distributed/batcher.json | 2 +- .../resources/services/distributed/consensus_manager.json | 2 +- .../apollo_deployments/resources/services/hybrid/core.json | 6 +++--- crates/apollo_deployments/src/deployments/distributed.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/apollo_deployments/resources/services/distributed/batcher.json b/crates/apollo_deployments/resources/services/distributed/batcher.json index 9986b9b2575..90e9428afd1 100644 --- a/crates/apollo_deployments/resources/services/distributed/batcher.json +++ b/crates/apollo_deployments/resources/services/distributed/batcher.json @@ -72,7 +72,7 @@ "components.l1_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_provider.remote_client_config.retries": 2, + "components.l1_provider.remote_client_config.retries": 0, "components.l1_provider.url": "sequencer-l1-service", "components.l1_scraper.execution_mode": "Disabled", "components.mempool.execution_mode": "Remote", diff --git a/crates/apollo_deployments/resources/services/distributed/consensus_manager.json b/crates/apollo_deployments/resources/services/distributed/consensus_manager.json index 4d6e40f9516..f1aa0f9a99e 100644 --- a/crates/apollo_deployments/resources/services/distributed/consensus_manager.json +++ b/crates/apollo_deployments/resources/services/distributed/consensus_manager.json @@ -66,7 +66,7 @@ "components.l1_gas_price_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_gas_price_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_gas_price_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_gas_price_provider.remote_client_config.retries": 2, + "components.l1_gas_price_provider.remote_client_config.retries": 0, "components.l1_gas_price_provider.url": "sequencer-l1-service", "components.l1_gas_price_scraper.execution_mode": "Disabled", "components.l1_provider.execution_mode": "Disabled", diff --git a/crates/apollo_deployments/resources/services/hybrid/core.json b/crates/apollo_deployments/resources/services/hybrid/core.json index 6e4ba841090..0f6757e40f9 100644 --- a/crates/apollo_deployments/resources/services/hybrid/core.json +++ b/crates/apollo_deployments/resources/services/hybrid/core.json @@ -55,7 +55,7 @@ "components.l1_endpoint_monitor.remote_client_config.idle_timeout_ms": 30000, "components.l1_endpoint_monitor.remote_client_config.initial_retry_delay_ms": 1, "components.l1_endpoint_monitor.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_endpoint_monitor.remote_client_config.retries": 2, + "components.l1_endpoint_monitor.remote_client_config.retries": 0, "components.l1_endpoint_monitor.url": "sequencer-l1-service", "components.l1_gas_price_provider.execution_mode": "Remote", "components.l1_gas_price_provider.ip": "0.0.0.0", @@ -68,7 +68,7 @@ "components.l1_gas_price_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_gas_price_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_gas_price_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_gas_price_provider.remote_client_config.retries": 2, + "components.l1_gas_price_provider.remote_client_config.retries": 0, "components.l1_gas_price_provider.url": "sequencer-l1-service", "components.l1_gas_price_scraper.execution_mode": "Disabled", "components.l1_provider.execution_mode": "Remote", @@ -82,7 +82,7 @@ "components.l1_provider.remote_client_config.idle_timeout_ms": 30000, "components.l1_provider.remote_client_config.initial_retry_delay_ms": 1, "components.l1_provider.remote_client_config.max_retry_interval_ms": 1000, - "components.l1_provider.remote_client_config.retries": 2, + "components.l1_provider.remote_client_config.retries": 0, "components.l1_provider.url": "sequencer-l1-service", "components.l1_scraper.execution_mode": "Disabled", "components.mempool.execution_mode": "Remote", diff --git a/crates/apollo_deployments/src/deployments/distributed.rs b/crates/apollo_deployments/src/deployments/distributed.rs index dfa56acd682..abdff035753 100644 --- a/crates/apollo_deployments/src/deployments/distributed.rs +++ b/crates/apollo_deployments/src/deployments/distributed.rs @@ -39,7 +39,7 @@ const BATCHER_STORAGE: usize = 500; const CLASS_MANAGER_STORAGE: usize = 500; const STATE_SYNC_STORAGE: usize = 500; -pub const RETRIES_FOR_L1_SERVICES: usize = 2; +pub const RETRIES_FOR_L1_SERVICES: usize = 0; // TODO(Tsabary): define consts and functions whenever relevant. From 53d54e698e91bedec6f41ddd98fdbc4f0103837d Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Mon, 27 Oct 2025 21:56:54 +0200 Subject: [PATCH 169/313] apollo_l1_provider: remove panic on unknown L1 event type; add support for cancellations (#9776) (#9800) Co-authored-by: guy-starkware --- crates/apollo_l1_provider/src/l1_provider.rs | 8 +++++++- crates/apollo_l1_provider/src/l1_scraper.rs | 7 ------- crates/apollo_l1_provider_types/src/errors.rs | 8 -------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/crates/apollo_l1_provider/src/l1_provider.rs b/crates/apollo_l1_provider/src/l1_provider.rs index b1f5ef608e0..64c0a38906c 100644 --- a/crates/apollo_l1_provider/src/l1_provider.rs +++ b/crates/apollo_l1_provider/src/l1_provider.rs @@ -116,6 +116,13 @@ impl L1Provider { ); }); } + Event::TransactionCanceled(event_data) => { + // TODO(guyn): delete the transaction from the provider. + info!( + "Cancellation finalized with data: {event_data:?}. THIS DOES NOT DELETE \ + THE TRANSACTION FROM THE PROVIDER YET." + ); + } Event::TransactionConsumed { tx_hash, timestamp: consumed_at } => { if let Err(previously_consumed_at) = self.tx_manager.consume_tx(tx_hash, consumed_at, self.clock.unix_now()) @@ -126,7 +133,6 @@ impl L1Provider { ); } } - _ => return Err(L1ProviderError::unsupported_l1_event(event)), } } Ok(()) diff --git a/crates/apollo_l1_provider/src/l1_scraper.rs b/crates/apollo_l1_provider/src/l1_scraper.rs index 7e85658183c..045e53bcc12 100644 --- a/crates/apollo_l1_provider/src/l1_scraper.rs +++ b/crates/apollo_l1_provider/src/l1_scraper.rs @@ -378,13 +378,6 @@ fn handle_client_error( L1ProviderClientError::L1ProviderError(L1ProviderError::Uninitialized) => { Err(L1ScraperError::NeedsRestart) } - L1ProviderClientError::L1ProviderError(L1ProviderError::UnsupportedL1Event(event)) => { - panic!( - "Scraper-->Provider consistency error: the event {event} is not supported by the \ - provider, but has been scraped and sent to it nonetheless. Check the list of \ - tracked events in the scraper and compare to the provider's." - ) - } error => panic!("Unexpected error: {error}"), } } diff --git a/crates/apollo_l1_provider_types/src/errors.rs b/crates/apollo_l1_provider_types/src/errors.rs index 2523e6d2308..9de7017d861 100644 --- a/crates/apollo_l1_provider_types/src/errors.rs +++ b/crates/apollo_l1_provider_types/src/errors.rs @@ -5,8 +5,6 @@ use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; use thiserror::Error; -use crate::Event; - #[derive(Clone, Debug, Error, PartialEq, Eq, Serialize, Deserialize)] pub enum L1ProviderError { #[error("`get_txs` while in `Validate` state")] @@ -26,8 +24,6 @@ pub enum L1ProviderError { UnexpectedHeight { expected_height: BlockNumber, got: BlockNumber }, #[error("Cannot transition from {from} to {to}")] UnexpectedProviderStateTransition { from: String, to: String }, - #[error("L1 event not supported: {0}")] - UnsupportedL1Event(String), #[error("`validate` called while in `Propose` state")] ValidateTransactionConsensusBug, } @@ -36,10 +32,6 @@ impl L1ProviderError { pub fn unexpected_transition(from: impl ToString, to: impl ToString) -> Self { Self::UnexpectedProviderStateTransition { from: from.to_string(), to: to.to_string() } } - - pub fn unsupported_l1_event(event: Event) -> Self { - Self::UnsupportedL1Event(event.to_string()) - } } #[derive(Clone, Debug, Error)] From c5b0a90e1c816b5f5cb8dbfccd30e00e1319d9ed Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Tue, 28 Oct 2025 08:36:52 +0200 Subject: [PATCH 170/313] ci: add dummy bench with input (#9632) --- .../data/dummy_bench_input/large_input.json | 105 ++++++++++++++++++ .../data/dummy_bench_input/small_input.json | 15 +++ crates/bench_tools/src/benches/dummy_bench.rs | 34 +++++- 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 crates/bench_tools/data/dummy_bench_input/large_input.json create mode 100644 crates/bench_tools/data/dummy_bench_input/small_input.json diff --git a/crates/bench_tools/data/dummy_bench_input/large_input.json b/crates/bench_tools/data/dummy_bench_input/large_input.json new file mode 100644 index 00000000000..9b5f02e0c0c --- /dev/null +++ b/crates/bench_tools/data/dummy_bench_input/large_input.json @@ -0,0 +1,105 @@ +{ + "values": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100 + ], + "multiplier": 10 +} \ No newline at end of file diff --git a/crates/bench_tools/data/dummy_bench_input/small_input.json b/crates/bench_tools/data/dummy_bench_input/small_input.json new file mode 100644 index 00000000000..591aebffbb5 --- /dev/null +++ b/crates/bench_tools/data/dummy_bench_input/small_input.json @@ -0,0 +1,15 @@ +{ + "values": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "multiplier": 2 +} \ No newline at end of file diff --git a/crates/bench_tools/src/benches/dummy_bench.rs b/crates/bench_tools/src/benches/dummy_bench.rs index c13f9ae4e95..298dfcc09f9 100644 --- a/crates/bench_tools/src/benches/dummy_bench.rs +++ b/crates/bench_tools/src/benches/dummy_bench.rs @@ -1,6 +1,18 @@ use std::hint::black_box; use criterion::{criterion_group, criterion_main, Criterion}; +use serde::{Deserialize, Serialize}; + +// Input files are embedded at compile time. +// Before building, ensure these files exist (e.g., downloaded from GCS). +const SMALL_INPUT: &str = include_str!("../../data/dummy_bench_input/small_input.json"); +const LARGE_INPUT: &str = include_str!("../../data/dummy_bench_input/large_input.json"); + +#[derive(Debug, Serialize, Deserialize)] +struct DummyInput { + values: Vec, + multiplier: u64, +} #[allow(dead_code)] fn dummy_function(n: u64) -> u64 { @@ -8,7 +20,7 @@ fn dummy_function(n: u64) -> u64 { (0..n).sum() } -/// Example benchmark function that demonstrates how to use Criterion for benchmarking. +/// Example benchmark functions to demonstrate how to use Criterion for benchmarking. /// This is used to test the benchmarking infrastructure and generate sample benchmark results /// that can be parsed by the bench_tools framework. #[allow(dead_code)] @@ -19,5 +31,23 @@ fn dummy_benchmark(c: &mut Criterion) { c.bench_function("dummy_sum_1000", |b| b.iter(|| black_box(dummy_function(1000)))); } -criterion_group!(benches, dummy_benchmark); +#[allow(dead_code)] +fn dummy_benchmark_with_input(c: &mut Criterion) { + let process_input = |input: &DummyInput| input.values.iter().sum::() * input.multiplier; + + let small_input: DummyInput = serde_json::from_str(SMALL_INPUT).unwrap(); + let large_input: DummyInput = serde_json::from_str(LARGE_INPUT).unwrap(); + + c.bench_function("dummy_process_small_input", |b| { + // black_box prevents the compiler from optimizing away the function call during + // benchmarking + b.iter(|| black_box(process_input(&small_input))) + }); + + c.bench_function("dummy_process_large_input", |b| { + b.iter(|| black_box(process_input(&large_input))) + }); +} + +criterion_group!(benches, dummy_benchmark, dummy_benchmark_with_input); criterion_main!(benches); From faee5c48d679c24e78ad67640554981daff39729 Mon Sep 17 00:00:00 2001 From: Yonatan-Starkware Date: Tue, 28 Oct 2025 08:51:31 +0200 Subject: [PATCH 171/313] blockifier: log number of storagw reads and writes (#9788) --- crates/blockifier/src/concurrency/worker_logic.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/blockifier/src/concurrency/worker_logic.rs b/crates/blockifier/src/concurrency/worker_logic.rs index 1f9a9801ac9..fd67dbe38e6 100644 --- a/crates/blockifier/src/concurrency/worker_logic.rs +++ b/crates/blockifier/src/concurrency/worker_logic.rs @@ -382,8 +382,12 @@ impl WorkerExecutor { let tx_hash = Transaction::tx_hash(tx.as_ref()); let run_time = execution_output.run_time.as_millis(); + let n_reads = execution_output.reads.storage.len(); + let n_writes = execution_output.state_diff.storage.len(); log::debug!( - "Transaction with tx_hash: {tx_hash} {execution_status}. Execution time: {run_time}ms." + "Transaction with tx_hash: {tx_hash} {execution_status}. Execution time: \ + {run_time}ms. number of storage reads: {n_reads}, number of storage writes: \ + {n_writes}." ); Ok(CommitResult::Success) From 0c86122e141ab1bfbb26886f97ecfe5834bd1caf Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:07:46 +0200 Subject: [PATCH 172/313] ci: add input to benchmark config (#9633) --- .../bench_tools/src/types/benchmark_config.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/crates/bench_tools/src/types/benchmark_config.rs b/crates/bench_tools/src/types/benchmark_config.rs index 516f79e3cfa..a5cfc59c53b 100644 --- a/crates/bench_tools/src/types/benchmark_config.rs +++ b/crates/bench_tools/src/types/benchmark_config.rs @@ -4,6 +4,9 @@ pub struct BenchmarkConfig { pub name: &'static str, pub package: &'static str, pub cmd_args: &'static [&'static str], + /// Optional input directory path relative to workspace root. If set, inputs will be + /// downloaded from GCS before running the benchmark. + pub input_dir: Option<&'static str>, } impl BenchmarkConfig { @@ -11,6 +14,11 @@ impl BenchmarkConfig { pub fn cmd_args_owned(&self) -> Vec { self.cmd_args.iter().map(|s| s.to_string()).collect() } + + /// Check if this benchmark requires input files. + pub fn needs_inputs(&self) -> bool { + self.input_dir.is_some() + } } /// All available benchmarks defined as a const array. @@ -19,16 +27,25 @@ pub const BENCHMARKS: &[BenchmarkConfig] = &[ name: "full_committer_flow", package: "starknet_committer_and_os_cli", cmd_args: &["bench", "-p", "starknet_committer_and_os_cli", "full_committer_flow"], + input_dir: Some("crates/starknet_committer_and_os_cli/test_inputs"), }, BenchmarkConfig { name: "single_tree_flow", package: "starknet_committer_and_os_cli", cmd_args: &["bench", "-p", "starknet_committer_and_os_cli", "single_tree_flow"], + input_dir: Some("crates/starknet_committer_and_os_cli/test_inputs"), }, BenchmarkConfig { name: "gateway_apply_block", package: "apollo_gateway", cmd_args: &["bench", "-p", "apollo_gateway", "apply_block"], + input_dir: None, + }, + BenchmarkConfig { + name: "dummy_benchmark", + package: "bench_tools", + cmd_args: &["bench", "-p", "bench_tools", "--bench", "dummy_bench"], + input_dir: Some("crates/bench_tools/data/dummy_bench_input"), }, ]; From 4806947f537e08524ee062c7fd39d4ce1c510c87 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:10:51 +0200 Subject: [PATCH 173/313] ci: download bench input from gcs (#9634) --- Cargo.lock | 1 + crates/bench_tools/Cargo.toml | 1 + crates/bench_tools/src/gcs.rs | 34 ++++++++++++- crates/bench_tools/src/gcs_test.rs | 48 +++++++++++++++++++ crates/bench_tools/src/lib.rs | 4 ++ crates/bench_tools/src/test_utils.rs | 11 +++++ .../bench_tools/src/types/estimates_test.rs | 9 +--- 7 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 crates/bench_tools/src/gcs_test.rs create mode 100644 crates/bench_tools/src/test_utils.rs diff --git a/Cargo.lock b/Cargo.lock index 726d0efa146..6bcce452a14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3358,6 +3358,7 @@ dependencies = [ "rstest", "serde", "serde_json", + "tempfile", ] [[package]] diff --git a/crates/bench_tools/Cargo.toml b/crates/bench_tools/Cargo.toml index 3ec042238f8..b8b92de0081 100644 --- a/crates/bench_tools/Cargo.toml +++ b/crates/bench_tools/Cargo.toml @@ -16,6 +16,7 @@ apollo_infra_utils.workspace = true glob.workspace = true rstest.workspace = true serde_json.workspace = true +tempfile.workspace = true [[bench]] harness = false diff --git a/crates/bench_tools/src/gcs.rs b/crates/bench_tools/src/gcs.rs index 551f73269d2..659580e62ab 100644 --- a/crates/bench_tools/src/gcs.rs +++ b/crates/bench_tools/src/gcs.rs @@ -7,7 +7,7 @@ pub const BENCHMARKS_BUCKET: &str = "apollo_benchmarks"; /// Uploads all files from a local directory to Google Cloud Storage. /// /// Uses gcloud CLI to upload files. Before running, authenticate with: -/// `gcloud auth application-default login` +/// `gcloud auth login` /// /// Files are uploaded to: `gs://{BENCHMARKS_BUCKET}/{benchmark_name}/input/` pub fn upload_inputs(benchmark_name: &str, input_dir: &Path) { @@ -35,3 +35,35 @@ pub fn upload_inputs(benchmark_name: &str, input_dir: &Path) { println!("{}", String::from_utf8_lossy(&output.stdout).trim()); println!("Input files uploaded successfully!"); } + +/// Downloads all input files for a benchmark from Google Cloud Storage. +/// +/// Uses gcloud CLI to download files. Before running, authenticate with: +/// `gcloud auth login` +/// +/// Downloads from: `gs://{BENCHMARKS_BUCKET}/{benchmark_name}/input/` to the local input directory. +pub fn download_inputs(benchmark_name: &str, local_input_dir: &Path) { + println!( + "Downloading inputs from gs://{}/{}/input/ to {}", + BENCHMARKS_BUCKET, + benchmark_name, + local_input_dir.display() + ); + + let source = format!("gs://{}/{}/input/*", BENCHMARKS_BUCKET, benchmark_name); + let dest = local_input_dir.display().to_string(); + + // Use gcloud storage cp command to download files. + let output = Command::new("gcloud") + .args(["storage", "cp", "-r", &source, &dest]) + .output() + .expect("Failed to cp inputs from GCS"); + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + panic!("Failed to download inputs from GCS: {}", stderr); + } + + println!("{}", String::from_utf8_lossy(&output.stdout).trim()); + println!("Input files downloaded successfully!"); +} diff --git a/crates/bench_tools/src/gcs_test.rs b/crates/bench_tools/src/gcs_test.rs new file mode 100644 index 00000000000..091d157602e --- /dev/null +++ b/crates/bench_tools/src/gcs_test.rs @@ -0,0 +1,48 @@ +use std::fs; + +use tempfile::TempDir; + +use crate::gcs::{download_inputs, upload_inputs}; +use crate::test_utils; + +#[test] +#[ignore] // Run with: cargo test -p bench_tools -- --ignored +fn test_upload_and_download_inputs() { + let benchmark_name = "dummy_benchmark"; + + // Get paths relative to bench_tools crate directory. + let source_dir = test_utils::bench_tools_crate_dir().join("data/dummy_bench_input"); + + // Ensure source files exist. + assert!(source_dir.exists(), "Source directory does not exist: {}", source_dir.display()); + + // Upload inputs. + println!("Testing upload..."); + upload_inputs(benchmark_name, &source_dir); + + // Create temp directory for download. + let temp_dir = TempDir::new().unwrap(); + let download_dir = temp_dir.path(); + + println!("\nDownload directory: {}", download_dir.display()); + + // Download inputs to temp directory. + println!("\nTesting download..."); + download_inputs(benchmark_name, download_dir); + + // Verify files were downloaded. + let small_input = download_dir.join("small_input.json"); + let large_input = download_dir.join("large_input.json"); + + assert!(small_input.exists(), "small_input.json was not downloaded"); + assert!(large_input.exists(), "large_input.json was not downloaded"); + + // Verify content matches original. + let original_small = fs::read_to_string(source_dir.join("small_input.json")).unwrap(); + let downloaded_small = fs::read_to_string(&small_input).unwrap(); + assert_eq!(original_small, downloaded_small, "small_input.json content does not match"); + + let original_large = fs::read_to_string(source_dir.join("large_input.json")).unwrap(); + let downloaded_large = fs::read_to_string(&large_input).unwrap(); + assert_eq!(original_large, downloaded_large, "large_input.json content does not match"); +} diff --git a/crates/bench_tools/src/lib.rs b/crates/bench_tools/src/lib.rs index 4d4fec63928..16f8ac0e4dd 100644 --- a/crates/bench_tools/src/lib.rs +++ b/crates/bench_tools/src/lib.rs @@ -1,4 +1,8 @@ #[cfg(test)] pub(crate) mod benches; pub mod gcs; +#[cfg(test)] +pub mod gcs_test; +#[cfg(test)] +pub mod test_utils; pub mod types; diff --git a/crates/bench_tools/src/test_utils.rs b/crates/bench_tools/src/test_utils.rs new file mode 100644 index 00000000000..bd42f94545b --- /dev/null +++ b/crates/bench_tools/src/test_utils.rs @@ -0,0 +1,11 @@ +use std::path::PathBuf; + +use rstest::fixture; + +/// Returns the bench_tools crate directory. +#[fixture] +pub fn bench_tools_crate_dir() -> PathBuf { + std::env::var("CARGO_MANIFEST_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| std::env::current_dir().unwrap()) +} diff --git a/crates/bench_tools/src/types/estimates_test.rs b/crates/bench_tools/src/types/estimates_test.rs index baf77b71c56..a327330e9c9 100644 --- a/crates/bench_tools/src/types/estimates_test.rs +++ b/crates/bench_tools/src/types/estimates_test.rs @@ -5,16 +5,9 @@ use std::process::Command; use apollo_infra_utils::path::project_path; use rstest::{fixture, rstest}; +use crate::test_utils::bench_tools_crate_dir; use crate::types::estimates::Estimates; -/// Returns the bench_tools crate directory. -#[fixture] -fn bench_tools_crate_dir() -> PathBuf { - std::env::var("CARGO_MANIFEST_DIR") - .map(PathBuf::from) - .unwrap_or_else(|_| std::env::current_dir().unwrap()) -} - /// Returns the directory where dummy benchmark estimate results are stored. #[fixture] fn dummy_bench_results_dir(bench_tools_crate_dir: PathBuf) -> PathBuf { From 1d8a68edbf17104d07e2b3a03a92f5be791576d1 Mon Sep 17 00:00:00 2001 From: Yonatan-Starkware Date: Tue, 28 Oct 2025 11:45:40 +0200 Subject: [PATCH 174/313] apollo_batcher: add block_weights metrics (#9744) --- crates/apollo_batcher/src/batcher.rs | 5 +++ crates/apollo_batcher/src/block_builder.rs | 1 + crates/apollo_batcher/src/metrics.rs | 6 ++++ .../resources/dev_grafana.json | 18 ++++++++++ .../apollo_dashboard/src/panels/blockifier.rs | 36 ++++++++++++++++++- .../src/blockifier/transaction_executor.rs | 2 +- 6 files changed, 66 insertions(+), 2 deletions(-) diff --git a/crates/apollo_batcher/src/batcher.rs b/crates/apollo_batcher/src/batcher.rs index d084d8db461..31e899bdfaa 100644 --- a/crates/apollo_batcher/src/batcher.rs +++ b/crates/apollo_batcher/src/batcher.rs @@ -68,9 +68,11 @@ use crate::metrics::{ LAST_PROPOSED_BLOCK_HEIGHT, LAST_SYNCED_BLOCK_HEIGHT, NUM_TRANSACTION_IN_BLOCK, + PROVING_GAS_IN_LAST_BLOCK, REJECTED_TRANSACTIONS, REVERTED_BLOCKS, REVERTED_TRANSACTIONS, + SIERRA_GAS_IN_LAST_BLOCK, STORAGE_HEIGHT, SYNCED_TRANSACTIONS, }; @@ -643,6 +645,9 @@ impl Batcher { REJECTED_TRANSACTIONS.increment(n_rejected_txs); REVERTED_TRANSACTIONS.increment(n_reverted_count); NUM_TRANSACTION_IN_BLOCK.record_lossy(n_txs); + SIERRA_GAS_IN_LAST_BLOCK.set_lossy(block_execution_artifacts.bouncer_weights.sierra_gas.0); + PROVING_GAS_IN_LAST_BLOCK + .set_lossy(block_execution_artifacts.bouncer_weights.proving_gas.0); Ok(DecisionReachedResponse { state_diff, diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index 1d815658c09..3cae0f97f44 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -379,6 +379,7 @@ impl BlockBuilder { casm_hash_computation_data_proving_gas, compiled_class_hashes_for_migration, } = block_summary; + let mut execution_data = std::mem::take(&mut self.execution_data); if let Some(final_n_executed_txs) = final_n_executed_txs { // Remove the transactions that were executed, but eventually not included in the block. diff --git a/crates/apollo_batcher/src/metrics.rs b/crates/apollo_batcher/src/metrics.rs index 0b0f9e6dcd6..3977de392d3 100644 --- a/crates/apollo_batcher/src/metrics.rs +++ b/crates/apollo_batcher/src/metrics.rs @@ -48,6 +48,9 @@ define_metrics!( MetricCounter { PRECONFIRMED_BLOCK_WRITTEN, "batcher_preconfirmed_block_written", "Counter of preconfirmed blocks written to storage", init = 0 }, // Block close reason LabeledMetricCounter { BLOCK_CLOSE_REASON, "batcher_block_close_reason", "Number of blocks closed by reason", init = 0 , labels = BLOCK_CLOSE_REASON_LABELS}, + // Block weights + MetricGauge { SIERRA_GAS_IN_LAST_BLOCK, "batcher_sierra_gas_in_last_block", "The sierra gas in the last block"}, + MetricGauge { PROVING_GAS_IN_LAST_BLOCK, "batcher_proving_gas_in_last_block", "The proving gas in the last block"}, }, ); @@ -93,6 +96,9 @@ pub fn register_metrics(storage_height: BlockNumber) { BLOCK_CLOSE_REASON.register(); NUM_TRANSACTION_IN_BLOCK.register(); + SIERRA_GAS_IN_LAST_BLOCK.register(); + PROVING_GAS_IN_LAST_BLOCK.register(); + // Blockifier's metrics CALLS_RUNNING_NATIVE.register(); CLASS_CACHE_HITS.register(); diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 8827911eb67..f64e06ba693 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -971,6 +971,24 @@ "histogram_quantile(0.95, sum by (le) (rate(batcher_num_transaction_in_block_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))" ], "extra_params": {} + }, + { + "title": "Average Sierra Gas Usage in Block", + "description": "The average sierra gas usage in block (10m window)", + "type": "timeseries", + "exprs": [ + "avg_over_time(batcher_sierra_gas_in_last_block{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])/1000000000" + ], + "extra_params": {} + }, + { + "title": "Average Proving Gas Usage in Block", + "description": "The average proving gas usage in block (10m window)", + "type": "timeseries", + "exprs": [ + "avg_over_time(batcher_proving_gas_in_last_block{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m])/1000000000" + ], + "extra_params": {} } ], "collapsed": true diff --git a/crates/apollo_dashboard/src/panels/blockifier.rs b/crates/apollo_dashboard/src/panels/blockifier.rs index 74b74584c10..d7ffb4241d8 100644 --- a/crates/apollo_dashboard/src/panels/blockifier.rs +++ b/crates/apollo_dashboard/src/panels/blockifier.rs @@ -1,4 +1,8 @@ -use apollo_batcher::metrics::NUM_TRANSACTION_IN_BLOCK; +use apollo_batcher::metrics::{ + NUM_TRANSACTION_IN_BLOCK, + PROVING_GAS_IN_LAST_BLOCK, + SIERRA_GAS_IN_LAST_BLOCK, +}; use blockifier::metrics::{ BLOCKIFIER_METRIC_RATE_DURATION, CALLS_RUNNING_NATIVE, @@ -11,6 +15,8 @@ use blockifier::metrics::{ use crate::dashboard::{Panel, PanelType, Row}; +const DENOMINATOR_DIVISOR_FOR_READABILITY: f64 = 1_000_000_000.0; + // TODO(MatanL/Shahak): use clamp_min(X, 1) on denom to avoid division by zero. fn get_panel_blockifier_state_reader_class_cache_miss_ratio() -> Panel { Panel::ratio_time_series( @@ -56,6 +62,32 @@ fn get_panel_transactions_per_block() -> Panel { ) } +fn get_panel_sierra_gas_in_last_block() -> Panel { + Panel::new( + "Average Sierra Gas Usage in Block", + "The average sierra gas usage in block (10m window)", + vec![format!( + "avg_over_time({}[10m])/{}", + SIERRA_GAS_IN_LAST_BLOCK.get_name_with_filter(), + DENOMINATOR_DIVISOR_FOR_READABILITY + )], + PanelType::TimeSeries, + ) +} + +fn get_panel_proving_gas_in_last_block() -> Panel { + Panel::new( + "Average Proving Gas Usage in Block", + "The average proving gas usage in block (10m window)", + vec![format!( + "avg_over_time({}[10m])/{}", + PROVING_GAS_IN_LAST_BLOCK.get_name_with_filter(), + DENOMINATOR_DIVISOR_FOR_READABILITY + )], + PanelType::TimeSeries, + ) +} + pub(crate) fn get_blockifier_row() -> Row { Row::new( "Blockifier", @@ -65,6 +97,8 @@ pub(crate) fn get_blockifier_row() -> Row { get_panel_native_compilation_error(), get_panel_native_execution_ratio(), get_panel_transactions_per_block(), + get_panel_sierra_gas_in_last_block(), + get_panel_proving_gas_in_last_block(), ], ) } diff --git a/crates/blockifier/src/blockifier/transaction_executor.rs b/crates/blockifier/src/blockifier/transaction_executor.rs index 3e8978b9573..64898bdcf48 100644 --- a/crates/blockifier/src/blockifier/transaction_executor.rs +++ b/crates/blockifier/src/blockifier/transaction_executor.rs @@ -24,7 +24,6 @@ use crate::transaction::errors::TransactionExecutionError; use crate::transaction::objects::TransactionExecutionInfo; use crate::transaction::transaction_execution::Transaction; use crate::transaction::transactions::ExecutableTransaction; - #[cfg(test)] #[path = "transaction_executor_test.rs"] pub mod transaction_executor_test; @@ -241,6 +240,7 @@ pub(crate) fn finalize_block( block_context.block_info.block_number, bouncer.get_bouncer_weights() ); + let alias_contract_address = block_context .versioned_constants .os_constants From bb9e6488cdfb69947646472f1b6196062f594a4e Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:01:40 +0200 Subject: [PATCH 175/313] apollo_config_manager: update config only on changes (#9570) --- .../src/config_manager_runner.rs | 44 +++++++++---- .../src/config_manager_runner_tests.rs | 11 +++- crates/apollo_node/src/components.rs | 65 ++++++++++--------- 3 files changed, 72 insertions(+), 48 deletions(-) diff --git a/crates/apollo_config_manager/src/config_manager_runner.rs b/crates/apollo_config_manager/src/config_manager_runner.rs index bb0fc096c00..1c6fbb3abf9 100644 --- a/crates/apollo_config_manager/src/config_manager_runner.rs +++ b/crates/apollo_config_manager/src/config_manager_runner.rs @@ -17,6 +17,7 @@ pub mod config_manager_runner_tests; pub struct ConfigManagerRunner { config_manager_config: ConfigManagerConfig, config_manager_client: SharedConfigManagerClient, + latest_node_dynamic_config: NodeDynamicConfig, cli_args: Vec, } @@ -50,30 +51,45 @@ impl ConfigManagerRunner { pub fn new( config_manager_config: ConfigManagerConfig, config_manager_client: SharedConfigManagerClient, + initial_node_dynamic_config: NodeDynamicConfig, cli_args: Vec, ) -> Self { - Self { config_manager_config, config_manager_client, cli_args } + Self { + config_manager_config, + config_manager_client, + latest_node_dynamic_config: initial_node_dynamic_config, + cli_args, + } } // TODO(Nadin): Define a proper result type instead of Box pub(crate) async fn update_config( - &self, + &mut self, ) -> Result> { let config = load_and_validate_config(self.cli_args.clone())?; let node_dynamic_config = NodeDynamicConfig::from(&config); - info!("Extracted NodeDynamicConfig: {:?}", node_dynamic_config); - // TODO(Nadin/Tsabary): Store the last loaded config, compare for changes and only send the - // changes to the config manager. - match self.config_manager_client.set_node_dynamic_config(node_dynamic_config.clone()).await - { - Ok(()) => { - info!("Successfully updated dynamic config"); - Ok(node_dynamic_config) - } - Err(e) => { - error!("Failed to update dynamic config: {:?}", e); - Err(format!("Failed to update dynamic config: {:?}", e).into()) + // Compare the previous and the newly read node dynamic config. + if self.latest_node_dynamic_config == node_dynamic_config { + // No change, so no action is needed. + Ok(node_dynamic_config) + } else { + // TODO(Nadin/Tsabary): log the diff between the latest and the new node dynamic config. + // Update the latest node dynamic config. + self.latest_node_dynamic_config = node_dynamic_config.clone(); + match self + .config_manager_client + .set_node_dynamic_config(node_dynamic_config.clone()) + .await + { + Ok(()) => { + info!("Successfully updated dynamic config"); + Ok(node_dynamic_config) + } + Err(e) => { + error!("Failed to update dynamic config: {:?}", e); + Err(format!("Failed to update dynamic config: {:?}", e).into()) + } } } } diff --git a/crates/apollo_config_manager/src/config_manager_runner_tests.rs b/crates/apollo_config_manager/src/config_manager_runner_tests.rs index f35ad2cc240..bf22cd88d8a 100644 --- a/crates/apollo_config_manager/src/config_manager_runner_tests.rs +++ b/crates/apollo_config_manager/src/config_manager_runner_tests.rs @@ -10,6 +10,7 @@ use apollo_config_manager_types::communication::{ use apollo_node_config::config_utils::DeploymentBaseAppConfig; use apollo_node_config::definitions::ConfigPointersMap; use apollo_node_config::node_config::{ + NodeDynamicConfig, SequencerNodeConfig, CONFIG_NON_POINTERS_WHITELIST, CONFIG_POINTERS, @@ -98,9 +99,15 @@ async fn test_config_manager_runner_update_config_with_changed_values() { // Create a temporary config file and get the validator id value. let (temp_file, cli_args, validator_id_value) = create_temp_config_file_and_args(); + let node_dynamic_config = NodeDynamicConfig::default(); + // Create a config manager runner and update the config. - let config_manager_runner = - ConfigManagerRunner::new(config_manager_config, config_manager_client, cli_args); + let mut config_manager_runner = ConfigManagerRunner::new( + config_manager_config, + config_manager_client, + node_dynamic_config, + cli_args, + ); // Helper function to convert a hex string to a u128. fn hex_to_u128(s: &str) -> u128 { diff --git a/crates/apollo_node/src/components.rs b/crates/apollo_node/src/components.rs index 236441c8519..5e40a9187f3 100644 --- a/crates/apollo_node/src/components.rs +++ b/crates/apollo_node/src/components.rs @@ -125,39 +125,40 @@ pub async fn create_node_components( ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, }; - let (config_manager, config_manager_runner) = match config - .components - .config_manager - .execution_mode - { - ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled => { - let config_manager_config = - config.config_manager_config.as_ref().expect("Config Manager config should be set"); - let config_manger = - ConfigManager::new(config_manager_config.clone(), NodeDynamicConfig::from(config)); - let config_manager_client = clients - .get_config_manager_shared_client() - .expect("Config Manager client should be available"); - let config_manager_runner = ConfigManagerRunner::new( - config_manager_config.clone(), - config_manager_client, - cli_args, - ); - (Some(config_manger), Some(config_manager_runner)) - } + let (config_manager, config_manager_runner) = + match config.components.config_manager.execution_mode { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled => { + let node_dynamic_config = NodeDynamicConfig::from(config); + let config_manager_config = config + .config_manager_config + .as_ref() + .expect("Config Manager config should be set"); + let config_manger = + ConfigManager::new(config_manager_config.clone(), node_dynamic_config.clone()); + let config_manager_client = clients + .get_config_manager_shared_client() + .expect("Config Manager client should be available"); + let config_manager_runner = ConfigManagerRunner::new( + config_manager_config.clone(), + config_manager_client, + node_dynamic_config, + cli_args, + ); + (Some(config_manger), Some(config_manager_runner)) + } - ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled - | ReactiveComponentExecutionMode::Remote => { - panic!( - "ConfigManager does not support remote mode - it's a local infrastructure \ - component" - ); - } - ReactiveComponentExecutionMode::Disabled => { - // TODO(tsabary): assert config is not set. - (None, None) - } - }; + ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled + | ReactiveComponentExecutionMode::Remote => { + panic!( + "ConfigManager does not support remote mode - it's a local infrastructure \ + component" + ); + } + ReactiveComponentExecutionMode::Disabled => { + // TODO(tsabary): assert config is not set. + (None, None) + } + }; let consensus_manager = match config.components.consensus_manager.execution_mode { ActiveComponentExecutionMode::Enabled => { From 9f79647b1a1944203f3b6b961c38c4120eb22610 Mon Sep 17 00:00:00 2001 From: dorimedini-starkware Date: Tue, 28 Oct 2025 13:32:09 +0200 Subject: [PATCH 176/313] release: commitlint on PR titles only (#9806) Signed-off-by: Dori Medini --- .github/workflows/main_pr.yml | 7 ------- scripts/local_presubmit.sh | 35 -------------------------------- scripts/presubmit_fast_checks.py | 20 ------------------ 3 files changed, 62 deletions(-) diff --git a/.github/workflows/main_pr.yml b/.github/workflows/main_pr.yml index b6413e13cfb..574181966f9 100644 --- a/.github/workflows/main_pr.yml +++ b/.github/workflows/main_pr.yml @@ -32,13 +32,6 @@ jobs: - name: Install commitlint run: npm install --global @commitlint/cli @commitlint/config-conventional - - name: Validate PR commits with commitlint - if: github.event_name == 'pull_request' && !(contains(github.event.pull_request.title, 'merge-main') || contains(github.event.pull_request.title, 'merge main')) - env: - BASE_SHA: ${{ github.event.pull_request.base.sha }} - HEAD_SHA: ${{ github.event.pull_request.head.sha }} - run: commitlint --from "$BASE_SHA" --to "$HEAD_SHA" --verbose - - name: Validate PR title with commitlint if: github.event_name != 'merge_group' && github.event_name != 'push' && !(contains(github.event.pull_request.title, 'merge-main') || contains(github.event.pull_request.title, 'merge main')) env: diff --git a/scripts/local_presubmit.sh b/scripts/local_presubmit.sh index 9b6229dde76..5e7accb0908 100755 --- a/scripts/local_presubmit.sh +++ b/scripts/local_presubmit.sh @@ -70,17 +70,6 @@ setup_env_variables_from_yml() { } install_dependencies() { - packages=("@commitlint/cli" "@commitlint/config-conventional") - - for pkg in "${packages[@]}"; do - if npm list "$pkg" >/dev/null 2>&1; then - log_debug "$pkg is already installed ✅" - else - echo "$pkg is NOT installed ❌ — installing..." - npm install "$pkg" - fi - done - # List of crate names to check/install CRATES=("taplo-cli" "cargo-machete") @@ -195,29 +184,6 @@ restore_old_env() { fi } -add_commit_lint_to_path() { - # Step 1: Try to locate commitlint using which. - COMMITLINT_PATH="$(which commitlint)" - if [ -n "$COMMITLINT_PATH" ]; then - log_debug 'commitlint found in $PATH' - return - fi - - # Step 2: If which fails, use find to search from home directory - echo "commitlint not found via which. Consider adding it to your path. Searching with find..." - COMMITLINT_PATH="$(find ~/ \( -type f -o -type l \) -name commitlint -perm -u+x 2>/dev/null | grep "bin/" | head -n 1 | xargs dirname)" - - # Step 3: Add to path if needed - if [ -n "$COMMITLINT_PATH" ]; then - echo "commitlint found at: $COMMITLINT_PATH" - ORIGINAL_PATH="$PATH" - export PATH="$COMMITLINT_PATH:$PATH" - else - echo "commitlint not found in PATH or local directories." >&2 - exit 1 - fi -} - # Parse command-line arguments parse_args "$@" @@ -233,7 +199,6 @@ setup_new_venv install_yq setup_env_variables_from_yml install_dependencies -add_commit_lint_to_path # Change directory to the top of the repository which is needed for the presubmit script to run. cd "$REPO_LOCATION" || { diff --git a/scripts/presubmit_fast_checks.py b/scripts/presubmit_fast_checks.py index cacb9d7db57..22dc3610466 100644 --- a/scripts/presubmit_fast_checks.py +++ b/scripts/presubmit_fast_checks.py @@ -104,25 +104,6 @@ def __init__(self): super().__init__(commands=[["git", "submodule", "status"]]) -class CommitLintCheck(ExternalCommandCheck): - def __init__(self, from_commit_hash: str, to_commit_hash: str): - assert from_commit_hash, "from_commit_hash is required for commit lint check." - assert to_commit_hash, "to_commit_hash is required for commit lint check." - super().__init__( - commands=[["commitlint"] + ["--from", from_commit_hash] + ["--to", to_commit_hash]] - ) - - @classmethod - def required_args(cls: type[TCheck]) -> set[PresubmitArg]: - return {PresubmitArg.FROM_COMMIT_HASH, PresubmitArg.TO_COMMIT_HASH} - - @classmethod - def from_args(cls, args: argparse.Namespace): - return CommitLintCheck( - from_commit_hash=args.from_commit_hash, to_commit_hash=args.to_commit_hash - ) - - class TodosCheck(Check): def __init__(self, from_commit_hash: str): assert from_commit_hash, "from_commit_hash is required for TODOs check." @@ -224,7 +205,6 @@ def get_checks_to_run(args: argparse.Namespace, all_checks: dict[str, type[Check def main(): all_check_classes = [ - CommitLintCheck, GitSubmodulesCheck, TodosCheck, CargoLockCheck, From dcb7f53331e2053dde92da9c86473e79b43b149b Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Wed, 29 Oct 2025 09:46:53 +0200 Subject: [PATCH 177/313] infra: copy dir rec (#9802) --- crates/bench_tools/src/lib.rs | 3 + crates/bench_tools/src/utils.rs | 64 ++++++++++++++++ crates/bench_tools/src/utils_test.rs | 105 +++++++++++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 crates/bench_tools/src/utils.rs create mode 100644 crates/bench_tools/src/utils_test.rs diff --git a/crates/bench_tools/src/lib.rs b/crates/bench_tools/src/lib.rs index 16f8ac0e4dd..c6a448e090b 100644 --- a/crates/bench_tools/src/lib.rs +++ b/crates/bench_tools/src/lib.rs @@ -6,3 +6,6 @@ pub mod gcs_test; #[cfg(test)] pub mod test_utils; pub mod types; +pub(crate) mod utils; +#[cfg(test)] +mod utils_test; diff --git a/crates/bench_tools/src/utils.rs b/crates/bench_tools/src/utils.rs new file mode 100644 index 00000000000..50f9fa0cd33 --- /dev/null +++ b/crates/bench_tools/src/utils.rs @@ -0,0 +1,64 @@ +use std::fs; +use std::path::Path; + +/// Recursively copies the contents of a directory from `src` to `dst`. +/// +/// Creates the destination directory if it doesn't exist. If a file or directory +/// with the same name already exists in the destination, it will be overwritten. +/// If `src` and `dst` are the same path, this function returns early without doing anything. +/// +/// # Panics +/// Panics if the source or destination paths are files. +/// Panics if any I/O operation fails, including: +/// - Creating the destination directory +/// - Reading the source directory +/// - Copying files +/// - Accessing file metadata +#[allow(dead_code)] +pub(crate) fn copy_dir_contents(src: &Path, dst: &Path) { + // Ensure destination exists. + fs::create_dir_all(dst) + .unwrap_or_else(|e| panic!("Failed to create directory {}: {}", dst.display(), e)); + + // Verify that source and destination are directories. + if !src.is_dir() { + panic!("Source path is not a directory: {}", src.display()); + } + if !dst.is_dir() { + panic!("Destination path is not a directory: {}", dst.display()); + } + + // No-op if source and destination are the same. + // Canonicalize paths to handle relative vs absolute paths and symlinks. + let src_canonical = src + .canonicalize() + .unwrap_or_else(|e| panic!("Failed to canonicalize source path {}: {}", src.display(), e)); + let dst_canonical = dst.canonicalize().unwrap_or_else(|e| { + panic!("Failed to canonicalize destination path {}: {}", dst.display(), e) + }); + + if src_canonical == dst_canonical { + return; + } + + let entries = fs::read_dir(src) + .unwrap_or_else(|e| panic!("Failed to read directory {}: {}", src.display(), e)); + + for entry in entries { + let entry = entry.unwrap_or_else(|e| panic!("Failed to read directory entry: {}", e)); + let from = entry.path(); + let to = dst.join(entry.file_name()); + + let file_type = entry + .file_type() + .unwrap_or_else(|e| panic!("Failed to get file type for {}: {}", from.display(), e)); + + if file_type.is_dir() { + copy_dir_contents(&from, &to); + } else { + fs::copy(&from, &to).unwrap_or_else(|e| { + panic!("Failed to copy {} to {}: {}", from.display(), to.display(), e) + }); + } + } +} diff --git a/crates/bench_tools/src/utils_test.rs b/crates/bench_tools/src/utils_test.rs new file mode 100644 index 00000000000..0127911a357 --- /dev/null +++ b/crates/bench_tools/src/utils_test.rs @@ -0,0 +1,105 @@ +use std::fs; +use std::path::Path; + +use rstest::rstest; +use tempfile::TempDir; + +use crate::utils::copy_dir_contents; + +/// Helper function to create a test directory structure in a temporary directory. +/// Returns the TempDir to keep it alive for the duration of the test. +fn create_test_dir_structure() -> TempDir { + let temp_dir = TempDir::new().unwrap(); + let base = temp_dir.path(); + + // Create files + fs::write(base.join("file1.txt"), "content1").unwrap(); + fs::write(base.join("file2.txt"), "content2").unwrap(); + + // Create subdirectory with files + fs::create_dir(base.join("subdir")).unwrap(); + fs::write(base.join("subdir/file3.txt"), "content3").unwrap(); + fs::write(base.join("subdir/file4.txt"), "content4").unwrap(); + + // Create nested subdirectory + fs::create_dir(base.join("subdir/nested")).unwrap(); + fs::write(base.join("subdir/nested/file5.txt"), "content5").unwrap(); + + temp_dir +} + +/// Verifies the test directory structure created by create_test_dir_structure. +fn verify_test_dir_structure(dir: &Path) { + assert!(dir.exists()); + assert!(dir.is_dir()); + + // Verify top-level files + assert!(dir.join("file1.txt").exists()); + assert!(dir.join("file2.txt").exists()); + assert_eq!(fs::read_to_string(dir.join("file1.txt")).unwrap(), "content1"); + assert_eq!(fs::read_to_string(dir.join("file2.txt")).unwrap(), "content2"); + + // Verify subdir and its files + assert!(dir.join("subdir").is_dir()); + assert!(dir.join("subdir/file3.txt").exists()); + assert!(dir.join("subdir/file4.txt").exists()); + assert_eq!(fs::read_to_string(dir.join("subdir/file3.txt")).unwrap(), "content3"); + assert_eq!(fs::read_to_string(dir.join("subdir/file4.txt")).unwrap(), "content4"); + + // Verify nested subdir and its file + assert!(dir.join("subdir/nested").is_dir()); + assert!(dir.join("subdir/nested/file5.txt").exists()); + assert_eq!(fs::read_to_string(dir.join("subdir/nested/file5.txt")).unwrap(), "content5"); +} + +#[rstest] +fn test_copy_basic_structure() { + let temp_src = create_test_dir_structure(); + let temp_dst = TempDir::new().unwrap(); + + copy_dir_contents(temp_src.path(), temp_dst.path()); + + verify_test_dir_structure(temp_dst.path()); +} + +#[rstest] +fn test_copy_to_nonexistent_destination() { + let temp_src = create_test_dir_structure(); + let temp_parent = TempDir::new().unwrap(); + let dst = temp_parent.path().join("new_dir"); + + assert!(!dst.exists()); + copy_dir_contents(temp_src.path(), &dst); + + verify_test_dir_structure(&dst); +} + +#[rstest] +fn test_copy_overwrites_existing_files() { + let temp_src = TempDir::new().unwrap(); + fs::write(temp_src.path().join("file.txt"), "new content").unwrap(); + + let temp_dst = TempDir::new().unwrap(); + fs::write(temp_dst.path().join("file.txt"), "old content").unwrap(); + + copy_dir_contents(temp_src.path(), temp_dst.path()); + + assert_eq!(fs::read_to_string(temp_dst.path().join("file.txt")).unwrap(), "new content"); +} + +#[rstest] +/// Tests that copying a directory to the same path does nothing. +fn test_copy_same_path() { + let temp = create_test_dir_structure(); + + copy_dir_contents(temp.path(), temp.path()); + + verify_test_dir_structure(temp.path()); +} + +#[rstest] +#[should_panic(expected = "Source path is not a directory: /nonexistent")] +fn test_copy_nonexistent_source_panics() { + let temp_dst = TempDir::new().unwrap(); + copy_dir_contents(Path::new("/nonexistent"), temp_dst.path()); +} From 6521a25de0fe7ea320909c935725c8d53840d620 Mon Sep 17 00:00:00 2001 From: Nadin Jbara <93648739+nadin-Starkware@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:07:51 +0200 Subject: [PATCH 178/313] apollo_config_manager: log the diff between the latest and the new node dynamic config (#9796) --- Cargo.lock | 1 + crates/apollo_config_manager/Cargo.toml | 2 ++ .../src/config_manager_runner.rs | 26 +++++++++++++- .../src/config_manager_runner_tests.rs | 34 +++++++++++++++++++ crates/apollo_node_config/src/node_config.rs | 10 ++++++ 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 6bcce452a14..ca570498e86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1127,6 +1127,7 @@ dependencies = [ "tempfile", "tokio", "tracing", + "tracing-test", ] [[package]] diff --git a/crates/apollo_config_manager/Cargo.toml b/crates/apollo_config_manager/Cargo.toml index 95d1bf65a4c..34be6f69a15 100644 --- a/crates/apollo_config_manager/Cargo.toml +++ b/crates/apollo_config_manager/Cargo.toml @@ -12,6 +12,7 @@ testing = [] workspace = true [dependencies] +apollo_config.workspace = true apollo_config_manager_config.workspace = true apollo_config_manager_types.workspace = true apollo_consensus_config.workspace = true @@ -30,3 +31,4 @@ apollo_config_manager_types = { workspace = true, features = ["testing"] } apollo_node_config = { workspace = true, features = ["testing"] } starknet_api.workspace = true tempfile.workspace = true +tracing-test.workspace = true diff --git a/crates/apollo_config_manager/src/config_manager_runner.rs b/crates/apollo_config_manager/src/config_manager_runner.rs index 1c6fbb3abf9..8a12efb06b9 100644 --- a/crates/apollo_config_manager/src/config_manager_runner.rs +++ b/crates/apollo_config_manager/src/config_manager_runner.rs @@ -1,5 +1,7 @@ +use std::collections::BTreeSet; use std::future::pending; +use apollo_config::presentation::get_config_presentation; use apollo_config_manager_config::config::ConfigManagerConfig; use apollo_config_manager_types::communication::SharedConfigManagerClient; use apollo_infra::component_definitions::{default_component_start_fn, ComponentStarter}; @@ -7,6 +9,7 @@ use apollo_infra::component_server::WrapperServer; use apollo_node_config::config_utils::load_and_validate_config; use apollo_node_config::node_config::NodeDynamicConfig; use async_trait::async_trait; +use serde_json::Value; use tokio::time::{interval, Duration as TokioDuration}; use tracing::{error, info}; @@ -74,7 +77,8 @@ impl ConfigManagerRunner { // No change, so no action is needed. Ok(node_dynamic_config) } else { - // TODO(Nadin/Tsabary): log the diff between the latest and the new node dynamic config. + // Log the diff between the latest and the new node dynamic config. + self.log_config_diff(&self.latest_node_dynamic_config, &node_dynamic_config); // Update the latest node dynamic config. self.latest_node_dynamic_config = node_dynamic_config.clone(); match self @@ -93,6 +97,26 @@ impl ConfigManagerRunner { } } } + + fn log_config_diff(&self, old_config: &NodeDynamicConfig, new_config: &NodeDynamicConfig) { + let old_config = get_config_presentation(old_config, false).unwrap(); + let new_config = get_config_presentation(new_config, false).unwrap(); + let all_keys: BTreeSet<_> = old_config + .as_object() + .unwrap() + .keys() + .chain(new_config.as_object().unwrap().keys()) + .collect(); + + for key in all_keys { + let old_value = old_config.as_object().unwrap().get(key).unwrap_or(&Value::Null); + let new_value = new_config.as_object().unwrap().get(key).unwrap_or(&Value::Null); + + if old_value != new_value { + info!("ConfigManagerRunner: {key} changed from {old_value} to {new_value}"); + } + } + } } pub type ConfigManagerRunnerServer = WrapperServer; diff --git a/crates/apollo_config_manager/src/config_manager_runner_tests.rs b/crates/apollo_config_manager/src/config_manager_runner_tests.rs index bf22cd88d8a..999af19905f 100644 --- a/crates/apollo_config_manager/src/config_manager_runner_tests.rs +++ b/crates/apollo_config_manager/src/config_manager_runner_tests.rs @@ -7,6 +7,7 @@ use apollo_config_manager_types::communication::{ MockConfigManagerClient, SharedConfigManagerClient, }; +use apollo_consensus_config::config::ConsensusDynamicConfig; use apollo_node_config::config_utils::DeploymentBaseAppConfig; use apollo_node_config::definitions::ConfigPointersMap; use apollo_node_config::node_config::{ @@ -18,6 +19,7 @@ use apollo_node_config::node_config::{ use serde_json::Value; use starknet_api::core::ContractAddress; use tempfile::NamedTempFile; +use tracing_test::traced_test; use crate::config_manager_runner::ConfigManagerRunner; @@ -144,3 +146,35 @@ async fn test_config_manager_runner_update_config_with_changed_values() { expected_validator_id ); } + +#[traced_test] +#[test] +fn log_config_diff_changes() { + let old_dynamic_config = NodeDynamicConfig { + consensus_dynamic_config: Some(ConsensusDynamicConfig { + validator_id: ContractAddress::from(1u128), + }), + ..Default::default() + }; + + let new_dynamic_config = NodeDynamicConfig { + consensus_dynamic_config: Some(ConsensusDynamicConfig { + validator_id: ContractAddress::from(2u128), + }), + ..Default::default() + }; + + let mock_client = MockConfigManagerClient::new(); + let runner = ConfigManagerRunner::new( + ConfigManagerConfig::default(), + Arc::new(mock_client), + old_dynamic_config.clone(), + Vec::::new(), + ); + + runner.log_config_diff(&old_dynamic_config, &new_dynamic_config); + + assert!(logs_contain( + r#"consensus_dynamic_config changed from {"validator_id":"0x1"} to {"validator_id":"0x2"}"# + )); +} diff --git a/crates/apollo_node_config/src/node_config.rs b/crates/apollo_node_config/src/node_config.rs index 2b6c114ba21..297a035290d 100644 --- a/crates/apollo_node_config/src/node_config.rs +++ b/crates/apollo_node_config/src/node_config.rs @@ -294,6 +294,16 @@ pub struct NodeDynamicConfig { pub mempool_dynamic_config: Option, } +impl SerializeConfig for NodeDynamicConfig { + fn dump(&self) -> BTreeMap { + let sub_configs = [ + ser_optional_sub_config(&self.consensus_dynamic_config, "consensus_dynamic_config"), + ser_optional_sub_config(&self.mempool_dynamic_config, "mempool_dynamic_config"), + ]; + sub_configs.into_iter().flatten().collect() + } +} + impl From<&SequencerNodeConfig> for NodeDynamicConfig { fn from(sequencer_node_config: &SequencerNodeConfig) -> Self { // TODO(Nadin/Tsabary): consider creating a macro for this. From a435f6fd378c8a71754a713a7f3971c6de337f4f Mon Sep 17 00:00:00 2001 From: einat-starkware Date: Wed, 29 Oct 2025 11:18:25 +0200 Subject: [PATCH 179/313] starknet_os: count blake opcode instances (#9791) --- crates/starknet_os/src/lib.rs | 1 + crates/starknet_os/src/opcode_instances.rs | 127 +++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 crates/starknet_os/src/opcode_instances.rs diff --git a/crates/starknet_os/src/lib.rs b/crates/starknet_os/src/lib.rs index c093ec17abb..f9706937650 100644 --- a/crates/starknet_os/src/lib.rs +++ b/crates/starknet_os/src/lib.rs @@ -5,6 +5,7 @@ pub mod hint_processor; pub mod hints; pub mod io; pub mod metrics; +pub mod opcode_instances; pub mod runner; pub mod syscall_handler_utils; #[cfg(any(test, feature = "testing"))] diff --git a/crates/starknet_os/src/opcode_instances.rs b/crates/starknet_os/src/opcode_instances.rs new file mode 100644 index 00000000000..300c2d77a8e --- /dev/null +++ b/crates/starknet_os/src/opcode_instances.rs @@ -0,0 +1,127 @@ +use cairo_vm::types::relocatable::MaybeRelocatable; +use cairo_vm::vm::runners::cairo_runner::CairoRunner; +use starknet_types_core::felt::Felt; + +fn instruction_to_u128(felt: &Felt) -> Result { + let bytes: [u8; 32] = felt.to_bytes_be(); + assert!(bytes[0..16] == [0; 16], "Instruction should fit in 128 bits"); + let u128_bytes: [u8; 16] = bytes[16..32].try_into().unwrap(); + Ok(u128::from_be_bytes(u128_bytes)) +} + +#[derive(Debug, PartialEq, Eq)] +enum OpcodeExt { + Stone, // 0 + Blake, // 1 + BlakeFinalize, // 2 + QM31Operation, // 3 + Unknown, +} + +pub struct OpcodeInstanceCounts { + pub blake_opcode_count: usize, +} + +/// Decode an encoded instruction (u128) into its components. +fn decode_instruction(mut encoded: u128) -> (bool, bool, bool, OpcodeExt) { + // Skip the 3 offsets (3 * 16 = 48 bits). + encoded >>= 48; + + // Read flags in the correct order (LSB-first). + let _dst_base_fp = (encoded & 1) != 0; + encoded >>= 1; + let _op0_base_fp = (encoded & 1) != 0; + encoded >>= 1; + + let op_1_imm = (encoded & 1) != 0; + encoded >>= 1; + let op_1_base_fp = (encoded & 1) != 0; + encoded >>= 1; + let op_1_base_ap = (encoded & 1) != 0; + encoded >>= 1; + + let res_add = (encoded & 1) != 0; + encoded >>= 1; + let res_mul = (encoded & 1) != 0; + encoded >>= 1; + let pc_update_jump = (encoded & 1) != 0; + encoded >>= 1; + let pc_update_jump_rel = (encoded & 1) != 0; + encoded >>= 1; + let pc_update_jnz = (encoded & 1) != 0; + encoded >>= 1; + let ap_update_add = (encoded & 1) != 0; + encoded >>= 1; + let _ap_update_add_1 = (encoded & 1) != 0; + encoded >>= 1; + let opcode_call = (encoded & 1) != 0; + encoded >>= 1; + let opcode_ret = (encoded & 1) != 0; + encoded >>= 1; + let opcode_assert_eq = (encoded & 1) != 0; + encoded >>= 1; + + let unwanted_flags = op_1_imm + || res_add + || res_mul + || pc_update_jump + || pc_update_jump_rel + || pc_update_jnz + || ap_update_add + || opcode_call + || opcode_ret + || opcode_assert_eq; + + // Remaining bits are the opcode extension. + let opcode_extension = match encoded { + 0 => OpcodeExt::Stone, + 1 => OpcodeExt::Blake, + 2 => OpcodeExt::BlakeFinalize, + 3 => OpcodeExt::QM31Operation, + _ => OpcodeExt::Unknown, + }; + + (unwanted_flags, op_1_base_fp, op_1_base_ap, opcode_extension) +} + +/// Check if a decoded instruction is a Blake opcode. +fn is_blake_opcode( + unwanted_flags: bool, + op_1_base_fp: bool, + op_1_base_ap: bool, + opcode_extension: &OpcodeExt, +) -> bool { + // Blake opcodes have: + // - opcode_extension is Blake or BlakeFinalize + // - no unwanted flags (op_1_imm, res_add, res_mul, etc.) + // - the data we hash is stored on ap or fp exclusively (XOR) + matches!(opcode_extension, OpcodeExt::Blake | OpcodeExt::BlakeFinalize) + && !unwanted_flags + && (op_1_base_fp ^ op_1_base_ap) +} + +/// Count Blake opcodes from the Cairo runner's execution trace. +pub fn get_opcode_instances(runner: &CairoRunner) -> OpcodeInstanceCounts { + let Ok(info) = runner.get_prover_input_info() else { + eprintln!("Failed to get prover input info. Returning zero count."); + return OpcodeInstanceCounts { blake_opcode_count: 0 }; + }; + + let count = info + .relocatable_trace + .iter() + .filter(|entry| { + (|| { + let seg = usize::try_from(entry.pc.segment_index).ok()?; + let value = info.relocatable_memory.get(seg)?.get(entry.pc.offset)?.as_ref()?; + let MaybeRelocatable::Int(felt) = value else { return None }; + let instr = instruction_to_u128(felt).ok()?; + let (unwanted_flags, op1_fp, op1_ap, opcode_ext) = decode_instruction(instr); + Some(is_blake_opcode(unwanted_flags, op1_fp, op1_ap, &opcode_ext)) + })() + .unwrap_or(false) + }) + .count(); + + OpcodeInstanceCounts { blake_opcode_count: count } +} From 3e7abf4fe776df7d7a132b74d3f16f4b1b0cc4a6 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:20:43 +0200 Subject: [PATCH 180/313] apollo_deployments: add replacers (#9775) --- .../deployments/replacer_deployment.json | 18 +++++++++++++ .../deployments/replacer_instance.json | 7 ++++++ .../apollo_deployments/src/config_override.rs | 18 +++++++++---- crates/apollo_deployments/src/lib.rs | 1 + crates/apollo_deployments/src/replacers.rs | 25 +++++++++++++++++++ 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 crates/apollo_deployments/resources/deployments/replacer_deployment.json create mode 100644 crates/apollo_deployments/resources/deployments/replacer_instance.json create mode 100644 crates/apollo_deployments/src/replacers.rs diff --git a/crates/apollo_deployments/resources/deployments/replacer_deployment.json b/crates/apollo_deployments/resources/deployments/replacer_deployment.json new file mode 100644 index 00000000000..ae177bae3a4 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/replacer_deployment.json @@ -0,0 +1,18 @@ +{ + "base_layer_config.starknet_contract_address": "$$$_REPLACE_base_layer_config.starknet_contract_address$$$", + "chain_id": "$$$_REPLACE_chain_id$$$", + "consensus_manager_config.context_config.num_validators": "$$$_REPLACE_consensus_manager_config.context_config.num_validators$$$", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "$$$_REPLACE_consensus_manager_config.network_config.bootstrap_peer_multiaddr$$$", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_REPLACE_consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none$$$", + "eth_fee_token_address": "$$$_REPLACE_eth_fee_token_address$$$", + "l1_provider_config.provider_startup_height_override": "$$$_REPLACE_l1_provider_config.provider_startup_height_override$$$", + "l1_provider_config.provider_startup_height_override.#is_none": "$$$_REPLACE_l1_provider_config.provider_startup_height_override.#is_none$$$", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "$$$_REPLACE_mempool_p2p_config.network_config.bootstrap_peer_multiaddr$$$", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_REPLACE_mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none$$$", + "sierra_compiler_config.audited_libfuncs_only": "$$$_REPLACE_sierra_compiler_config.audited_libfuncs_only$$$", + "starknet_url": "$$$_REPLACE_starknet_url$$$", + "state_sync_config.central_sync_client_config.#is_none": "$$$_REPLACE_state_sync_config.central_sync_client_config.#is_none$$$", + "state_sync_config.network_config.#is_none": "$$$_REPLACE_state_sync_config.network_config.#is_none$$$", + "state_sync_config.p2p_sync_client_config.#is_none": "$$$_REPLACE_state_sync_config.p2p_sync_client_config.#is_none$$$", + "strk_fee_token_address": "$$$_REPLACE_strk_fee_token_address$$$" +} diff --git a/crates/apollo_deployments/resources/deployments/replacer_instance.json b/crates/apollo_deployments/resources/deployments/replacer_instance.json new file mode 100644 index 00000000000..455a4cf47a4 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/replacer_instance.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "$$$_REPLACE_consensus_manager_config.network_config.advertised_multiaddr$$$", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": "$$$_REPLACE_consensus_manager_config.network_config.advertised_multiaddr.#is_none$$$", + "mempool_p2p_config.network_config.advertised_multiaddr": "$$$_REPLACE_mempool_p2p_config.network_config.advertised_multiaddr$$$", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": "$$$_REPLACE_mempool_p2p_config.network_config.advertised_multiaddr.#is_none$$$", + "validator_id": "$$$_REPLACE_validator_id$$$" +} diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index a0f82eed1d9..7408f27c037 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use apollo_config::converters::serialize_optional_comma_separated; use apollo_infra_utils::dumping::serialize_to_file; @@ -12,10 +12,14 @@ use starknet_api::block::BlockNumber; use url::Url; use crate::deployment_definitions::{StateSyncConfig, StateSyncType}; +use crate::replacers::insert_replacer_annotations; #[cfg(test)] use crate::test_utils::FIX_BINARY_NAME; const DEPLOYMENT_FILE_NAME: &str = "deployment_config_override.json"; +const REPLACER_DEPLOYMENT_FILE_NAME: &str = "replacer_deployment.json"; +const REPLACER_INSTANCE_FILE_NAME: &str = "replacer_instance.json"; +const REPLACER_DIR: &str = "crates/apollo_deployments/resources/deployments/"; // Serialization prefixes for p2p configs with_prefix!(consensus_prefix "consensus_manager_config.network_config."); @@ -45,14 +49,18 @@ impl ConfigOverride { let instance_path = deployment_config_override_dir.join(format!("{instance_name}.json")); if create { + let deployment_data = to_value(&self.deployment_config_override).unwrap(); + serialize_to_file(&deployment_data, deployment_path.to_str().unwrap()); serialize_to_file( - &to_value(&self.deployment_config_override).unwrap(), - deployment_path.to_str().unwrap(), + &insert_replacer_annotations(deployment_data), + PathBuf::from(REPLACER_DIR).join(REPLACER_DEPLOYMENT_FILE_NAME).to_str().unwrap(), ); + let instance_data = to_value(&self.instance_config_override).unwrap(); + serialize_to_file(&instance_data, instance_path.to_str().unwrap()); serialize_to_file( - &to_value(&self.instance_config_override).unwrap(), - instance_path.to_str().unwrap(), + &insert_replacer_annotations(instance_data), + PathBuf::from(REPLACER_DIR).join(REPLACER_INSTANCE_FILE_NAME).to_str().unwrap(), ); } diff --git a/crates/apollo_deployments/src/lib.rs b/crates/apollo_deployments/src/lib.rs index ac8a41f1c68..245b6633550 100644 --- a/crates/apollo_deployments/src/lib.rs +++ b/crates/apollo_deployments/src/lib.rs @@ -5,6 +5,7 @@ pub(crate) mod deployment; pub mod deployment_definitions; pub mod deployments; pub(crate) mod k8s; +pub(crate) mod replacers; pub(crate) mod scale_policy; pub mod service; #[cfg(test)] diff --git a/crates/apollo_deployments/src/replacers.rs b/crates/apollo_deployments/src/replacers.rs new file mode 100644 index 00000000000..3d21157b312 --- /dev/null +++ b/crates/apollo_deployments/src/replacers.rs @@ -0,0 +1,25 @@ +use apollo_infra_utils::template::Template; +use serde_json::Value; + +const REPLACER_FORMAT: &str = "$$$_REPLACE_{}$$$"; + +/// Given a flattened JSON object, overwrite each `key`'s value with `format_key(key)`. +pub(crate) fn insert_replacer_annotations(mut json: Value) -> Value { + // Assert it’s an object (serde_json::Value::Object) + assert!(json.is_object(), "expected a JSON object, got: {}", json); + + // SAFETY: we just asserted it's an object. + let map = json.as_object_mut().unwrap(); + + // Collect keys to avoid mutable borrow issues while iterating. + let keys: Vec = map.keys().cloned().collect(); + for key in keys { + map.insert(key.clone(), Value::String(format_key(key))); + } + + json +} + +fn format_key(key: String) -> String { + Template::new(REPLACER_FORMAT).format(&[&key]) +} From c356483f8437a0d3861e1186de74b6a1961d1b2c Mon Sep 17 00:00:00 2001 From: einat-starkware Date: Wed, 29 Oct 2025 11:32:27 +0200 Subject: [PATCH 181/313] starknet_os: check estimation vs actual blake count (#9793) --- .../compiled_class/compiled_class_test.rs | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/crates/starknet_os/src/hints/hint_implementation/compiled_class/compiled_class_test.rs b/crates/starknet_os/src/hints/hint_implementation/compiled_class/compiled_class_test.rs index c248e438dda..2847340ffc4 100644 --- a/crates/starknet_os/src/hints/hint_implementation/compiled_class/compiled_class_test.rs +++ b/crates/starknet_os/src/hints/hint_implementation/compiled_class/compiled_class_test.rs @@ -29,6 +29,7 @@ use starknet_types_core::felt::Felt; use crate::hints::hint_implementation::compiled_class::utils::create_bytecode_segment_structure; use crate::hints::vars::Const; +use crate::opcode_instances::{get_opcode_instances, OpcodeInstanceCounts}; use crate::test_utils::cairo_runner::{ initialize_cairo_runner, run_cairo_0_entrypoint, @@ -68,6 +69,7 @@ const EXPECTED_BUILTIN_USAGE_PARTIAL_CONTRACT_V2_HASH: expect_test::Expect = const EXPECTED_N_STEPS_PARTIAL_CONTRACT_V2_HASH: Expect = expect!["41697"]; // Allowed margin between estimated and actual execution resources. const ALLOWED_MARGIN_BLAKE_N_STEPS: usize = 267; +const ALLOWED_MARGIN_BLAKE_OPCODE_COUNT: usize = 4; /// Specifies the expected inputs and outputs for testing a class hash version. /// Includes entrypoint, bytecode, and expected runtime behavior. @@ -88,12 +90,20 @@ trait HashVersionTestSpec { fn expected_hash(&self) -> Expect; /// The allowed margin for the number of steps. fn allowed_margin_n_steps(&self) -> usize; + /// The allowed margin for the number of Blake opcodes. + fn allowed_margin_blake_opcode_count(&self) -> usize; /// Estimates the execution resources for the compiled class hash function. fn estimate_execution_resources( &self, bytecode_segment_felt_sizes: &NestedFeltCounts, entry_points_by_type: &EntryPointsByType, ) -> ExecutionResources; + /// Estimates the number of Blake opcodes used for the compiled class hash function. + fn estimated_blake_opcode_count( + &self, + bytecode_segment_felt_sizes: &NestedFeltCounts, + entry_points_by_type: &EntryPointsByType, + ) -> usize; } impl HashVersionTestSpec for HashVersion { @@ -156,6 +166,12 @@ impl HashVersionTestSpec for HashVersion { HashVersion::V2 => ALLOWED_MARGIN_BLAKE_N_STEPS, } } + fn allowed_margin_blake_opcode_count(&self) -> usize { + match self { + HashVersion::V1 => 0, + HashVersion::V2 => ALLOWED_MARGIN_BLAKE_OPCODE_COUNT, + } + } fn estimate_execution_resources( &self, bytecode_segment_felt_sizes: &NestedFeltCounts, @@ -178,6 +194,22 @@ impl HashVersionTestSpec for HashVersion { } } } + fn estimated_blake_opcode_count( + &self, + bytecode_segment_felt_sizes: &NestedFeltCounts, + entry_points_by_type: &EntryPointsByType, + ) -> usize { + match self { + HashVersion::V1 => 0, + HashVersion::V2 => { + CasmV2HashResourceEstimate::estimated_resources_of_compiled_class_hash( + bytecode_segment_felt_sizes, + entry_points_by_type, + ) + .blake_count() + } + } + } } /// Runs the compiled class hash entry point for the given contract class, @@ -187,11 +219,11 @@ fn run_compiled_class_hash_entry_point( contract_class: &CasmContractClass, load_full_contract: bool, hash_version: &HashVersion, -) -> (ExecutionResources, Felt) { +) -> (ExecutionResources, OpcodeInstanceCounts, Felt) { // Set up the entry point runner configuration. let runner_config = EntryPointRunnerConfig { layout: LayoutName::all_cairo, - trace_enabled: false, + trace_enabled: true, verify_secure: false, proof_mode: false, add_main_prefix_to_entrypoint: false, // Set to false since we're using full path. @@ -256,7 +288,7 @@ fn run_compiled_class_hash_entry_point( // Get the actual execution resources, and compare with expected values. let actual_execution_resources = runner.get_execution_resources().unwrap(); - + let opcode_instances = get_opcode_instances(&runner); // Get the hash result from the explicit return values. let EndpointArg::Value(ValueArg::Single(MaybeRelocatable::Int(hash_computed_by_cairo))) = explicit_return_values[0] @@ -264,7 +296,7 @@ fn run_compiled_class_hash_entry_point( panic!("Expected a single felt return value"); }; - (actual_execution_resources, hash_computed_by_cairo) + (actual_execution_resources, opcode_instances, hash_computed_by_cairo) } #[rstest] @@ -280,7 +312,7 @@ fn test_compiled_class_hash( _ => panic!("Expected ContractClass::V1"), }; // Run the compiled class hash entry point. - let (actual_execution_resources, hash_computed_by_cairo) = + let (actual_execution_resources, _, hash_computed_by_cairo) = run_compiled_class_hash_entry_point(&contract_class, load_full_contract, &hash_version); // Format builtin usage statistics for comparison with expected values. @@ -376,7 +408,7 @@ fn compare_estimated_vs_actual_casm_hash_resources( hash_version: &HashVersion, ) { // Run the compiled class hash entry point with full contract loading. - let (actual_execution_resources, _) = + let (actual_execution_resources, actual_opcode_instances, _) = run_compiled_class_hash_entry_point(&contract_class, true, hash_version); let bytecode_segments = NestedFeltCounts::new( @@ -387,7 +419,7 @@ fn compare_estimated_vs_actual_casm_hash_resources( // Estimate resources. let execution_resources_estimation = hash_version.estimate_execution_resources( &bytecode_segments, - &contract_class.entry_points_by_type.into(), + &contract_class.entry_points_by_type.clone().into(), ); // Compare n_steps. @@ -406,4 +438,18 @@ fn compare_estimated_vs_actual_casm_hash_resources( actual_execution_resources.filter_unused_builtins().builtin_instance_counter, "{contract_name}: Estimated builtins do not match actual builtins" ); + + // Compare Blake opcode count. + let estimated_blake_opcode_count = hash_version.estimated_blake_opcode_count( + &bytecode_segments, + &contract_class.entry_points_by_type.into(), + ); + let blake_opcode_count_margin = + estimated_blake_opcode_count.abs_diff(actual_opcode_instances.blake_opcode_count); + let allowed_blake_opcode_count_margin = hash_version.allowed_margin_blake_opcode_count(); + assert!( + blake_opcode_count_margin <= allowed_blake_opcode_count_margin, + "{contract_name}: Estimated Blake opcode count differs from actual by more than \ + {allowed_blake_opcode_count_margin}. Margin: {blake_opcode_count_margin}" + ); } From 7cdc39f72ab02e30889c65357be65259ec90fa77 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:09:36 +0200 Subject: [PATCH 182/313] apollo_deployments: improve replacer strings (#9837) --- .../deployments/replacer_deployment.json | 32 +++++++++---------- .../deployments/replacer_instance.json | 10 +++--- crates/apollo_deployments/src/replacers.rs | 10 ++---- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/crates/apollo_deployments/resources/deployments/replacer_deployment.json b/crates/apollo_deployments/resources/deployments/replacer_deployment.json index ae177bae3a4..372b106ea07 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_deployment.json +++ b/crates/apollo_deployments/resources/deployments/replacer_deployment.json @@ -1,18 +1,18 @@ { - "base_layer_config.starknet_contract_address": "$$$_REPLACE_base_layer_config.starknet_contract_address$$$", - "chain_id": "$$$_REPLACE_chain_id$$$", - "consensus_manager_config.context_config.num_validators": "$$$_REPLACE_consensus_manager_config.context_config.num_validators$$$", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "$$$_REPLACE_consensus_manager_config.network_config.bootstrap_peer_multiaddr$$$", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_REPLACE_consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none$$$", - "eth_fee_token_address": "$$$_REPLACE_eth_fee_token_address$$$", - "l1_provider_config.provider_startup_height_override": "$$$_REPLACE_l1_provider_config.provider_startup_height_override$$$", - "l1_provider_config.provider_startup_height_override.#is_none": "$$$_REPLACE_l1_provider_config.provider_startup_height_override.#is_none$$$", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "$$$_REPLACE_mempool_p2p_config.network_config.bootstrap_peer_multiaddr$$$", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_REPLACE_mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none$$$", - "sierra_compiler_config.audited_libfuncs_only": "$$$_REPLACE_sierra_compiler_config.audited_libfuncs_only$$$", - "starknet_url": "$$$_REPLACE_starknet_url$$$", - "state_sync_config.central_sync_client_config.#is_none": "$$$_REPLACE_state_sync_config.central_sync_client_config.#is_none$$$", - "state_sync_config.network_config.#is_none": "$$$_REPLACE_state_sync_config.network_config.#is_none$$$", - "state_sync_config.p2p_sync_client_config.#is_none": "$$$_REPLACE_state_sync_config.p2p_sync_client_config.#is_none$$$", - "strk_fee_token_address": "$$$_REPLACE_strk_fee_token_address$$$" + "base_layer_config.starknet_contract_address": "$$$_BASE_LAYER_CONFIG-STARKNET_CONTRACT_ADDRESS_$$$", + "chain_id": "$$$_CHAIN_ID_$$$", + "consensus_manager_config.context_config.num_validators": "$$$_CONSENSUS_MANAGER_CONFIG-CONTEXT_CONFIG-NUM_VALIDATORS_$$$", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", + "eth_fee_token_address": "$$$_ETH_FEE_TOKEN_ADDRESS_$$$", + "l1_provider_config.provider_startup_height_override": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE_$$$", + "l1_provider_config.provider_startup_height_override.#is_none": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE-IS_NONE_$$$", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", + "sierra_compiler_config.audited_libfuncs_only": "$$$_SIERRA_COMPILER_CONFIG-AUDITED_LIBFUNCS_ONLY_$$$", + "starknet_url": "$$$_STARKNET_URL_$$$", + "state_sync_config.central_sync_client_config.#is_none": "$$$_STATE_SYNC_CONFIG-CENTRAL_SYNC_CLIENT_CONFIG-IS_NONE_$$$", + "state_sync_config.network_config.#is_none": "$$$_STATE_SYNC_CONFIG-NETWORK_CONFIG-IS_NONE_$$$", + "state_sync_config.p2p_sync_client_config.#is_none": "$$$_STATE_SYNC_CONFIG-P2P_SYNC_CLIENT_CONFIG-IS_NONE_$$$", + "strk_fee_token_address": "$$$_STRK_FEE_TOKEN_ADDRESS_$$$" } diff --git a/crates/apollo_deployments/resources/deployments/replacer_instance.json b/crates/apollo_deployments/resources/deployments/replacer_instance.json index 455a4cf47a4..93e4ca688d2 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_instance.json +++ b/crates/apollo_deployments/resources/deployments/replacer_instance.json @@ -1,7 +1,7 @@ { - "consensus_manager_config.network_config.advertised_multiaddr": "$$$_REPLACE_consensus_manager_config.network_config.advertised_multiaddr$$$", - "consensus_manager_config.network_config.advertised_multiaddr.#is_none": "$$$_REPLACE_consensus_manager_config.network_config.advertised_multiaddr.#is_none$$$", - "mempool_p2p_config.network_config.advertised_multiaddr": "$$$_REPLACE_mempool_p2p_config.network_config.advertised_multiaddr$$$", - "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": "$$$_REPLACE_mempool_p2p_config.network_config.advertised_multiaddr.#is_none$$$", - "validator_id": "$$$_REPLACE_validator_id$$$" + "consensus_manager_config.network_config.advertised_multiaddr": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR_$$$", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR-IS_NONE_$$$", + "mempool_p2p_config.network_config.advertised_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR_$$$", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR-IS_NONE_$$$", + "validator_id": "$$$_VALIDATOR_ID_$$$" } diff --git a/crates/apollo_deployments/src/replacers.rs b/crates/apollo_deployments/src/replacers.rs index 3d21157b312..dee53f42117 100644 --- a/crates/apollo_deployments/src/replacers.rs +++ b/crates/apollo_deployments/src/replacers.rs @@ -1,15 +1,11 @@ use apollo_infra_utils::template::Template; use serde_json::Value; -const REPLACER_FORMAT: &str = "$$$_REPLACE_{}$$$"; +const REPLACER_FORMAT: &str = "$$$_{}_$$$"; /// Given a flattened JSON object, overwrite each `key`'s value with `format_key(key)`. pub(crate) fn insert_replacer_annotations(mut json: Value) -> Value { - // Assert it’s an object (serde_json::Value::Object) - assert!(json.is_object(), "expected a JSON object, got: {}", json); - - // SAFETY: we just asserted it's an object. - let map = json.as_object_mut().unwrap(); + let map = json.as_object_mut().expect("Should be a JSON object"); // Collect keys to avoid mutable borrow issues while iterating. let keys: Vec = map.keys().cloned().collect(); @@ -21,5 +17,5 @@ pub(crate) fn insert_replacer_annotations(mut json: Value) -> Value { } fn format_key(key: String) -> String { - Template::new(REPLACER_FORMAT).format(&[&key]) + Template::new(REPLACER_FORMAT).format(&[&key]).to_uppercase().replace('.', "-").replace('#', "") } From b3511f03f1942e8266684729242b05b4b0bd9a58 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:21:27 +0200 Subject: [PATCH 183/313] ci: run benchmark command (#9636) --- crates/bench_tools/Cargo.toml | 1 + crates/bench_tools/src/gcs.rs | 2 +- crates/bench_tools/src/lib.rs | 1 + crates/bench_tools/src/main.rs | 14 +++- crates/bench_tools/src/runner.rs | 107 +++++++++++++++++++++++++++++++ crates/bench_tools/src/utils.rs | 1 - 6 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 crates/bench_tools/src/runner.rs diff --git a/crates/bench_tools/Cargo.toml b/crates/bench_tools/Cargo.toml index b8b92de0081..2654db5e7a2 100644 --- a/crates/bench_tools/Cargo.toml +++ b/crates/bench_tools/Cargo.toml @@ -10,6 +10,7 @@ workspace = true clap = { workspace = true, features = ["derive"] } criterion.workspace = true serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true [dev-dependencies] apollo_infra_utils.workspace = true diff --git a/crates/bench_tools/src/gcs.rs b/crates/bench_tools/src/gcs.rs index 659580e62ab..4cc61e95cf2 100644 --- a/crates/bench_tools/src/gcs.rs +++ b/crates/bench_tools/src/gcs.rs @@ -57,7 +57,7 @@ pub fn download_inputs(benchmark_name: &str, local_input_dir: &Path) { let output = Command::new("gcloud") .args(["storage", "cp", "-r", &source, &dest]) .output() - .expect("Failed to cp inputs from GCS"); + .unwrap_or_else(|e| panic!("Failed to cp inputs from GCS: {}", e)); if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr); diff --git a/crates/bench_tools/src/lib.rs b/crates/bench_tools/src/lib.rs index c6a448e090b..85dca4a6c0f 100644 --- a/crates/bench_tools/src/lib.rs +++ b/crates/bench_tools/src/lib.rs @@ -3,6 +3,7 @@ pub(crate) mod benches; pub mod gcs; #[cfg(test)] pub mod gcs_test; +pub mod runner; #[cfg(test)] pub mod test_utils; pub mod types; diff --git a/crates/bench_tools/src/main.rs b/crates/bench_tools/src/main.rs index 6fa04d8a143..bda64a7e22e 100644 --- a/crates/bench_tools/src/main.rs +++ b/crates/bench_tools/src/main.rs @@ -25,6 +25,10 @@ enum Commands { /// Output directory for results. #[arg(short, long)] out: String, + /// Optional: Local directory containing input files. If not provided, inputs will be + /// downloaded from GCS for benchmarks that require them. + #[arg(long)] + input_dir: Option, }, /// List benchmarks for a package. List { @@ -46,8 +50,14 @@ enum Commands { fn main() { let cli = Cli::parse(); match cli.command { - Commands::Run { package: _, out: _ } => { - unimplemented!() + Commands::Run { package, out, input_dir } => { + let benchmarks = find_benchmarks_by_package(&package); + + if benchmarks.is_empty() { + panic!("No benchmarks found for package: {}", package); + } + + bench_tools::runner::run_benchmarks(&benchmarks, input_dir.as_deref(), &out); } Commands::List { package } => match package { Some(package_name) => { diff --git a/crates/bench_tools/src/runner.rs b/crates/bench_tools/src/runner.rs new file mode 100644 index 00000000000..be89ee27453 --- /dev/null +++ b/crates/bench_tools/src/runner.rs @@ -0,0 +1,107 @@ +use std::fs; +use std::path::PathBuf; + +use crate::gcs; +use crate::types::benchmark_config::BenchmarkConfig; +use crate::utils::copy_dir_contents; + +/// Prepares inputs for a benchmark. +/// If the benchmark needs inputs and a local input directory is provided, +/// it copies the contents from the local directory to the expected input location. +/// If the benchmark needs inputs and no local input directory is provided, +/// it downloads the inputs from GCS. +fn prepare_inputs(bench: &BenchmarkConfig, input_dir: Option<&str>) { + if !bench.needs_inputs() { + return; + } + + let benchmark_input_dir = PathBuf::from(bench.input_dir.unwrap()); + + // Create the input directory if it doesn't exist. + fs::create_dir_all(&benchmark_input_dir).unwrap_or_else(|e| { + panic!("Failed to create directory {}: {}", benchmark_input_dir.display(), e) + }); + + if let Some(local_dir) = input_dir { + let local_path = PathBuf::from(local_dir); + if !local_path.exists() { + panic!("Input directory does not exist: {}", local_dir); + } + + // Copy local directory contents to the benchmark input directory. + copy_dir_contents(&local_path, &benchmark_input_dir); + + println!("Copied inputs from {} to {}", local_dir, benchmark_input_dir.display()); + } else { + gcs::download_inputs(bench.name, &benchmark_input_dir); + if !benchmark_input_dir.exists() { + panic!( + "Failed to download inputs for {}: {}", + bench.name, + benchmark_input_dir.display() + ); + } + } +} + +/// Runs a single benchmark and panic if it fails. +fn run_single_benchmark(bench: &BenchmarkConfig) { + println!("Running: {}", bench.name); + + let output = std::process::Command::new("cargo") + .args(bench.cmd_args) + .output() + .unwrap_or_else(|e| panic!("Failed to execute {}: {}", bench.name, e)); + + if !output.status.success() { + panic!("\nBenchmark {} failed:\n{}", bench.name, String::from_utf8_lossy(&output.stderr)); + } +} + +/// Collects benchmark results from criterion output and saves them to the output directory. +fn save_benchmark_results(_bench: &BenchmarkConfig, output_dir: &str) { + let criterion_base = PathBuf::from("target/criterion"); + let Ok(entries) = fs::read_dir(&criterion_base) else { return }; + + // Collect all estimates files. + for entry in entries.flatten() { + let path = entry.path(); + if !path.is_dir() { + continue; + } + + // Save estimates file. + let estimates_path = path.join("new/estimates.json"); + if let Ok(data) = fs::read_to_string(&estimates_path) { + if let Ok(json) = serde_json::from_str::(&data) { + if let Ok(pretty) = serde_json::to_string_pretty(&json) { + let bench_name = path.file_name().unwrap().to_string_lossy(); + let dest = + PathBuf::from(output_dir).join(format!("{}_estimates.json", bench_name)); + if fs::write(&dest, pretty).is_ok() { + println!("Saved results: {}", dest.display()); + } + } + } + } + } +} + +/// Runs benchmarks for a given package, handling input downloads if needed. +pub fn run_benchmarks(benchmarks: &[&BenchmarkConfig], input_dir: Option<&str>, output_dir: &str) { + // Prepare inputs. + for bench in benchmarks { + prepare_inputs(bench, input_dir); + } + + // Create output directory. + fs::create_dir_all(output_dir).unwrap_or_else(|e| panic!("Failed to create output dir: {}", e)); + + // Run benchmarks. + for bench in benchmarks { + run_single_benchmark(bench); + save_benchmark_results(bench, output_dir); + } + + println!("\n✓ All benchmarks completed! Results saved to: {}", output_dir); +} diff --git a/crates/bench_tools/src/utils.rs b/crates/bench_tools/src/utils.rs index 50f9fa0cd33..43b79528f27 100644 --- a/crates/bench_tools/src/utils.rs +++ b/crates/bench_tools/src/utils.rs @@ -14,7 +14,6 @@ use std::path::Path; /// - Reading the source directory /// - Copying files /// - Accessing file metadata -#[allow(dead_code)] pub(crate) fn copy_dir_contents(src: &Path, dst: &Path) { // Ensure destination exists. fs::create_dir_all(dst) From 92589bae04f878b6aae5b7640a94e047908d44ca Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Wed, 29 Oct 2025 14:10:31 +0200 Subject: [PATCH 184/313] bench_tools: add bench tools to allowed scopes (#9696) --- commitlint.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/commitlint.config.js b/commitlint.config.js index c6f62eae38e..95a9473a64e 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -75,6 +75,7 @@ const AllowedScopes = ['apollo_batcher', 'apollo_test_utils', 'apollo_time', 'batcher', + 'bench_tools', 'blockifier', 'blockifier_reexecution', 'blockifier_test_utils', From e8f886a02b3fc76507ad1e20b6fc2b2cca720946 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Wed, 29 Oct 2025 14:52:43 +0200 Subject: [PATCH 185/313] apollo_deployments: add replacers per each service application config (#9838) --- .../services/consolidated/node_replacer.json | 156 +++++++++++++++++ .../distributed/batcher_replacer.json | 134 +++++++++++++++ .../distributed/class_manager_replacer.json | 122 ++++++++++++++ .../consensus_manager_replacer.json | 142 ++++++++++++++++ .../distributed/gateway_replacer.json | 134 +++++++++++++++ .../distributed/http_server_replacer.json | 118 +++++++++++++ .../services/distributed/l1_replacer.json | 136 +++++++++++++++ .../distributed/mempool_replacer.json | 132 +++++++++++++++ .../distributed/sierra_compiler_replacer.json | 116 +++++++++++++ .../signature_manager_replacer.json | 116 +++++++++++++ .../distributed/state_sync_replacer.json | 122 ++++++++++++++ .../services/hybrid/core_replacer.json | 158 ++++++++++++++++++ .../services/hybrid/gateway_replacer.json | 134 +++++++++++++++ .../services/hybrid/http_server_replacer.json | 118 +++++++++++++ .../services/hybrid/l1_replacer.json | 136 +++++++++++++++ .../services/hybrid/mempool_replacer.json | 132 +++++++++++++++ .../hybrid/sierra_compiler_replacer.json | 116 +++++++++++++ .../apollo_deployments/src/config_override.rs | 4 +- crates/apollo_deployments/src/replacers.rs | 16 +- crates/apollo_deployments/src/service.rs | 46 ++++- .../src/component_execution_config.rs | 2 +- 21 files changed, 2282 insertions(+), 8 deletions(-) create mode 100644 crates/apollo_deployments/resources/services/consolidated/node_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/batcher_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/class_manager_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/consensus_manager_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/gateway_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/http_server_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/l1_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/mempool_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/sierra_compiler_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/signature_manager_replacer.json create mode 100644 crates/apollo_deployments/resources/services/distributed/state_sync_replacer.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/core_replacer.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/gateway_replacer.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/http_server_replacer.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/l1_replacer.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/mempool_replacer.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/sierra_compiler_replacer.json diff --git a/crates/apollo_deployments/resources/services/consolidated/node_replacer.json b/crates/apollo_deployments/resources/services/consolidated/node_replacer.json new file mode 100644 index 00000000000..710fcbff460 --- /dev/null +++ b/crates/apollo_deployments/resources/services/consolidated/node_replacer.json @@ -0,0 +1,156 @@ +{ + "base_layer_config.#is_none": false, + "batcher_config.#is_none": false, + "class_manager_config.#is_none": false, + "components.batcher.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": false, + "components.batcher.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.batcher.local_server_config.inbound_requests_channel_capacity": 1024, + "components.batcher.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.batcher.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": false, + "components.class_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "localhost", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Enabled", + "components.gateway.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": false, + "components.gateway.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.gateway.local_server_config.inbound_requests_channel_capacity": 1024, + "components.gateway.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.gateway.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Enabled", + "components.l1_endpoint_monitor.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": false, + "components.l1_endpoint_monitor.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": false, + "components.l1_gas_price_provider.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Enabled", + "components.l1_provider.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": false, + "components.l1_provider.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Enabled", + "components.mempool.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": false, + "components.mempool.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.mempool.local_server_config.inbound_requests_channel_capacity": 1024, + "components.mempool.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.mempool.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": false, + "components.mempool_p2p.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.inbound_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": false, + "components.sierra_compiler.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.inbound_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": false, + "components.signature_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": false, + "components.state_sync.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.inbound_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": false, + "gateway_config.#is_none": false, + "http_server_config.#is_none": false, + "l1_endpoint_monitor_config.#is_none": false, + "l1_gas_price_provider_config.#is_none": false, + "l1_gas_price_scraper_config.#is_none": false, + "l1_provider_config.#is_none": false, + "l1_scraper_config.#is_none": false, + "mempool_config.#is_none": false, + "mempool_p2p_config.#is_none": false, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": false, + "state_sync_config.#is_none": false +} diff --git a/crates/apollo_deployments/resources/services/distributed/batcher_replacer.json b/crates/apollo_deployments/resources/services/distributed/batcher_replacer.json new file mode 100644 index 00000000000..f61159e66c4 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/batcher_replacer.json @@ -0,0 +1,134 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": false, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": false, + "components.batcher.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.batcher.local_server_config.inbound_requests_channel_capacity": 1024, + "components.batcher.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.batcher.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.batcher.max_concurrency": 128, + "components.batcher.port": "$$$_COMPONENTS-BATCHER-PORT_$$$", + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "$$$_COMPONENTS-BATCHER-URL_$$$", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": false, + "components.class_manager.remote_client_config.attempts_per_log": 10, + "components.class_manager.remote_client_config.idle_connections": 10, + "components.class_manager.remote_client_config.idle_timeout_ms": 30000, + "components.class_manager.remote_client_config.initial_retry_delay_ms": 1, + "components.class_manager.remote_client_config.max_retry_interval_ms": 1000, + "components.class_manager.remote_client_config.retries": 150, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Remote", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": "$$$_COMPONENTS-L1_PROVIDER-PORT_$$$", + "components.l1_provider.remote_client_config.#is_none": false, + "components.l1_provider.remote_client_config.attempts_per_log": 10, + "components.l1_provider.remote_client_config.idle_connections": 10, + "components.l1_provider.remote_client_config.idle_timeout_ms": 30000, + "components.l1_provider.remote_client_config.initial_retry_delay_ms": 1, + "components.l1_provider.remote_client_config.max_retry_interval_ms": 1000, + "components.l1_provider.remote_client_config.retries": 0, + "components.l1_provider.url": "$$$_COMPONENTS-L1_PROVIDER-URL_$$$", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Remote", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": "$$$_COMPONENTS-MEMPOOL-PORT_$$$", + "components.mempool.remote_client_config.#is_none": false, + "components.mempool.remote_client_config.attempts_per_log": 10, + "components.mempool.remote_client_config.idle_connections": 10, + "components.mempool.remote_client_config.idle_timeout_ms": 30000, + "components.mempool.remote_client_config.initial_retry_delay_ms": 1, + "components.mempool.remote_client_config.max_retry_interval_ms": 1000, + "components.mempool.remote_client_config.retries": 150, + "components.mempool.url": "$$$_COMPONENTS-MEMPOOL-URL_$$$", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/class_manager_replacer.json b/crates/apollo_deployments/resources/services/distributed/class_manager_replacer.json new file mode 100644 index 00000000000..2c5f42c754e --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/class_manager_replacer.json @@ -0,0 +1,122 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": false, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": false, + "components.class_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Remote", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": "$$$_COMPONENTS-SIERRA_COMPILER-PORT_$$$", + "components.sierra_compiler.remote_client_config.#is_none": false, + "components.sierra_compiler.remote_client_config.attempts_per_log": 10, + "components.sierra_compiler.remote_client_config.idle_connections": 0, + "components.sierra_compiler.remote_client_config.idle_timeout_ms": 30000, + "components.sierra_compiler.remote_client_config.initial_retry_delay_ms": 1, + "components.sierra_compiler.remote_client_config.max_retry_interval_ms": 1000, + "components.sierra_compiler.remote_client_config.retries": 150, + "components.sierra_compiler.url": "$$$_COMPONENTS-SIERRA_COMPILER-URL_$$$", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/consensus_manager_replacer.json b/crates/apollo_deployments/resources/services/distributed/consensus_manager_replacer.json new file mode 100644 index 00000000000..60ec738a967 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/consensus_manager_replacer.json @@ -0,0 +1,142 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Remote", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": "$$$_COMPONENTS-BATCHER-PORT_$$$", + "components.batcher.remote_client_config.#is_none": false, + "components.batcher.remote_client_config.attempts_per_log": 10, + "components.batcher.remote_client_config.idle_connections": 10, + "components.batcher.remote_client_config.idle_timeout_ms": 30000, + "components.batcher.remote_client_config.initial_retry_delay_ms": 1, + "components.batcher.remote_client_config.max_retry_interval_ms": 1000, + "components.batcher.remote_client_config.retries": 150, + "components.batcher.url": "$$$_COMPONENTS-BATCHER-URL_$$$", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": false, + "components.class_manager.remote_client_config.attempts_per_log": 10, + "components.class_manager.remote_client_config.idle_connections": 10, + "components.class_manager.remote_client_config.idle_timeout_ms": 30000, + "components.class_manager.remote_client_config.initial_retry_delay_ms": 1, + "components.class_manager.remote_client_config.max_retry_interval_ms": 1000, + "components.class_manager.remote_client_config.retries": 150, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Enabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Remote", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": "$$$_COMPONENTS-L1_GAS_PRICE_PROVIDER-PORT_$$$", + "components.l1_gas_price_provider.remote_client_config.#is_none": false, + "components.l1_gas_price_provider.remote_client_config.attempts_per_log": 10, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 10, + "components.l1_gas_price_provider.remote_client_config.idle_timeout_ms": 30000, + "components.l1_gas_price_provider.remote_client_config.initial_retry_delay_ms": 1, + "components.l1_gas_price_provider.remote_client_config.max_retry_interval_ms": 1000, + "components.l1_gas_price_provider.remote_client_config.retries": 0, + "components.l1_gas_price_provider.url": "$$$_COMPONENTS-L1_GAS_PRICE_PROVIDER-URL_$$$", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Remote", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": "$$$_COMPONENTS-SIGNATURE_MANAGER-PORT_$$$", + "components.signature_manager.remote_client_config.#is_none": false, + "components.signature_manager.remote_client_config.attempts_per_log": 10, + "components.signature_manager.remote_client_config.idle_connections": 10, + "components.signature_manager.remote_client_config.idle_timeout_ms": 30000, + "components.signature_manager.remote_client_config.initial_retry_delay_ms": 1, + "components.signature_manager.remote_client_config.max_retry_interval_ms": 1000, + "components.signature_manager.remote_client_config.retries": 150, + "components.signature_manager.url": "$$$_COMPONENTS-SIGNATURE_MANAGER-URL_$$$", + "components.state_sync.execution_mode": "Remote", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": "$$$_COMPONENTS-STATE_SYNC-PORT_$$$", + "components.state_sync.remote_client_config.#is_none": false, + "components.state_sync.remote_client_config.attempts_per_log": 10, + "components.state_sync.remote_client_config.idle_connections": 10, + "components.state_sync.remote_client_config.idle_timeout_ms": 30000, + "components.state_sync.remote_client_config.initial_retry_delay_ms": 1, + "components.state_sync.remote_client_config.max_retry_interval_ms": 1000, + "components.state_sync.remote_client_config.retries": 150, + "components.state_sync.url": "$$$_COMPONENTS-STATE_SYNC-URL_$$$", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": false, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/gateway_replacer.json b/crates/apollo_deployments/resources/services/distributed/gateway_replacer.json new file mode 100644 index 00000000000..22ae14a4d9c --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/gateway_replacer.json @@ -0,0 +1,134 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": false, + "components.class_manager.remote_client_config.attempts_per_log": 10, + "components.class_manager.remote_client_config.idle_connections": 10, + "components.class_manager.remote_client_config.idle_timeout_ms": 30000, + "components.class_manager.remote_client_config.initial_retry_delay_ms": 1, + "components.class_manager.remote_client_config.max_retry_interval_ms": 1000, + "components.class_manager.remote_client_config.retries": 150, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": false, + "components.gateway.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.gateway.local_server_config.inbound_requests_channel_capacity": 1024, + "components.gateway.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.gateway.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.gateway.max_concurrency": 128, + "components.gateway.port": "$$$_COMPONENTS-GATEWAY-PORT_$$$", + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "$$$_COMPONENTS-GATEWAY-URL_$$$", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Remote", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": "$$$_COMPONENTS-MEMPOOL-PORT_$$$", + "components.mempool.remote_client_config.#is_none": false, + "components.mempool.remote_client_config.attempts_per_log": 10, + "components.mempool.remote_client_config.idle_connections": 10, + "components.mempool.remote_client_config.idle_timeout_ms": 30000, + "components.mempool.remote_client_config.initial_retry_delay_ms": 1, + "components.mempool.remote_client_config.max_retry_interval_ms": 1000, + "components.mempool.remote_client_config.retries": 150, + "components.mempool.url": "$$$_COMPONENTS-MEMPOOL-URL_$$$", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Remote", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": "$$$_COMPONENTS-STATE_SYNC-PORT_$$$", + "components.state_sync.remote_client_config.#is_none": false, + "components.state_sync.remote_client_config.attempts_per_log": 10, + "components.state_sync.remote_client_config.idle_connections": 10, + "components.state_sync.remote_client_config.idle_timeout_ms": 30000, + "components.state_sync.remote_client_config.initial_retry_delay_ms": 1, + "components.state_sync.remote_client_config.max_retry_interval_ms": 1000, + "components.state_sync.remote_client_config.retries": 150, + "components.state_sync.url": "$$$_COMPONENTS-STATE_SYNC-URL_$$$", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": false, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/http_server_replacer.json b/crates/apollo_deployments/resources/services/distributed/http_server_replacer.json new file mode 100644 index 00000000000..c54815a8863 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/http_server_replacer.json @@ -0,0 +1,118 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "localhost", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Remote", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": "$$$_COMPONENTS-GATEWAY-PORT_$$$", + "components.gateway.remote_client_config.#is_none": false, + "components.gateway.remote_client_config.attempts_per_log": 10, + "components.gateway.remote_client_config.idle_connections": 0, + "components.gateway.remote_client_config.idle_timeout_ms": 30000, + "components.gateway.remote_client_config.initial_retry_delay_ms": 1, + "components.gateway.remote_client_config.max_retry_interval_ms": 1000, + "components.gateway.remote_client_config.retries": 150, + "components.gateway.url": "$$$_COMPONENTS-GATEWAY-URL_$$$", + "components.http_server.execution_mode": "Enabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": false, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/l1_replacer.json b/crates/apollo_deployments/resources/services/distributed/l1_replacer.json new file mode 100644 index 00000000000..ebc737faa8c --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/l1_replacer.json @@ -0,0 +1,136 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Remote", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": "$$$_COMPONENTS-BATCHER-PORT_$$$", + "components.batcher.remote_client_config.#is_none": false, + "components.batcher.remote_client_config.attempts_per_log": 10, + "components.batcher.remote_client_config.idle_connections": 10, + "components.batcher.remote_client_config.idle_timeout_ms": 30000, + "components.batcher.remote_client_config.initial_retry_delay_ms": 1, + "components.batcher.remote_client_config.max_retry_interval_ms": 1000, + "components.batcher.remote_client_config.retries": 150, + "components.batcher.url": "$$$_COMPONENTS-BATCHER-URL_$$$", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "localhost", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": false, + "components.l1_endpoint_monitor.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": "$$$_COMPONENTS-L1_ENDPOINT_MONITOR-PORT_$$$", + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "$$$_COMPONENTS-L1_ENDPOINT_MONITOR-URL_$$$", + "components.l1_gas_price_provider.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": false, + "components.l1_gas_price_provider.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": "$$$_COMPONENTS-L1_GAS_PRICE_PROVIDER-PORT_$$$", + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "$$$_COMPONENTS-L1_GAS_PRICE_PROVIDER-URL_$$$", + "components.l1_gas_price_scraper.execution_mode": "Enabled", + "components.l1_provider.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": false, + "components.l1_provider.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": "$$$_COMPONENTS-L1_PROVIDER-PORT_$$$", + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "$$$_COMPONENTS-L1_PROVIDER-URL_$$$", + "components.l1_scraper.execution_mode": "Enabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Remote", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": "$$$_COMPONENTS-STATE_SYNC-PORT_$$$", + "components.state_sync.remote_client_config.#is_none": false, + "components.state_sync.remote_client_config.attempts_per_log": 10, + "components.state_sync.remote_client_config.idle_connections": 10, + "components.state_sync.remote_client_config.idle_timeout_ms": 30000, + "components.state_sync.remote_client_config.initial_retry_delay_ms": 1, + "components.state_sync.remote_client_config.max_retry_interval_ms": 1000, + "components.state_sync.remote_client_config.retries": 150, + "components.state_sync.url": "$$$_COMPONENTS-STATE_SYNC-URL_$$$", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": false, + "l1_gas_price_provider_config.#is_none": false, + "l1_gas_price_scraper_config.#is_none": false, + "l1_provider_config.#is_none": false, + "l1_scraper_config.#is_none": false, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/mempool_replacer.json b/crates/apollo_deployments/resources/services/distributed/mempool_replacer.json new file mode 100644 index 00000000000..946261ba453 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/mempool_replacer.json @@ -0,0 +1,132 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": false, + "components.class_manager.remote_client_config.attempts_per_log": 10, + "components.class_manager.remote_client_config.idle_connections": 10, + "components.class_manager.remote_client_config.idle_timeout_ms": 30000, + "components.class_manager.remote_client_config.initial_retry_delay_ms": 1, + "components.class_manager.remote_client_config.max_retry_interval_ms": 1000, + "components.class_manager.remote_client_config.retries": 150, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Remote", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": "$$$_COMPONENTS-GATEWAY-PORT_$$$", + "components.gateway.remote_client_config.#is_none": false, + "components.gateway.remote_client_config.attempts_per_log": 10, + "components.gateway.remote_client_config.idle_connections": 0, + "components.gateway.remote_client_config.idle_timeout_ms": 30000, + "components.gateway.remote_client_config.initial_retry_delay_ms": 1, + "components.gateway.remote_client_config.max_retry_interval_ms": 1000, + "components.gateway.remote_client_config.retries": 150, + "components.gateway.url": "$$$_COMPONENTS-GATEWAY-URL_$$$", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": false, + "components.mempool.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.mempool.local_server_config.inbound_requests_channel_capacity": 1024, + "components.mempool.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.mempool.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.mempool.max_concurrency": 128, + "components.mempool.port": "$$$_COMPONENTS-MEMPOOL-PORT_$$$", + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "$$$_COMPONENTS-MEMPOOL-URL_$$$", + "components.mempool_p2p.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": false, + "components.mempool_p2p.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.inbound_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": false, + "mempool_p2p_config.#is_none": false, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/sierra_compiler_replacer.json b/crates/apollo_deployments/resources/services/distributed/sierra_compiler_replacer.json new file mode 100644 index 00000000000..5c5bbc5a3a0 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/sierra_compiler_replacer.json @@ -0,0 +1,116 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "localhost", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": false, + "components.sierra_compiler.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.inbound_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": "$$$_COMPONENTS-SIERRA_COMPILER-PORT_$$$", + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "$$$_COMPONENTS-SIERRA_COMPILER-URL_$$$", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": false, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/signature_manager_replacer.json b/crates/apollo_deployments/resources/services/distributed/signature_manager_replacer.json new file mode 100644 index 00000000000..767024cc8b6 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/signature_manager_replacer.json @@ -0,0 +1,116 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "localhost", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": false, + "components.signature_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": "$$$_COMPONENTS-SIGNATURE_MANAGER-PORT_$$$", + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "$$$_COMPONENTS-SIGNATURE_MANAGER-URL_$$$", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/distributed/state_sync_replacer.json b/crates/apollo_deployments/resources/services/distributed/state_sync_replacer.json new file mode 100644 index 00000000000..4cd74febf93 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/state_sync_replacer.json @@ -0,0 +1,122 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": false, + "components.class_manager.remote_client_config.attempts_per_log": 10, + "components.class_manager.remote_client_config.idle_connections": 10, + "components.class_manager.remote_client_config.idle_timeout_ms": 30000, + "components.class_manager.remote_client_config.initial_retry_delay_ms": 1, + "components.class_manager.remote_client_config.max_retry_interval_ms": 1000, + "components.class_manager.remote_client_config.retries": 150, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": false, + "components.state_sync.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.inbound_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": "$$$_COMPONENTS-STATE_SYNC-PORT_$$$", + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "$$$_COMPONENTS-STATE_SYNC-URL_$$$", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": false +} diff --git a/crates/apollo_deployments/resources/services/hybrid/core_replacer.json b/crates/apollo_deployments/resources/services/hybrid/core_replacer.json new file mode 100644 index 00000000000..ba3ccee5f89 --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/core_replacer.json @@ -0,0 +1,158 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": false, + "class_manager_config.#is_none": false, + "components.batcher.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": false, + "components.batcher.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.batcher.local_server_config.inbound_requests_channel_capacity": 1024, + "components.batcher.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.batcher.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.batcher.max_concurrency": 128, + "components.batcher.port": "$$$_COMPONENTS-BATCHER-PORT_$$$", + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "$$$_COMPONENTS-BATCHER-URL_$$$", + "components.class_manager.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": false, + "components.class_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.class_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Enabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Remote", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": "$$$_COMPONENTS-L1_ENDPOINT_MONITOR-PORT_$$$", + "components.l1_endpoint_monitor.remote_client_config.#is_none": false, + "components.l1_endpoint_monitor.remote_client_config.attempts_per_log": 10, + "components.l1_endpoint_monitor.remote_client_config.idle_connections": 10, + "components.l1_endpoint_monitor.remote_client_config.idle_timeout_ms": 30000, + "components.l1_endpoint_monitor.remote_client_config.initial_retry_delay_ms": 1, + "components.l1_endpoint_monitor.remote_client_config.max_retry_interval_ms": 1000, + "components.l1_endpoint_monitor.remote_client_config.retries": 0, + "components.l1_endpoint_monitor.url": "$$$_COMPONENTS-L1_ENDPOINT_MONITOR-URL_$$$", + "components.l1_gas_price_provider.execution_mode": "Remote", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": "$$$_COMPONENTS-L1_GAS_PRICE_PROVIDER-PORT_$$$", + "components.l1_gas_price_provider.remote_client_config.#is_none": false, + "components.l1_gas_price_provider.remote_client_config.attempts_per_log": 10, + "components.l1_gas_price_provider.remote_client_config.idle_connections": 10, + "components.l1_gas_price_provider.remote_client_config.idle_timeout_ms": 30000, + "components.l1_gas_price_provider.remote_client_config.initial_retry_delay_ms": 1, + "components.l1_gas_price_provider.remote_client_config.max_retry_interval_ms": 1000, + "components.l1_gas_price_provider.remote_client_config.retries": 0, + "components.l1_gas_price_provider.url": "$$$_COMPONENTS-L1_GAS_PRICE_PROVIDER-URL_$$$", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Remote", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": "$$$_COMPONENTS-L1_PROVIDER-PORT_$$$", + "components.l1_provider.remote_client_config.#is_none": false, + "components.l1_provider.remote_client_config.attempts_per_log": 10, + "components.l1_provider.remote_client_config.idle_connections": 10, + "components.l1_provider.remote_client_config.idle_timeout_ms": 30000, + "components.l1_provider.remote_client_config.initial_retry_delay_ms": 1, + "components.l1_provider.remote_client_config.max_retry_interval_ms": 1000, + "components.l1_provider.remote_client_config.retries": 0, + "components.l1_provider.url": "$$$_COMPONENTS-L1_PROVIDER-URL_$$$", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Remote", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": "$$$_COMPONENTS-MEMPOOL-PORT_$$$", + "components.mempool.remote_client_config.#is_none": false, + "components.mempool.remote_client_config.attempts_per_log": 10, + "components.mempool.remote_client_config.idle_connections": 10, + "components.mempool.remote_client_config.idle_timeout_ms": 30000, + "components.mempool.remote_client_config.initial_retry_delay_ms": 1, + "components.mempool.remote_client_config.max_retry_interval_ms": 1000, + "components.mempool.remote_client_config.retries": 150, + "components.mempool.url": "$$$_COMPONENTS-MEMPOOL-URL_$$$", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Remote", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": "$$$_COMPONENTS-SIERRA_COMPILER-PORT_$$$", + "components.sierra_compiler.remote_client_config.#is_none": false, + "components.sierra_compiler.remote_client_config.attempts_per_log": 10, + "components.sierra_compiler.remote_client_config.idle_connections": 0, + "components.sierra_compiler.remote_client_config.idle_timeout_ms": 30000, + "components.sierra_compiler.remote_client_config.initial_retry_delay_ms": 1, + "components.sierra_compiler.remote_client_config.max_retry_interval_ms": 1000, + "components.sierra_compiler.remote_client_config.retries": 150, + "components.sierra_compiler.url": "$$$_COMPONENTS-SIERRA_COMPILER-URL_$$$", + "components.signature_manager.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": false, + "components.signature_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.signature_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": "$$$_COMPONENTS-SIGNATURE_MANAGER-PORT_$$$", + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "$$$_COMPONENTS-SIGNATURE_MANAGER-URL_$$$", + "components.state_sync.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": false, + "components.state_sync.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.inbound_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.state_sync.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": "$$$_COMPONENTS-STATE_SYNC-PORT_$$$", + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "$$$_COMPONENTS-STATE_SYNC-URL_$$$", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": false, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": false +} diff --git a/crates/apollo_deployments/resources/services/hybrid/gateway_replacer.json b/crates/apollo_deployments/resources/services/hybrid/gateway_replacer.json new file mode 100644 index 00000000000..22ae14a4d9c --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/gateway_replacer.json @@ -0,0 +1,134 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": false, + "components.class_manager.remote_client_config.attempts_per_log": 10, + "components.class_manager.remote_client_config.idle_connections": 10, + "components.class_manager.remote_client_config.idle_timeout_ms": 30000, + "components.class_manager.remote_client_config.initial_retry_delay_ms": 1, + "components.class_manager.remote_client_config.max_retry_interval_ms": 1000, + "components.class_manager.remote_client_config.retries": 150, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": false, + "components.gateway.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.gateway.local_server_config.inbound_requests_channel_capacity": 1024, + "components.gateway.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.gateway.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.gateway.max_concurrency": 128, + "components.gateway.port": "$$$_COMPONENTS-GATEWAY-PORT_$$$", + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "$$$_COMPONENTS-GATEWAY-URL_$$$", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Remote", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": "$$$_COMPONENTS-MEMPOOL-PORT_$$$", + "components.mempool.remote_client_config.#is_none": false, + "components.mempool.remote_client_config.attempts_per_log": 10, + "components.mempool.remote_client_config.idle_connections": 10, + "components.mempool.remote_client_config.idle_timeout_ms": 30000, + "components.mempool.remote_client_config.initial_retry_delay_ms": 1, + "components.mempool.remote_client_config.max_retry_interval_ms": 1000, + "components.mempool.remote_client_config.retries": 150, + "components.mempool.url": "$$$_COMPONENTS-MEMPOOL-URL_$$$", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Remote", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": "$$$_COMPONENTS-STATE_SYNC-PORT_$$$", + "components.state_sync.remote_client_config.#is_none": false, + "components.state_sync.remote_client_config.attempts_per_log": 10, + "components.state_sync.remote_client_config.idle_connections": 10, + "components.state_sync.remote_client_config.idle_timeout_ms": 30000, + "components.state_sync.remote_client_config.initial_retry_delay_ms": 1, + "components.state_sync.remote_client_config.max_retry_interval_ms": 1000, + "components.state_sync.remote_client_config.retries": 150, + "components.state_sync.url": "$$$_COMPONENTS-STATE_SYNC-URL_$$$", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": false, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/hybrid/http_server_replacer.json b/crates/apollo_deployments/resources/services/hybrid/http_server_replacer.json new file mode 100644 index 00000000000..c54815a8863 --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/http_server_replacer.json @@ -0,0 +1,118 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "localhost", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Remote", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": "$$$_COMPONENTS-GATEWAY-PORT_$$$", + "components.gateway.remote_client_config.#is_none": false, + "components.gateway.remote_client_config.attempts_per_log": 10, + "components.gateway.remote_client_config.idle_connections": 0, + "components.gateway.remote_client_config.idle_timeout_ms": 30000, + "components.gateway.remote_client_config.initial_retry_delay_ms": 1, + "components.gateway.remote_client_config.max_retry_interval_ms": 1000, + "components.gateway.remote_client_config.retries": 150, + "components.gateway.url": "$$$_COMPONENTS-GATEWAY-URL_$$$", + "components.http_server.execution_mode": "Enabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": false, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/hybrid/l1_replacer.json b/crates/apollo_deployments/resources/services/hybrid/l1_replacer.json new file mode 100644 index 00000000000..181227dded9 --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/l1_replacer.json @@ -0,0 +1,136 @@ +{ + "base_layer_config.#is_none": false, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Remote", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": "$$$_COMPONENTS-BATCHER-PORT_$$$", + "components.batcher.remote_client_config.#is_none": false, + "components.batcher.remote_client_config.attempts_per_log": 10, + "components.batcher.remote_client_config.idle_connections": 10, + "components.batcher.remote_client_config.idle_timeout_ms": 30000, + "components.batcher.remote_client_config.initial_retry_delay_ms": 1, + "components.batcher.remote_client_config.max_retry_interval_ms": 1000, + "components.batcher.remote_client_config.retries": 150, + "components.batcher.url": "$$$_COMPONENTS-BATCHER-URL_$$$", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "localhost", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": false, + "components.l1_endpoint_monitor.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_endpoint_monitor.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": false, + "components.l1_gas_price_provider.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_gas_price_provider.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": "$$$_COMPONENTS-L1_GAS_PRICE_PROVIDER-PORT_$$$", + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "$$$_COMPONENTS-L1_GAS_PRICE_PROVIDER-URL_$$$", + "components.l1_gas_price_scraper.execution_mode": "Enabled", + "components.l1_provider.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": false, + "components.l1_provider.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.inbound_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.l1_provider.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": "$$$_COMPONENTS-L1_PROVIDER-PORT_$$$", + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "$$$_COMPONENTS-L1_PROVIDER-URL_$$$", + "components.l1_scraper.execution_mode": "Enabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Remote", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": "$$$_COMPONENTS-STATE_SYNC-PORT_$$$", + "components.state_sync.remote_client_config.#is_none": false, + "components.state_sync.remote_client_config.attempts_per_log": 10, + "components.state_sync.remote_client_config.idle_connections": 10, + "components.state_sync.remote_client_config.idle_timeout_ms": 30000, + "components.state_sync.remote_client_config.initial_retry_delay_ms": 1, + "components.state_sync.remote_client_config.max_retry_interval_ms": 1000, + "components.state_sync.remote_client_config.retries": 150, + "components.state_sync.url": "$$$_COMPONENTS-STATE_SYNC-URL_$$$", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": false, + "l1_gas_price_provider_config.#is_none": false, + "l1_gas_price_scraper_config.#is_none": false, + "l1_provider_config.#is_none": false, + "l1_scraper_config.#is_none": false, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/hybrid/mempool_replacer.json b/crates/apollo_deployments/resources/services/hybrid/mempool_replacer.json new file mode 100644 index 00000000000..946261ba453 --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/mempool_replacer.json @@ -0,0 +1,132 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Remote", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": "$$$_COMPONENTS-CLASS_MANAGER-PORT_$$$", + "components.class_manager.remote_client_config.#is_none": false, + "components.class_manager.remote_client_config.attempts_per_log": 10, + "components.class_manager.remote_client_config.idle_connections": 10, + "components.class_manager.remote_client_config.idle_timeout_ms": 30000, + "components.class_manager.remote_client_config.initial_retry_delay_ms": 1, + "components.class_manager.remote_client_config.max_retry_interval_ms": 1000, + "components.class_manager.remote_client_config.retries": 150, + "components.class_manager.url": "$$$_COMPONENTS-CLASS_MANAGER-URL_$$$", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Remote", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": "$$$_COMPONENTS-GATEWAY-PORT_$$$", + "components.gateway.remote_client_config.#is_none": false, + "components.gateway.remote_client_config.attempts_per_log": 10, + "components.gateway.remote_client_config.idle_connections": 0, + "components.gateway.remote_client_config.idle_timeout_ms": 30000, + "components.gateway.remote_client_config.initial_retry_delay_ms": 1, + "components.gateway.remote_client_config.max_retry_interval_ms": 1000, + "components.gateway.remote_client_config.retries": 150, + "components.gateway.url": "$$$_COMPONENTS-GATEWAY-URL_$$$", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": false, + "components.mempool.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.mempool.local_server_config.inbound_requests_channel_capacity": 1024, + "components.mempool.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.mempool.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.mempool.max_concurrency": 128, + "components.mempool.port": "$$$_COMPONENTS-MEMPOOL-PORT_$$$", + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "$$$_COMPONENTS-MEMPOOL-URL_$$$", + "components.mempool_p2p.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": false, + "components.mempool_p2p.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.inbound_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.mempool_p2p.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "Disabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": true, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": 0, + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "localhost", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": false, + "mempool_p2p_config.#is_none": false, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": true, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/resources/services/hybrid/sierra_compiler_replacer.json b/crates/apollo_deployments/resources/services/hybrid/sierra_compiler_replacer.json new file mode 100644 index 00000000000..5c5bbc5a3a0 --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/sierra_compiler_replacer.json @@ -0,0 +1,116 @@ +{ + "base_layer_config.#is_none": true, + "batcher_config.#is_none": true, + "class_manager_config.#is_none": true, + "components.batcher.execution_mode": "Disabled", + "components.batcher.ip": "0.0.0.0", + "components.batcher.local_server_config.#is_none": true, + "components.batcher.max_concurrency": 128, + "components.batcher.port": 0, + "components.batcher.remote_client_config.#is_none": true, + "components.batcher.url": "localhost", + "components.class_manager.execution_mode": "Disabled", + "components.class_manager.ip": "0.0.0.0", + "components.class_manager.local_server_config.#is_none": true, + "components.class_manager.max_concurrency": 128, + "components.class_manager.port": 0, + "components.class_manager.remote_client_config.#is_none": true, + "components.class_manager.url": "localhost", + "components.config_manager.execution_mode": "LocalExecutionWithRemoteDisabled", + "components.config_manager.ip": "0.0.0.0", + "components.config_manager.local_server_config.#is_none": false, + "components.config_manager.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.inbound_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.config_manager.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.config_manager.max_concurrency": 128, + "components.config_manager.port": 0, + "components.config_manager.remote_client_config.#is_none": true, + "components.config_manager.url": "localhost", + "components.consensus_manager.execution_mode": "Disabled", + "components.gateway.execution_mode": "Disabled", + "components.gateway.ip": "0.0.0.0", + "components.gateway.local_server_config.#is_none": true, + "components.gateway.max_concurrency": 128, + "components.gateway.port": 0, + "components.gateway.remote_client_config.#is_none": true, + "components.gateway.url": "localhost", + "components.http_server.execution_mode": "Disabled", + "components.l1_endpoint_monitor.execution_mode": "Disabled", + "components.l1_endpoint_monitor.ip": "0.0.0.0", + "components.l1_endpoint_monitor.local_server_config.#is_none": true, + "components.l1_endpoint_monitor.max_concurrency": 128, + "components.l1_endpoint_monitor.port": 0, + "components.l1_endpoint_monitor.remote_client_config.#is_none": true, + "components.l1_endpoint_monitor.url": "localhost", + "components.l1_gas_price_provider.execution_mode": "Disabled", + "components.l1_gas_price_provider.ip": "0.0.0.0", + "components.l1_gas_price_provider.local_server_config.#is_none": true, + "components.l1_gas_price_provider.max_concurrency": 128, + "components.l1_gas_price_provider.port": 0, + "components.l1_gas_price_provider.remote_client_config.#is_none": true, + "components.l1_gas_price_provider.url": "localhost", + "components.l1_gas_price_scraper.execution_mode": "Disabled", + "components.l1_provider.execution_mode": "Disabled", + "components.l1_provider.ip": "0.0.0.0", + "components.l1_provider.local_server_config.#is_none": true, + "components.l1_provider.max_concurrency": 128, + "components.l1_provider.port": 0, + "components.l1_provider.remote_client_config.#is_none": true, + "components.l1_provider.url": "localhost", + "components.l1_scraper.execution_mode": "Disabled", + "components.mempool.execution_mode": "Disabled", + "components.mempool.ip": "0.0.0.0", + "components.mempool.local_server_config.#is_none": true, + "components.mempool.max_concurrency": 128, + "components.mempool.port": 0, + "components.mempool.remote_client_config.#is_none": true, + "components.mempool.url": "localhost", + "components.mempool_p2p.execution_mode": "Disabled", + "components.mempool_p2p.ip": "0.0.0.0", + "components.mempool_p2p.local_server_config.#is_none": true, + "components.mempool_p2p.max_concurrency": 128, + "components.mempool_p2p.port": 0, + "components.mempool_p2p.remote_client_config.#is_none": true, + "components.mempool_p2p.url": "localhost", + "components.monitoring_endpoint.execution_mode": "Enabled", + "components.sierra_compiler.execution_mode": "LocalExecutionWithRemoteEnabled", + "components.sierra_compiler.ip": "0.0.0.0", + "components.sierra_compiler.local_server_config.#is_none": false, + "components.sierra_compiler.local_server_config.high_priority_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.inbound_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.normal_priority_requests_channel_capacity": 1024, + "components.sierra_compiler.local_server_config.processing_time_warning_threshold_ms": 3000, + "components.sierra_compiler.max_concurrency": 128, + "components.sierra_compiler.port": "$$$_COMPONENTS-SIERRA_COMPILER-PORT_$$$", + "components.sierra_compiler.remote_client_config.#is_none": true, + "components.sierra_compiler.url": "$$$_COMPONENTS-SIERRA_COMPILER-URL_$$$", + "components.signature_manager.execution_mode": "Disabled", + "components.signature_manager.ip": "0.0.0.0", + "components.signature_manager.local_server_config.#is_none": true, + "components.signature_manager.max_concurrency": 128, + "components.signature_manager.port": 0, + "components.signature_manager.remote_client_config.#is_none": true, + "components.signature_manager.url": "localhost", + "components.state_sync.execution_mode": "Disabled", + "components.state_sync.ip": "0.0.0.0", + "components.state_sync.local_server_config.#is_none": true, + "components.state_sync.max_concurrency": 128, + "components.state_sync.port": 0, + "components.state_sync.remote_client_config.#is_none": true, + "components.state_sync.url": "localhost", + "config_manager_config.#is_none": false, + "consensus_manager_config.#is_none": true, + "gateway_config.#is_none": true, + "http_server_config.#is_none": true, + "l1_endpoint_monitor_config.#is_none": true, + "l1_gas_price_provider_config.#is_none": true, + "l1_gas_price_scraper_config.#is_none": true, + "l1_provider_config.#is_none": true, + "l1_scraper_config.#is_none": true, + "mempool_config.#is_none": true, + "mempool_p2p_config.#is_none": true, + "monitoring_endpoint_config.#is_none": false, + "sierra_compiler_config.#is_none": false, + "state_sync_config.#is_none": true +} diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index 7408f27c037..46901da5cac 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -52,14 +52,14 @@ impl ConfigOverride { let deployment_data = to_value(&self.deployment_config_override).unwrap(); serialize_to_file(&deployment_data, deployment_path.to_str().unwrap()); serialize_to_file( - &insert_replacer_annotations(deployment_data), + &insert_replacer_annotations(deployment_data, |_, _| true), PathBuf::from(REPLACER_DIR).join(REPLACER_DEPLOYMENT_FILE_NAME).to_str().unwrap(), ); let instance_data = to_value(&self.instance_config_override).unwrap(); serialize_to_file(&instance_data, instance_path.to_str().unwrap()); serialize_to_file( - &insert_replacer_annotations(instance_data), + &insert_replacer_annotations(instance_data, |_, _| true), PathBuf::from(REPLACER_DIR).join(REPLACER_INSTANCE_FILE_NAME).to_str().unwrap(), ); } diff --git a/crates/apollo_deployments/src/replacers.rs b/crates/apollo_deployments/src/replacers.rs index dee53f42117..0e2e3edcdb8 100644 --- a/crates/apollo_deployments/src/replacers.rs +++ b/crates/apollo_deployments/src/replacers.rs @@ -3,14 +3,24 @@ use serde_json::Value; const REPLACER_FORMAT: &str = "$$$_{}_$$$"; -/// Given a flattened JSON object, overwrite each `key`'s value with `format_key(key)`. -pub(crate) fn insert_replacer_annotations(mut json: Value) -> Value { +pub(crate) fn insert_replacer_annotations(mut json: Value, pred: F) -> Value +where + F: Fn(&str, &Value) -> bool, +{ let map = json.as_object_mut().expect("Should be a JSON object"); // Collect keys to avoid mutable borrow issues while iterating. let keys: Vec = map.keys().cloned().collect(); for key in keys { - map.insert(key.clone(), Value::String(format_key(key))); + let should_replace = { + // Evaluate predicate on current value + let value = map.get(&key).expect("Key must exist"); + pred(&key, value) + }; + + if should_replace { + map.insert(key.clone(), Value::String(format_key(key.clone()))); + } } json diff --git a/crates/apollo_deployments/src/service.rs b/crates/apollo_deployments/src/service.rs index ef789611524..a3b4f458ea5 100644 --- a/crates/apollo_deployments/src/service.rs +++ b/crates/apollo_deployments/src/service.rs @@ -10,12 +10,15 @@ use apollo_infra_utils::dumping::serialize_to_file; #[cfg(test)] use apollo_infra_utils::dumping::serialize_to_file_test; use apollo_node_config::component_config::ComponentConfig; -use apollo_node_config::component_execution_config::ReactiveComponentExecutionConfig; +use apollo_node_config::component_execution_config::{ + ReactiveComponentExecutionConfig, + DEFAULT_URL, +}; use apollo_node_config::config_utils::{config_to_preset, prune_by_is_none}; use indexmap::IndexMap; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use serde_json::json; +use serde_json::{json, Value}; use strum::{Display, EnumVariantNames, IntoEnumIterator}; use strum_macros::{EnumDiscriminants, EnumIter, IntoStaticStr}; @@ -40,6 +43,7 @@ use crate::k8s::{ Resources, Toleration, }; +use crate::replacers::insert_replacer_annotations; use crate::scale_policy::ScalePolicy; #[cfg(test)] use crate::test_utils::FIX_BINARY_NAME; @@ -169,6 +173,12 @@ impl NodeService { name } + fn get_replacer_config_file_path(&self) -> String { + let mut name = self.as_inner().to_string(); + name.push_str("_replacer.json"); + name + } + pub fn create_service( &self, environment: &Environment, @@ -244,6 +254,8 @@ impl NodeService { self.as_inner().k8s_service_name() } + // TODO(Tsabary): deprecate this function after we complete the transition to the replacer + // format. fn get_service_file_path(&self) -> String { PathBuf::from(CONFIG_BASE_DIR) .join(SERVICES_DIR_NAME) @@ -253,6 +265,15 @@ impl NodeService { .to_string() } + fn get_replacer_service_file_path(&self) -> String { + PathBuf::from(CONFIG_BASE_DIR) + .join(SERVICES_DIR_NAME) + .join(NodeType::from(self).get_folder_name()) + .join(self.get_replacer_config_file_path()) + .to_string_lossy() + .to_string() + } + fn get_components_in_service(&self) -> BTreeSet { self.as_inner().get_components_in_service() } @@ -394,8 +415,29 @@ impl NodeType { ComponentConfigsSerializationWrapper::new(component_config, components_in_service); let flattened = config_to_preset(&json!(wrapper.dump())); let pruned = prune_by_is_none(flattened); + // TODO(Tsabary): deprecate this section after we complete the transition to the + // replacer format. Dumping in the original format. let file_path = node_service.get_service_file_path(); writer(&pruned, &file_path); + + // Dumping in the replacer format. + + let replace_pred = |key: &str, value: &Value| { + // Condition 1: ports set by the infra: ".port" suffix and a non-zero integer value + let port_cond = + key.ends_with(".port") && value.as_i64().map(|n| n != 0).unwrap_or(false); + + // Condition 2: service urls: ".url" suffix and a non-localhost string value + let url_cond = key.ends_with(".url") + && value.as_str().map(|s| s != DEFAULT_URL).unwrap_or(false); + + port_cond || url_cond + }; + + let pruned_with_replacer_annotations = + insert_replacer_annotations(pruned, replace_pred); + let file_path = node_service.get_replacer_service_file_path(); + writer(&pruned_with_replacer_annotations, &file_path); } } diff --git a/crates/apollo_node_config/src/component_execution_config.rs b/crates/apollo_node_config/src/component_execution_config.rs index 09b00344090..1cae06885d1 100644 --- a/crates/apollo_node_config/src/component_execution_config.rs +++ b/crates/apollo_node_config/src/component_execution_config.rs @@ -13,7 +13,7 @@ use crate::config_utils::create_validation_error; use crate::definitions::ConfigExpectation::{self, Redundant, Required}; use crate::definitions::ConfigPresence::{self, Absent, Present}; -const DEFAULT_URL: &str = "localhost"; +pub const DEFAULT_URL: &str = "localhost"; const DEFAULT_IP: IpAddr = IpAddr::V4(Ipv4Addr::UNSPECIFIED); const DEFAULT_INVALID_PORT: u16 = 0; From 4f7280376ca748ebc8f50ac7c9d49e13ab40713b Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 29 Oct 2025 16:00:56 +0200 Subject: [PATCH 186/313] apollo_integration_tests: add anvil base layer (#7782) (#9708) Add an anvil base layer wrapper, to hide anvil implementation details and ensure only one Anvil is running at a time. The saved `DynProvider` is an alloy l1-client that saves an `AnvilInstance` RIAA guard internally as a field, thus hiding the Anvil guard from callers, and tying its lifetime with that of the baselayer itself. Currently adding a single usage in the scraper flow test, will soon add to the rest of the callsites and remove `ethereum_base_layer_config_for_anvil` and other anvil-related initializers. Note: the code in `new` is nothing new :dog_pun:, it's basically what's inside the two utils it replaced in the test code. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../tests/scraper_end_to_end.rs | 22 +-- crates/papyrus_base_layer/Cargo.toml | 7 +- .../src/anvil_base_layer.rs | 135 ++++++++++++++++++ crates/papyrus_base_layer/src/lib.rs | 1 + 4 files changed, 146 insertions(+), 19 deletions(-) create mode 100644 crates/papyrus_base_layer/src/anvil_base_layer.rs diff --git a/crates/apollo_l1_provider/tests/scraper_end_to_end.rs b/crates/apollo_l1_provider/tests/scraper_end_to_end.rs index d9aa6f1c34e..84523544d1d 100644 --- a/crates/apollo_l1_provider/tests/scraper_end_to_end.rs +++ b/crates/apollo_l1_provider/tests/scraper_end_to_end.rs @@ -8,12 +8,8 @@ use apollo_l1_provider_types::{Event, MockL1ProviderClient}; use apollo_l1_scraper_config::config::L1ScraperConfig; use mockall::predicate::eq; use mockall::Sequence; -use papyrus_base_layer::ethereum_base_layer_contract::{EthereumBaseLayerContract, Starknet}; -use papyrus_base_layer::test_utils::{ - anvil_instance_from_url, - ethereum_base_layer_config_for_anvil, - DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, -}; +use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; +use papyrus_base_layer::test_utils::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS; use papyrus_base_layer::BaseLayerContract; use starknet_api::block::BlockTimestamp; use starknet_api::contract_address; @@ -34,29 +30,25 @@ async fn scraper_end_to_end() { } // Setup. - let (base_layer_config, base_layer_url) = ethereum_base_layer_config_for_anvil(None); - let _anvil_server_guard = anvil_instance_from_url(&base_layer_url); + let base_layer = AnvilBaseLayer::new().await; + let contract = &base_layer.ethereum_base_layer.contract; let mut l1_provider_client = MockL1ProviderClient::default(); - let base_layer = EthereumBaseLayerContract::new(base_layer_config, base_layer_url); - - // Deploy a fresh Starknet contract on Anvil from the bytecode in the JSON file. - Starknet::deploy(base_layer.contract.provider().clone()).await.unwrap(); // Send messages from L1 to L2. let l2_contract_address = "0x12"; let l2_entry_point = "0x34"; - let message_to_l2_0 = base_layer.contract.sendMessageToL2( + let message_to_l2_0 = contract.sendMessageToL2( l2_contract_address.parse().unwrap(), l2_entry_point.parse().unwrap(), vec![U256::from(1_u8), U256::from(2_u8)], ); - let message_to_l2_1 = base_layer.contract.sendMessageToL2( + let message_to_l2_1 = contract.sendMessageToL2( l2_contract_address.parse().unwrap(), l2_entry_point.parse().unwrap(), vec![U256::from(3_u8), U256::from(4_u8)], ); let nonce_of_message_to_l2_0 = U256::from(0_u8); - let request_cancel_message_0 = base_layer.contract.startL1ToL2MessageCancellation( + let request_cancel_message_0 = contract.startL1ToL2MessageCancellation( l2_contract_address.parse().unwrap(), l2_entry_point.parse().unwrap(), vec![U256::from(1_u8), U256::from(2_u8)], diff --git a/crates/papyrus_base_layer/Cargo.toml b/crates/papyrus_base_layer/Cargo.toml index d2d8ebe8c3c..160eb6c98e0 100644 --- a/crates/papyrus_base_layer/Cargo.toml +++ b/crates/papyrus_base_layer/Cargo.toml @@ -9,14 +9,14 @@ license-file.workspace = true workspace = true [features] -testing = ["alloy/node-bindings", "colored", "tar", "tempfile"] +testing = ["alloy/node-bindings", "tar", "tempfile"] [dependencies] -alloy = { workspace = true, features = ["contract", "json-rpc", "rpc-types"] } +alloy = { workspace = true, features = ["contract", "json-rpc", "node-bindings", "rpc-types"] } apollo_config.workspace = true apollo_l1_endpoint_monitor_types.workspace = true async-trait.workspace = true -colored = { workspace = true, optional = true } +colored.workspace = true ethers.workspace = true futures.workspace = true hex.workspace = true @@ -33,7 +33,6 @@ url = { workspace = true, features = ["serde"] } validator.workspace = true [dev-dependencies] -alloy = { workspace = true, features = ["node-bindings"] } apollo_l1_endpoint_monitor_types = { workspace = true, features = ["testing"] } assert_matches.workspace = true colored.workspace = true diff --git a/crates/papyrus_base_layer/src/anvil_base_layer.rs b/crates/papyrus_base_layer/src/anvil_base_layer.rs new file mode 100644 index 00000000000..5ab670ea40d --- /dev/null +++ b/crates/papyrus_base_layer/src/anvil_base_layer.rs @@ -0,0 +1,135 @@ +use std::ops::RangeInclusive; + +use alloy::node_bindings::NodeError as AnvilError; +use alloy::providers::{DynProvider, Provider, ProviderBuilder}; +use async_trait::async_trait; +use colored::*; +use starknet_api::block::BlockHashAndNumber; +use url::Url; + +use crate::ethereum_base_layer_contract::{ + EthereumBaseLayerConfig, + EthereumBaseLayerContract, + EthereumBaseLayerError, + Starknet, +}; +use crate::{BaseLayerContract, L1BlockHeader, L1BlockNumber, L1BlockReference, L1Event}; + +/// Initialize an anvil instance under the default port and deploy the Starknet contract. +/// +/// Usage: use this in cargo integration tests (tests under `tests/` dir), which ensure +/// sequential execution of tests and only one instance of Anvil running at once. Using Anvil in +/// unit tests is not supported and is discouraged, since unit tests should not need to run a whole +/// L1 (and they are parallelized, which creates port issues). For unit tests, prefer using +/// `ProviderBuilder::new().on_mocked_client` to mock L1. +#[derive(Clone, Debug)] +pub struct AnvilBaseLayer { + pub anvil_provider: DynProvider, + pub ethereum_base_layer: EthereumBaseLayerContract, +} + +impl AnvilBaseLayer { + const DEFAULT_ANVIL_PORT: u16 = 8545; + const DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS: &str = "0x5fbdb2315678afecb367f032d93f642f64180aa3"; + + /// Note: if you have port conflicts, this is because you are running anvil in unit tests, see + /// usage docstring of the struct. Alternatively, you might have a zombie anvil instance + /// running, but that should be impossible if using this service. + pub async fn new() -> Self { + // TODO(Arni): Remove the allow(deprecated) once we remove the deprecated function. + #[allow(deprecated)] + let anvil_client = ProviderBuilder::new() + .on_anvil_with_wallet_and_config(|anvil| anvil.port(Self::DEFAULT_ANVIL_PORT)) + .unwrap_or_else(|error| match error { + AnvilError::SpawnError(e) + if e.to_string().contains("No such file or directory") => + { + panic!( + "\n{}\n{}\n", + "Anvil binary not found!".bold().red(), + "Install instructions (for local development):\n + cargo install \ + --git https://github.com/foundry-rs/foundry anvil --locked --tag=v0.3.0" + .yellow() + ) + } + _ => panic!("Failed to spawn Anvil: {}", error.to_string().red()), + }); + + Starknet::deploy(anvil_client.clone()).await.unwrap(); + + let url: Url = format!("http://127.0.0.1:{}", Self::DEFAULT_ANVIL_PORT).parse().unwrap(); + let config = EthereumBaseLayerConfig { + starknet_contract_address: Self::DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS.parse().unwrap(), + ..Default::default() + }; + let root_client = anvil_client.root().clone(); + let contract = Starknet::new(config.starknet_contract_address, root_client); + + Self { + anvil_provider: anvil_client.erased(), + ethereum_base_layer: EthereumBaseLayerContract { config, contract, url }, + } + } +} + +#[async_trait] +impl BaseLayerContract for AnvilBaseLayer { + type Error = EthereumBaseLayerError; + + async fn get_proved_block_at( + &self, + l1_block: L1BlockNumber, + ) -> Result { + self.ethereum_base_layer.get_proved_block_at(l1_block).await + } + + async fn latest_proved_block( + &self, + finality: u64, + ) -> Result, Self::Error> { + self.ethereum_base_layer.latest_proved_block(finality).await + } + + async fn latest_l1_block_number(&self, finality: u64) -> Result { + self.ethereum_base_layer.latest_l1_block_number(finality).await + } + + async fn latest_l1_block( + &self, + finality: u64, + ) -> Result, Self::Error> { + self.ethereum_base_layer.latest_l1_block(finality).await + } + + async fn l1_block_at( + &self, + block_number: L1BlockNumber, + ) -> Result, Self::Error> { + self.ethereum_base_layer.l1_block_at(block_number).await + } + + async fn events<'a>( + &'a self, + block_range: RangeInclusive, + event_identifiers: &'a [&'a str], + ) -> Result, Self::Error> { + self.ethereum_base_layer.events(block_range, event_identifiers).await + } + + async fn get_block_header( + &self, + block_number: L1BlockNumber, + ) -> Result, Self::Error> { + self.ethereum_base_layer.get_block_header(block_number).await + } + + // TODO(Arni): Consider deleting this function from the trait. + async fn get_url(&self) -> Result { + Ok(self.ethereum_base_layer.url.clone()) + } + + async fn set_provider_url(&mut self, _url: Url) -> Result<(), Self::Error> { + unimplemented!("Anvil base layer is tied to a an Anvil server, url is fixed.") + } +} diff --git a/crates/papyrus_base_layer/src/lib.rs b/crates/papyrus_base_layer/src/lib.rs index c5c13560f7c..963aa0c4a0c 100644 --- a/crates/papyrus_base_layer/src/lib.rs +++ b/crates/papyrus_base_layer/src/lib.rs @@ -14,6 +14,7 @@ use starknet_api::transaction::fields::{Calldata, Fee}; use starknet_api::transaction::L1HandlerTransaction; use url::Url; +pub mod anvil_base_layer; pub mod constants; pub mod ethereum_base_layer_contract; pub mod monitored_base_layer; From 9ab89eead374580095e6c0aa83711184885578a6 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Wed, 29 Oct 2025 16:03:45 +0200 Subject: [PATCH 187/313] apollo_deployments: add a list of replacer files per service (#9846) --- .../deployments/testing_env_3/hybrid_3.json | 11 ----- .../replacer_deployment_node.json | 25 +++++++++++ ...{node_replacer.json => replacer_node.json} | 0 ...er_replacer.json => replacer_batcher.json} | 0 ...lacer.json => replacer_class_manager.json} | 0 ...r.json => replacer_consensus_manager.json} | 0 .../replacer_deployment_batcher.json | 11 +++++ .../replacer_deployment_class_manager.json | 11 +++++ ...replacer_deployment_consensus_manager.json | 11 +++++ .../replacer_deployment_gateway.json | 11 +++++ .../replacer_deployment_http_server.json | 11 +++++ .../distributed/replacer_deployment_l1.json | 15 +++++++ .../replacer_deployment_mempool.json | 12 ++++++ .../replacer_deployment_sierra_compiler.json | 11 +++++ ...replacer_deployment_signature_manager.json | 10 +++++ .../replacer_deployment_state_sync.json | 11 +++++ ...ay_replacer.json => replacer_gateway.json} | 0 ...eplacer.json => replacer_http_server.json} | 0 .../{l1_replacer.json => replacer_l1.json} | 0 ...ol_replacer.json => replacer_mempool.json} | 0 ...cer.json => replacer_sierra_compiler.json} | 0 ...r.json => replacer_signature_manager.json} | 0 ...replacer.json => replacer_state_sync.json} | 0 ...{core_replacer.json => replacer_core.json} | 0 .../hybrid/replacer_deployment_core.json | 14 ++++++ .../hybrid/replacer_deployment_gateway.json | 11 +++++ .../replacer_deployment_http_server.json | 11 +++++ .../hybrid/replacer_deployment_l1.json | 16 +++++++ .../hybrid/replacer_deployment_mempool.json | 12 ++++++ .../replacer_deployment_sierra_compiler.json | 11 +++++ ...ay_replacer.json => replacer_gateway.json} | 0 ...eplacer.json => replacer_http_server.json} | 0 .../{l1_replacer.json => replacer_l1.json} | 0 ...ol_replacer.json => replacer_mempool.json} | 0 ...cer.json => replacer_sierra_compiler.json} | 0 .../apollo_deployments/src/config_override.rs | 12 +++++- crates/apollo_deployments/src/service.rs | 43 ++++++++++++++----- 37 files changed, 257 insertions(+), 23 deletions(-) delete mode 100644 crates/apollo_deployments/resources/deployments/testing_env_3/hybrid_3.json create mode 100644 crates/apollo_deployments/resources/services/consolidated/replacer_deployment_node.json rename crates/apollo_deployments/resources/services/consolidated/{node_replacer.json => replacer_node.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{batcher_replacer.json => replacer_batcher.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{class_manager_replacer.json => replacer_class_manager.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{consensus_manager_replacer.json => replacer_consensus_manager.json} (100%) create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_batcher.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_class_manager.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_consensus_manager.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_gateway.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_http_server.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_l1.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_mempool.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_sierra_compiler.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_signature_manager.json create mode 100644 crates/apollo_deployments/resources/services/distributed/replacer_deployment_state_sync.json rename crates/apollo_deployments/resources/services/distributed/{gateway_replacer.json => replacer_gateway.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{http_server_replacer.json => replacer_http_server.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{l1_replacer.json => replacer_l1.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{mempool_replacer.json => replacer_mempool.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{sierra_compiler_replacer.json => replacer_sierra_compiler.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{signature_manager_replacer.json => replacer_signature_manager.json} (100%) rename crates/apollo_deployments/resources/services/distributed/{state_sync_replacer.json => replacer_state_sync.json} (100%) rename crates/apollo_deployments/resources/services/hybrid/{core_replacer.json => replacer_core.json} (100%) create mode 100644 crates/apollo_deployments/resources/services/hybrid/replacer_deployment_core.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/replacer_deployment_gateway.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/replacer_deployment_http_server.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/replacer_deployment_l1.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/replacer_deployment_mempool.json create mode 100644 crates/apollo_deployments/resources/services/hybrid/replacer_deployment_sierra_compiler.json rename crates/apollo_deployments/resources/services/hybrid/{gateway_replacer.json => replacer_gateway.json} (100%) rename crates/apollo_deployments/resources/services/hybrid/{http_server_replacer.json => replacer_http_server.json} (100%) rename crates/apollo_deployments/resources/services/hybrid/{l1_replacer.json => replacer_l1.json} (100%) rename crates/apollo_deployments/resources/services/hybrid/{mempool_replacer.json => replacer_mempool.json} (100%) rename crates/apollo_deployments/resources/services/hybrid/{sierra_compiler_replacer.json => replacer_sierra_compiler.json} (100%) diff --git a/crates/apollo_deployments/resources/deployments/testing_env_3/hybrid_3.json b/crates/apollo_deployments/resources/deployments/testing_env_3/hybrid_3.json deleted file mode 100644 index e81f2d2d515..00000000000 --- a/crates/apollo_deployments/resources/deployments/testing_env_3/hybrid_3.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "consensus_manager_config.network_config.advertised_multiaddr": "/dns/sequencer-core-service.sequencer-test-3-node-3.sw-dev.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54", - "consensus_manager_config.network_config.advertised_multiaddr.#is_none": false, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.sequencer-test-3-node-0.sw-dev.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, - "mempool_p2p_config.network_config.advertised_multiaddr": "/dns/sequencer-mempool-service.sequencer-test-3-node-3.sw-dev.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54", - "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": false, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.sequencer-test-3-node-0.sw-dev.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, - "validator_id": "0x67" -} diff --git a/crates/apollo_deployments/resources/services/consolidated/replacer_deployment_node.json b/crates/apollo_deployments/resources/services/consolidated/replacer_deployment_node.json new file mode 100644 index 00000000000..b1ff257fbea --- /dev/null +++ b/crates/apollo_deployments/resources/services/consolidated/replacer_deployment_node.json @@ -0,0 +1,25 @@ +[ + "crates/apollo_deployments/resources/app_configs/base_layer_config.json", + "crates/apollo_deployments/resources/app_configs/batcher_config.json", + "crates/apollo_deployments/resources/app_configs/class_manager_config.json", + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/consensus_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/gateway_config.json", + "crates/apollo_deployments/resources/app_configs/http_server_config.json", + "crates/apollo_deployments/resources/app_configs/l1_endpoint_monitor_config.json", + "crates/apollo_deployments/resources/app_configs/l1_gas_price_provider_config.json", + "crates/apollo_deployments/resources/app_configs/l1_gas_price_scraper_config.json", + "crates/apollo_deployments/resources/app_configs/l1_provider_config.json", + "crates/apollo_deployments/resources/app_configs/l1_scraper_config.json", + "crates/apollo_deployments/resources/app_configs/mempool_config.json", + "crates/apollo_deployments/resources/app_configs/mempool_p2p_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/app_configs/sierra_compiler_config.json", + "crates/apollo_deployments/resources/app_configs/state_sync_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/consolidated/replacer_node.json" +] diff --git a/crates/apollo_deployments/resources/services/consolidated/node_replacer.json b/crates/apollo_deployments/resources/services/consolidated/replacer_node.json similarity index 100% rename from crates/apollo_deployments/resources/services/consolidated/node_replacer.json rename to crates/apollo_deployments/resources/services/consolidated/replacer_node.json diff --git a/crates/apollo_deployments/resources/services/distributed/batcher_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_batcher.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/batcher_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_batcher.json diff --git a/crates/apollo_deployments/resources/services/distributed/class_manager_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_class_manager.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/class_manager_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_class_manager.json diff --git a/crates/apollo_deployments/resources/services/distributed/consensus_manager_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_consensus_manager.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/consensus_manager_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_consensus_manager.json diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_batcher.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_batcher.json new file mode 100644 index 00000000000..e429ed21372 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_batcher.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/batcher_config.json", + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_batcher.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_class_manager.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_class_manager.json new file mode 100644 index 00000000000..38fba9734a3 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_class_manager.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/class_manager_config.json", + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_class_manager.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_consensus_manager.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_consensus_manager.json new file mode 100644 index 00000000000..56e8e1fefbd --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_consensus_manager.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/consensus_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_consensus_manager.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_gateway.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_gateway.json new file mode 100644 index 00000000000..ac2b3d3f70f --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_gateway.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/gateway_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_gateway.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_http_server.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_http_server.json new file mode 100644 index 00000000000..43ac4aad6e3 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_http_server.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/http_server_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_http_server.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_l1.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_l1.json new file mode 100644 index 00000000000..9b693b43ee2 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_l1.json @@ -0,0 +1,15 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/l1_endpoint_monitor_config.json", + "crates/apollo_deployments/resources/app_configs/l1_gas_price_provider_config.json", + "crates/apollo_deployments/resources/app_configs/l1_gas_price_scraper_config.json", + "crates/apollo_deployments/resources/app_configs/l1_provider_config.json", + "crates/apollo_deployments/resources/app_configs/l1_scraper_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_l1.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_mempool.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_mempool.json new file mode 100644 index 00000000000..64b36499c1b --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_mempool.json @@ -0,0 +1,12 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/mempool_config.json", + "crates/apollo_deployments/resources/app_configs/mempool_p2p_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_mempool.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_sierra_compiler.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_sierra_compiler.json new file mode 100644 index 00000000000..9af82dc3363 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_sierra_compiler.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/app_configs/sierra_compiler_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_sierra_compiler.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_signature_manager.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_signature_manager.json new file mode 100644 index 00000000000..d3b70ad8885 --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_signature_manager.json @@ -0,0 +1,10 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_signature_manager.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/replacer_deployment_state_sync.json b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_state_sync.json new file mode 100644 index 00000000000..743ef9c283f --- /dev/null +++ b/crates/apollo_deployments/resources/services/distributed/replacer_deployment_state_sync.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/app_configs/state_sync_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/distributed/replacer_state_sync.json" +] diff --git a/crates/apollo_deployments/resources/services/distributed/gateway_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_gateway.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/gateway_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_gateway.json diff --git a/crates/apollo_deployments/resources/services/distributed/http_server_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_http_server.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/http_server_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_http_server.json diff --git a/crates/apollo_deployments/resources/services/distributed/l1_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_l1.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/l1_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_l1.json diff --git a/crates/apollo_deployments/resources/services/distributed/mempool_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_mempool.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/mempool_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_mempool.json diff --git a/crates/apollo_deployments/resources/services/distributed/sierra_compiler_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_sierra_compiler.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/sierra_compiler_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_sierra_compiler.json diff --git a/crates/apollo_deployments/resources/services/distributed/signature_manager_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_signature_manager.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/signature_manager_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_signature_manager.json diff --git a/crates/apollo_deployments/resources/services/distributed/state_sync_replacer.json b/crates/apollo_deployments/resources/services/distributed/replacer_state_sync.json similarity index 100% rename from crates/apollo_deployments/resources/services/distributed/state_sync_replacer.json rename to crates/apollo_deployments/resources/services/distributed/replacer_state_sync.json diff --git a/crates/apollo_deployments/resources/services/hybrid/core_replacer.json b/crates/apollo_deployments/resources/services/hybrid/replacer_core.json similarity index 100% rename from crates/apollo_deployments/resources/services/hybrid/core_replacer.json rename to crates/apollo_deployments/resources/services/hybrid/replacer_core.json diff --git a/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_core.json b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_core.json new file mode 100644 index 00000000000..34375d524fe --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_core.json @@ -0,0 +1,14 @@ +[ + "crates/apollo_deployments/resources/app_configs/batcher_config.json", + "crates/apollo_deployments/resources/app_configs/class_manager_config.json", + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/consensus_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/app_configs/state_sync_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/hybrid/replacer_core.json" +] diff --git a/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_gateway.json b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_gateway.json new file mode 100644 index 00000000000..01146ba5c5a --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_gateway.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/gateway_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/hybrid/replacer_gateway.json" +] diff --git a/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_http_server.json b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_http_server.json new file mode 100644 index 00000000000..dd3e328bf50 --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_http_server.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/http_server_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/hybrid/replacer_http_server.json" +] diff --git a/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_l1.json b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_l1.json new file mode 100644 index 00000000000..9a21009359b --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_l1.json @@ -0,0 +1,16 @@ +[ + "crates/apollo_deployments/resources/app_configs/base_layer_config.json", + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/l1_endpoint_monitor_config.json", + "crates/apollo_deployments/resources/app_configs/l1_gas_price_provider_config.json", + "crates/apollo_deployments/resources/app_configs/l1_gas_price_scraper_config.json", + "crates/apollo_deployments/resources/app_configs/l1_provider_config.json", + "crates/apollo_deployments/resources/app_configs/l1_scraper_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/hybrid/replacer_l1.json" +] diff --git a/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_mempool.json b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_mempool.json new file mode 100644 index 00000000000..23ff5cec9c3 --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_mempool.json @@ -0,0 +1,12 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/mempool_config.json", + "crates/apollo_deployments/resources/app_configs/mempool_p2p_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/hybrid/replacer_mempool.json" +] diff --git a/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_sierra_compiler.json b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_sierra_compiler.json new file mode 100644 index 00000000000..c981df0db48 --- /dev/null +++ b/crates/apollo_deployments/resources/services/hybrid/replacer_deployment_sierra_compiler.json @@ -0,0 +1,11 @@ +[ + "crates/apollo_deployments/resources/app_configs/config_manager_config.json", + "crates/apollo_deployments/resources/app_configs/revert_config.json", + "crates/apollo_deployments/resources/app_configs/versioned_constants_overrides_config.json", + "crates/apollo_deployments/resources/app_configs/validate_resource_bounds_config.json", + "crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json", + "crates/apollo_deployments/resources/app_configs/sierra_compiler_config.json", + "crates/apollo_deployments/resources/deployments/replacer_deployment.json", + "crates/apollo_deployments/resources/deployments/replacer_instance.json", + "crates/apollo_deployments/resources/services/hybrid/replacer_sierra_compiler.json" +] diff --git a/crates/apollo_deployments/resources/services/hybrid/gateway_replacer.json b/crates/apollo_deployments/resources/services/hybrid/replacer_gateway.json similarity index 100% rename from crates/apollo_deployments/resources/services/hybrid/gateway_replacer.json rename to crates/apollo_deployments/resources/services/hybrid/replacer_gateway.json diff --git a/crates/apollo_deployments/resources/services/hybrid/http_server_replacer.json b/crates/apollo_deployments/resources/services/hybrid/replacer_http_server.json similarity index 100% rename from crates/apollo_deployments/resources/services/hybrid/http_server_replacer.json rename to crates/apollo_deployments/resources/services/hybrid/replacer_http_server.json diff --git a/crates/apollo_deployments/resources/services/hybrid/l1_replacer.json b/crates/apollo_deployments/resources/services/hybrid/replacer_l1.json similarity index 100% rename from crates/apollo_deployments/resources/services/hybrid/l1_replacer.json rename to crates/apollo_deployments/resources/services/hybrid/replacer_l1.json diff --git a/crates/apollo_deployments/resources/services/hybrid/mempool_replacer.json b/crates/apollo_deployments/resources/services/hybrid/replacer_mempool.json similarity index 100% rename from crates/apollo_deployments/resources/services/hybrid/mempool_replacer.json rename to crates/apollo_deployments/resources/services/hybrid/replacer_mempool.json diff --git a/crates/apollo_deployments/resources/services/hybrid/sierra_compiler_replacer.json b/crates/apollo_deployments/resources/services/hybrid/replacer_sierra_compiler.json similarity index 100% rename from crates/apollo_deployments/resources/services/hybrid/sierra_compiler_replacer.json rename to crates/apollo_deployments/resources/services/hybrid/replacer_sierra_compiler.json diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index 46901da5cac..88d8db2acca 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -31,6 +31,14 @@ pub struct ConfigOverride { instance_config_override: InstanceConfigOverride, } +pub(crate) fn deployment_replacer_file_path() -> String { + PathBuf::from(REPLACER_DIR).join(REPLACER_DEPLOYMENT_FILE_NAME).to_string_lossy().to_string() +} + +pub(crate) fn instance_replacer_file_path() -> String { + PathBuf::from(REPLACER_DIR).join(REPLACER_INSTANCE_FILE_NAME).to_string_lossy().to_string() +} + impl ConfigOverride { pub const fn new( deployment_config_override: DeploymentConfigOverride, @@ -53,14 +61,14 @@ impl ConfigOverride { serialize_to_file(&deployment_data, deployment_path.to_str().unwrap()); serialize_to_file( &insert_replacer_annotations(deployment_data, |_, _| true), - PathBuf::from(REPLACER_DIR).join(REPLACER_DEPLOYMENT_FILE_NAME).to_str().unwrap(), + &deployment_replacer_file_path(), ); let instance_data = to_value(&self.instance_config_override).unwrap(); serialize_to_file(&instance_data, instance_path.to_str().unwrap()); serialize_to_file( &insert_replacer_annotations(instance_data, |_, _| true), - PathBuf::from(REPLACER_DIR).join(REPLACER_INSTANCE_FILE_NAME).to_str().unwrap(), + &instance_replacer_file_path(), ); } diff --git a/crates/apollo_deployments/src/service.rs b/crates/apollo_deployments/src/service.rs index a3b4f458ea5..c0d8f39e815 100644 --- a/crates/apollo_deployments/src/service.rs +++ b/crates/apollo_deployments/src/service.rs @@ -22,6 +22,7 @@ use serde_json::{json, Value}; use strum::{Display, EnumVariantNames, IntoEnumIterator}; use strum_macros::{EnumDiscriminants, EnumIter, IntoStaticStr}; +use crate::config_override::{deployment_replacer_file_path, instance_replacer_file_path}; use crate::deployment::build_service_namespace_domain_address; use crate::deployment_definitions::{ ComponentConfigInService, @@ -88,8 +89,6 @@ impl Service { // TODO(Tsabary): reduce visibility of relevant functions and consts. - let service_file_path = node_service.get_service_file_path(); - let components_in_service = node_service .get_components_in_service() .into_iter() @@ -97,9 +96,26 @@ impl Service { .collect::>(); let config_paths = components_in_service .into_iter() - .chain(config_filenames) - .chain(once(service_file_path)) + .chain(config_filenames.clone()) + .chain(once(node_service.get_service_file_path())) + .collect(); + + // TODO(Tsabary): currently using the creation of the non-replacer service struct to DUMP + // the list of files of the replacer format. This should be triggered by a new flow. + let replacer_components_in_service = node_service + .get_components_in_service() + .into_iter() + .flat_map(|c| c.get_component_config_file_paths()) + .collect::>(); + let replacer_config_filenames: Vec = + vec![deployment_replacer_file_path(), instance_replacer_file_path()]; + let replacer_config_paths: Vec = replacer_components_in_service + .into_iter() + .chain(replacer_config_filenames) + .chain(once(node_service.get_replacer_service_file_path())) .collect(); + let replacer_deployment_file_path = node_service.replacer_deployment_file_path(); + serialize_to_file(&replacer_config_paths, &replacer_deployment_file_path); let controller = node_service.get_controller(); let scale_policy = node_service.get_scale_policy(); @@ -166,17 +182,24 @@ pub enum NodeService { Distributed(DistributedNodeServiceName), } +// TODO(Tsabary): move p2p ports from the application configs to the replacer format. + impl NodeService { + pub fn replacer_deployment_file_path(&self) -> String { + PathBuf::from(CONFIG_BASE_DIR) + .join(SERVICES_DIR_NAME) + .join(NodeType::from(self).get_folder_name()) + .join(format!("replacer_deployment_{}.json", self.as_inner())) + .to_string_lossy() + .to_string() + } + fn get_config_file_path(&self) -> String { - let mut name = self.as_inner().to_string(); - name.push_str(".json"); - name + format!("{}.json", self.as_inner()) } fn get_replacer_config_file_path(&self) -> String { - let mut name = self.as_inner().to_string(); - name.push_str("_replacer.json"); - name + format!("replacer_{}.json", self.as_inner()) } pub fn create_service( From 9b1e1f0c043d41eabd8fef30c168369caf5d3654 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 30 Oct 2025 07:56:10 +0200 Subject: [PATCH 188/313] apollo_integration_tests: consolidate Ethereum contract address re-export (#7783) (#9709) Removes `alloy` type from the API of `papyrus_base_layer` and define in the proper place, which is `ethereum_base_layer`. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- crates/papyrus_base_layer/src/eth_events.rs | 3 ++- .../src/ethereum_base_layer_contract.rs | 3 ++- crates/papyrus_base_layer/src/test_utils.rs | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/papyrus_base_layer/src/eth_events.rs b/crates/papyrus_base_layer/src/eth_events.rs index 2f9177a620e..af61af9dec7 100644 --- a/crates/papyrus_base_layer/src/eth_events.rs +++ b/crates/papyrus_base_layer/src/eth_events.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use alloy::primitives::{Address as EthereumContractAddress, U256}; +use alloy::primitives::U256; use alloy::rpc::types::Log; use alloy::sol_types::SolEventInterface; use starknet_api::block::BlockTimestamp; @@ -12,6 +12,7 @@ use starknet_types_core::felt::Felt; use crate::ethereum_base_layer_contract::{ EthereumBaseLayerError, EthereumBaseLayerResult, + EthereumContractAddress, Starknet, }; use crate::{EventData, L1Event}; diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index 48302a37ce7..00c6c53e99a 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -6,7 +6,7 @@ use std::time::Duration; use alloy::dyn_abi::SolType; use alloy::eips::eip7840; use alloy::network::Ethereum; -use alloy::primitives::Address as EthereumContractAddress; +use alloy::primitives::Address; use alloy::providers::{Provider, ProviderBuilder, RootProvider}; use alloy::rpc::json_rpc::RpcError; use alloy::rpc::types::eth::Filter as EthEventFilter; @@ -37,6 +37,7 @@ use crate::{ }; pub type EthereumBaseLayerResult = Result; +pub type EthereumContractAddress = Address; // Wraps the Starknet contract with a type that implements its interface, and is aware of its // events. diff --git a/crates/papyrus_base_layer/src/test_utils.rs b/crates/papyrus_base_layer/src/test_utils.rs index f34738ce2e0..c52ef15a4a3 100644 --- a/crates/papyrus_base_layer/src/test_utils.rs +++ b/crates/papyrus_base_layer/src/test_utils.rs @@ -3,8 +3,7 @@ use std::process::Command; use alloy::network::TransactionBuilder; use alloy::node_bindings::{Anvil, AnvilInstance, NodeError as AnvilError}; -pub(crate) use alloy::primitives::Address as EthereumContractAddress; -use alloy::primitives::{Address, U256}; +use alloy::primitives::U256; use alloy::providers::Provider; use alloy::rpc::types::TransactionRequest; use colored::*; @@ -18,6 +17,7 @@ use url::Url; use crate::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, EthereumBaseLayerContract, + EthereumContractAddress, Starknet, StarknetL1Contract, }; @@ -159,8 +159,8 @@ pub async fn deploy_starknet_l1_contract( } pub async fn make_block_history_on_anvil( - sender_address: Address, - receiver_address: Address, + sender_address: EthereumContractAddress, + receiver_address: EthereumContractAddress, base_layer_config: EthereumBaseLayerConfig, url: &Url, num_blocks: usize, From 1800f786e5b92638f59a7449b37a9f3b3bbdce35 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:41:17 +0200 Subject: [PATCH 189/313] apollo_deployments: potc mock sharp nodes 10-12 (#9836) --- .../deployment_inputs/potc_mock.json | 12 + .../deployment_config_hybrid_10.json | 273 ++++++++++++++++++ .../deployment_config_hybrid_11.json | 273 ++++++++++++++++++ .../deployment_config_hybrid_12.json | 273 ++++++++++++++++++ .../potc_mock/deployment_config_override.json | 4 +- .../deployments/potc_mock/hybrid_10.json | 7 + .../deployments/potc_mock/hybrid_11.json | 7 + .../deployments/potc_mock/hybrid_12.json | 7 + 8 files changed, 854 insertions(+), 2 deletions(-) create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_10.json create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_11.json create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_12.json create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/hybrid_10.json create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/hybrid_11.json create mode 100644 crates/apollo_deployments/resources/deployments/potc_mock/hybrid_12.json diff --git a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json index ca986dcc89f..339c50e498b 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json +++ b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json @@ -11,6 +11,18 @@ [ 2, "0x66" + ], + [ + 10, + "0x1" + ], + [ + 11, + "0x1" + ], + [ + 12, + "0x1" ] ], "num_validators": 3, diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_10.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_10.json new file mode 100644 index 00000000000..c309c7d1805 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_10.json @@ -0,0 +1,273 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_10.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "batcher-8-64", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 7, + "memory": 14 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-10" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_10.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "potc-testnet-mock-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_10.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_10.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-10" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_10.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-10" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_10.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-10" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_11.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_11.json new file mode 100644 index 00000000000..50e2bcb54e9 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_11.json @@ -0,0 +1,273 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_11.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "batcher-8-64", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 7, + "memory": 14 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-11" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_11.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "potc-testnet-mock-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_11.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_11.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-11" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_11.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-11" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_11.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-11" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_12.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_12.json new file mode 100644 index 00000000000..41396c2e316 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_hybrid_12.json @@ -0,0 +1,273 @@ +{ + "application_config_subdir": "crates/apollo_deployments/resources/", + "services": [ + { + "name": "Core", + "controller": "StatefulSet", + "config_paths": [ + "app_configs/batcher_config.json", + "app_configs/class_manager_config.json", + "app_configs/config_manager_config.json", + "app_configs/consensus_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/state_sync_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_12.json", + "services/hybrid/core.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": 1000, + "toleration": "batcher-8-64", + "resources": { + "requests": { + "cpu": 2, + "memory": 4 + }, + "limits": { + "cpu": 7, + "memory": 14 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-12" + }, + "anti_affinity": true, + "update_strategy_type": "RollingUpdate", + "ports": { + "Batcher": 55000, + "ClassManager": 55001, + "SignatureManager": 55008, + "StateSync": 55009, + "ConsensusP2p": 53080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "HttpServer", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/http_server_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_12.json", + "services/hybrid/http_server.json" + ], + "ingress": { + "domain": "starknet.io", + "alternative_names": [ + "potc-testnet-mock-sepolia.starknet.io" + ], + "internal": false, + "rules": [ + { + "path": "/gateway", + "port": 8080, + "backend": null + } + ] + }, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 4, + "memory": 8 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-12" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "HttpServer": 8080, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Gateway", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/gateway_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_12.json", + "services/hybrid/gateway.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-12" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "Gateway": 55002, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "L1", + "controller": "Deployment", + "config_paths": [ + "app_configs/base_layer_config.json", + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/l1_endpoint_monitor_config.json", + "app_configs/l1_gas_price_provider_config.json", + "app_configs/l1_gas_price_scraper_config.json", + "app_configs/l1_provider_config.json", + "app_configs/l1_scraper_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_12.json", + "services/hybrid/l1.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-l1-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-12" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "L1EndpointMonitor": 55005, + "L1GasPriceProvider": 55003, + "L1Provider": 55004, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "Mempool", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/mempool_config.json", + "app_configs/mempool_p2p_config.json", + "app_configs/monitoring_endpoint_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_12.json", + "services/hybrid/mempool.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": false, + "replicas": 1, + "storage": null, + "toleration": "apollo-mempool-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-12" + }, + "anti_affinity": true, + "update_strategy_type": "Recreate", + "ports": { + "Mempool": 55006, + "MonitoringEndpoint": 8082 + } + }, + { + "name": "SierraCompiler", + "controller": "Deployment", + "config_paths": [ + "app_configs/config_manager_config.json", + "app_configs/revert_config.json", + "app_configs/versioned_constants_overrides_config.json", + "app_configs/validate_resource_bounds_config.json", + "app_configs/monitoring_endpoint_config.json", + "app_configs/sierra_compiler_config.json", + "deployments/potc_mock/deployment_config_override.json", + "deployments/potc_mock/hybrid_12.json", + "services/hybrid/sierra_compiler.json" + ], + "ingress": null, + "k8s_service_config": null, + "autoscale": true, + "replicas": 2, + "storage": null, + "toleration": "apollo-general-service", + "resources": { + "requests": { + "cpu": 1, + "memory": 2 + }, + "limits": { + "cpu": 2, + "memory": 4 + } + }, + "external_secret": { + "gcsm_key": "apollo-potc-mock-12" + }, + "anti_affinity": false, + "update_strategy_type": "RollingUpdate", + "ports": { + "SierraCompiler": 55007, + "MonitoringEndpoint": 8082 + } + } + ] +} diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json index fae638de90a..3b07315977b 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json @@ -2,12 +2,12 @@ "base_layer_config.starknet_contract_address": "0xd8A5518cf4AC3ECD3b4cec772478109679a73E78", "chain_id": "PRIVATE_SN_POTC_MOCK_SEPOLIA", "consensus_manager_config.context_config.num_validators": 3, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-potc-mock-10.svc.cluster.local/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-potc-mock-11.svc.cluster.local/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-potc-mock-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-potc-mock-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-potc-mock-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-potc-mock-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.potc-testnet-mock-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_10.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_10.json new file mode 100644 index 00000000000..a1e64457f84 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_10.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_11.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_11.json new file mode 100644 index 00000000000..a1e64457f84 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_11.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "validator_id": "0x1" +} diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_12.json b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_12.json new file mode 100644 index 00000000000..a1e64457f84 --- /dev/null +++ b/crates/apollo_deployments/resources/deployments/potc_mock/hybrid_12.json @@ -0,0 +1,7 @@ +{ + "consensus_manager_config.network_config.advertised_multiaddr": "", + "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.advertised_multiaddr": "", + "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, + "validator_id": "0x1" +} From 753f61c27b9dd85fc02ba0dee3c3fa236fb6f997 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:19:36 +0200 Subject: [PATCH 190/313] bench_tools: add criterion benchmark names to benchmark config (#9697) --- crates/bench_tools/src/types/benchmark_config.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/bench_tools/src/types/benchmark_config.rs b/crates/bench_tools/src/types/benchmark_config.rs index a5cfc59c53b..020f196a4d4 100644 --- a/crates/bench_tools/src/types/benchmark_config.rs +++ b/crates/bench_tools/src/types/benchmark_config.rs @@ -7,6 +7,10 @@ pub struct BenchmarkConfig { /// Optional input directory path relative to workspace root. If set, inputs will be /// downloaded from GCS before running the benchmark. pub input_dir: Option<&'static str>, + /// Optional list of Criterion benchmark names that this benchmark suite produces. + /// If None, assumes a single benchmark with the same name as the config. + /// Used for regression checking to know which criterion directories to check. + pub criterion_benchmark_names: Option<&'static [&'static str]>, } impl BenchmarkConfig { @@ -28,24 +32,33 @@ pub const BENCHMARKS: &[BenchmarkConfig] = &[ package: "starknet_committer_and_os_cli", cmd_args: &["bench", "-p", "starknet_committer_and_os_cli", "full_committer_flow"], input_dir: Some("crates/starknet_committer_and_os_cli/test_inputs"), + criterion_benchmark_names: None, // Single benchmark with same name. }, BenchmarkConfig { name: "single_tree_flow", package: "starknet_committer_and_os_cli", cmd_args: &["bench", "-p", "starknet_committer_and_os_cli", "single_tree_flow"], input_dir: Some("crates/starknet_committer_and_os_cli/test_inputs"), + criterion_benchmark_names: None, // Single benchmark with same name. }, BenchmarkConfig { name: "gateway_apply_block", package: "apollo_gateway", cmd_args: &["bench", "-p", "apollo_gateway", "apply_block"], input_dir: None, + criterion_benchmark_names: None, // Single benchmark with same name. }, BenchmarkConfig { name: "dummy_benchmark", package: "bench_tools", cmd_args: &["bench", "-p", "bench_tools", "--bench", "dummy_bench"], input_dir: Some("crates/bench_tools/data/dummy_bench_input"), + criterion_benchmark_names: Some(&[ + "dummy_sum_100", + "dummy_sum_1000", + "dummy_process_small_input", + "dummy_process_large_input", + ]), }, ]; From dda2576440bd1531d0120e99bc6d26a166de7eed Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:37:56 +0200 Subject: [PATCH 191/313] bench_tools: save specific benchmark result (#9742) --- crates/bench_tools/src/runner.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/crates/bench_tools/src/runner.rs b/crates/bench_tools/src/runner.rs index be89ee27453..1a071e5071b 100644 --- a/crates/bench_tools/src/runner.rs +++ b/crates/bench_tools/src/runner.rs @@ -59,23 +59,24 @@ fn run_single_benchmark(bench: &BenchmarkConfig) { } /// Collects benchmark results from criterion output and saves them to the output directory. -fn save_benchmark_results(_bench: &BenchmarkConfig, output_dir: &str) { +fn save_benchmark_results(bench: &BenchmarkConfig, output_dir: &str) { let criterion_base = PathBuf::from("target/criterion"); - let Ok(entries) = fs::read_dir(&criterion_base) else { return }; - // Collect all estimates files. - for entry in entries.flatten() { - let path = entry.path(); - if !path.is_dir() { - continue; - } + // Get the list of criterion benchmark names to save. + // If None, use the benchmark config name. + let benchmark_names: Vec<&str> = match bench.criterion_benchmark_names { + Some(names) => names.to_vec(), + None => vec![bench.name], + }; + + // Save results for each criterion benchmark name. + for bench_name in benchmark_names { + let bench_path = criterion_base.join(bench_name); + let estimates_path = bench_path.join("new/estimates.json"); - // Save estimates file. - let estimates_path = path.join("new/estimates.json"); if let Ok(data) = fs::read_to_string(&estimates_path) { if let Ok(json) = serde_json::from_str::(&data) { if let Ok(pretty) = serde_json::to_string_pretty(&json) { - let bench_name = path.file_name().unwrap().to_string_lossy(); let dest = PathBuf::from(output_dir).join(format!("{}_estimates.json", bench_name)); if fs::write(&dest, pretty).is_ok() { From 6b0e1126d058fa342669c561aca4d1a654dfb756 Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:46:06 +0200 Subject: [PATCH 192/313] apollo_consensus: refactor RunConsensusArguments to use ConsensusConfig (#9765) --- crates/apollo_consensus/src/manager.rs | 56 +++++++--------- crates/apollo_consensus/src/manager_test.rs | 64 +++++++++++++------ .../src/consensus_manager.rs | 9 +-- 3 files changed, 67 insertions(+), 62 deletions(-) diff --git a/crates/apollo_consensus/src/manager.rs b/crates/apollo_consensus/src/manager.rs index a89599ddcca..d6e500b95b3 100644 --- a/crates/apollo_consensus/src/manager.rs +++ b/crates/apollo_consensus/src/manager.rs @@ -10,9 +10,8 @@ mod manager_test; use std::collections::BTreeMap; -use std::time::Duration; -use apollo_consensus_config::config::TimeoutsConfig; +use apollo_consensus_config::config::ConsensusConfig; use apollo_network::network_manager::BroadcastTopicClientTrait; use apollo_network_types::network_types::BroadcastedMessageMetadata; use apollo_protobuf::consensus::{ProposalInit, Vote}; @@ -35,24 +34,18 @@ use crate::metrics::{ CONSENSUS_PROPOSALS_RECEIVED, }; use crate::single_height_consensus::{ShcReturn, SingleHeightConsensus}; -use crate::types::{BroadcastVoteChannel, ConsensusContext, ConsensusError, Decision, ValidatorId}; +use crate::types::{BroadcastVoteChannel, ConsensusContext, ConsensusError, Decision}; use crate::votes_threshold::QuorumType; /// Arguments for running consensus. #[derive(Clone, Debug)] pub struct RunConsensusArguments { + /// Consensus configuration (dynamic + static parameters). + pub consensus_config: ConsensusConfig, /// The height at which the node may participate in consensus (if it is a validator). pub start_active_height: BlockNumber, /// The height at which the node begins to run consensus. pub start_observe_height: BlockNumber, - /// The ID of this node. - pub validator_id: ValidatorId, - /// Delay before starting consensus; allowing the network to connect to peers. - pub consensus_delay: Duration, - /// The timeouts for the consensus algorithm. - pub timeouts: TimeoutsConfig, - /// The interval to wait between sync retries. - pub sync_retry_interval: Duration, /// Set to Byzantine by default. Using Honest means we trust all validators. Use with caution! pub quorum_type: QuorumType, } @@ -71,7 +64,11 @@ pub struct RunConsensusArguments { /// - `proposals_receiver`: The channel to receive proposals from the network. Proposals are /// represented as streams (ProposalInit, Content.*, ProposalFin). // Always print the validator ID since some tests collate multiple consensus logs in a single file. -#[instrument(skip_all, fields(validator_id=%run_consensus_args.validator_id), level = "error")] +#[instrument( + skip_all, + fields(validator_id=%run_consensus_args.consensus_config.dynamic_config.validator_id), + level = "error" +)] pub async fn run_consensus( run_consensus_args: RunConsensusArguments, mut context: ContextT, @@ -84,17 +81,15 @@ where info!("Running consensus, args: {:?}", run_consensus_args.clone()); register_metrics(); // Add a short delay to allow peers to connect and avoid "InsufficientPeers" error - tokio::time::sleep(run_consensus_args.consensus_delay).await; + tokio::time::sleep(run_consensus_args.consensus_config.static_config.startup_delay).await; // Ensure the node begins observing consensus no later than it becomes active. assert!(run_consensus_args.start_observe_height <= run_consensus_args.start_active_height); let mut current_height = run_consensus_args.start_observe_height; let mut manager = MultiHeightManager::new( - run_consensus_args.validator_id, - run_consensus_args.sync_retry_interval, + run_consensus_args.consensus_config.clone(), run_consensus_args.quorum_type, - run_consensus_args.timeouts, ); loop { let must_observer = current_height < run_consensus_args.start_active_height; @@ -114,7 +109,7 @@ where let round = decision.precommits[0].round; let proposer = context.proposer(current_height, round); - if proposer == run_consensus_args.validator_id { + if proposer == run_consensus_args.consensus_config.dynamic_config.validator_id { CONSENSUS_DECISIONS_REACHED_AS_PROPOSER.increment(1); } info!( @@ -149,30 +144,21 @@ type ProposalReceiverTuple = (ProposalInit, mpsc::Receiver); /// part of the single height consensus algorithm (e.g. messages from future heights). #[derive(Debug, Default)] struct MultiHeightManager { - validator_id: ValidatorId, + consensus_config: ConsensusConfig, future_votes: BTreeMap>, - sync_retry_interval: Duration, quorum_type: QuorumType, // Mapping: { Height : { Round : (Init, Receiver)}} cached_proposals: BTreeMap>>, - timeouts: TimeoutsConfig, } impl MultiHeightManager { /// Create a new consensus manager. - pub(crate) fn new( - validator_id: ValidatorId, - sync_retry_interval: Duration, - quorum_type: QuorumType, - timeouts: TimeoutsConfig, - ) -> Self { + pub(crate) fn new(consensus_config: ConsensusConfig, quorum_type: QuorumType) -> Self { Self { - validator_id, - sync_retry_interval, + consensus_config, quorum_type, future_votes: BTreeMap::new(), cached_proposals: BTreeMap::new(), - timeouts, } } @@ -252,7 +238,8 @@ impl MultiHeightManager { } let validators = context.validators(height).await; - let is_observer = must_observer || !validators.contains(&self.validator_id); + let is_observer = must_observer + || !validators.contains(&self.consensus_config.dynamic_config.validator_id); info!( "START_HEIGHT: running consensus for height {:?}. is_observer: {}, validators: {:?}", height, is_observer, validators, @@ -261,10 +248,10 @@ impl MultiHeightManager { let mut shc = SingleHeightConsensus::new( height, is_observer, - self.validator_id, + self.consensus_config.dynamic_config.validator_id, validators, self.quorum_type, - self.timeouts.clone(), + self.consensus_config.static_config.timeouts.clone(), ); let mut shc_events = FuturesUnordered::new(); @@ -281,7 +268,8 @@ impl MultiHeightManager { // Loop over incoming proposals, messages, and self generated events. let clock = DefaultClock; - let mut sync_poll_deadline = clock.now() + self.sync_retry_interval; + let sync_retry_interval = self.consensus_config.static_config.sync_retry_interval; + let mut sync_poll_deadline = clock.now() + sync_retry_interval; loop { self.report_max_cached_block_number_metric(height); let shc_return = tokio::select! { @@ -298,7 +286,7 @@ impl MultiHeightManager { // Using sleep_until to make sure that we won't restart the sleep due to other // events occuring. _ = sleep_until(sync_poll_deadline, &clock) => { - sync_poll_deadline += self.sync_retry_interval; + sync_poll_deadline += sync_retry_interval; if context.try_sync(height).await { return Ok(RunHeightRes::Sync); } diff --git a/crates/apollo_consensus/src/manager_test.rs b/crates/apollo_consensus/src/manager_test.rs index da1faf3c47b..e58d18fb17a 100644 --- a/crates/apollo_consensus/src/manager_test.rs +++ b/crates/apollo_consensus/src/manager_test.rs @@ -1,7 +1,12 @@ use std::time::Duration; use std::vec; -use apollo_consensus_config::config::TimeoutsConfig; +use apollo_consensus_config::config::{ + ConsensusConfig, + ConsensusDynamicConfig, + ConsensusStaticConfig, + TimeoutsConfig, +}; use apollo_network::network_manager::test_utils::{ mock_register_broadcast_topic, MockBroadcastedMessagesSender, @@ -107,12 +112,17 @@ async fn manager_multiple_heights_unordered() { context.expect_set_height_and_round().returning(move |_, _| ()); context.expect_broadcast().returning(move |_| Ok(())); - let mut manager = MultiHeightManager::new( - *VALIDATOR_ID, - SYNC_RETRY_INTERVAL, - QuorumType::Byzantine, - TIMEOUTS.clone(), + // TODO(Asmaa): Extract to a #[fixture] + let consensus_config = ConsensusConfig::from_parts( + ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, + ConsensusStaticConfig { + startup_delay: Duration::ZERO, + timeouts: TIMEOUTS.clone(), + sync_retry_interval: SYNC_RETRY_INTERVAL, + ..Default::default() + }, ); + let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let mut subscriber_channels = subscriber_channels.into(); let decision = manager .run_height( @@ -179,13 +189,19 @@ async fn run_consensus_sync() { let mut network_sender = mock_network.broadcasted_messages_sender; send(&mut network_sender, prevote(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; send(&mut network_sender, precommit(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; + let consensus_config = ConsensusConfig::from_parts( + ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, + ConsensusStaticConfig { + startup_delay: Duration::ZERO, + timeouts: TIMEOUTS.clone(), + sync_retry_interval: SYNC_RETRY_INTERVAL, + ..Default::default() + }, + ); let run_consensus_args = RunConsensusArguments { + consensus_config, start_active_height: BlockNumber(1), start_observe_height: BlockNumber(1), - validator_id: *VALIDATOR_ID, - consensus_delay: Duration::ZERO, - timeouts: TIMEOUTS.clone(), - sync_retry_interval: SYNC_RETRY_INTERVAL, quorum_type: QuorumType::Byzantine, }; // Start at height 1. @@ -243,12 +259,16 @@ async fn test_timeouts() { }); context.expect_broadcast().returning(move |_| Ok(())); - let mut manager = MultiHeightManager::new( - *VALIDATOR_ID, - SYNC_RETRY_INTERVAL, - QuorumType::Byzantine, - TIMEOUTS.clone(), + let consensus_config = ConsensusConfig::from_parts( + ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, + ConsensusStaticConfig { + startup_delay: Duration::ZERO, + timeouts: TIMEOUTS.clone(), + sync_retry_interval: SYNC_RETRY_INTERVAL, + ..Default::default() + }, ); + let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let manager_handle = tokio::spawn(async move { let decision = manager .run_height( @@ -304,12 +324,16 @@ async fn timely_message_handling() { // Fill up the buffer. while vote_sender.send((vote.clone(), metadata.clone())).now_or_never().is_some() {} - let mut manager = MultiHeightManager::new( - *VALIDATOR_ID, - SYNC_RETRY_INTERVAL, - QuorumType::Byzantine, - TIMEOUTS.clone(), + let consensus_config = ConsensusConfig::from_parts( + ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, + ConsensusStaticConfig { + startup_delay: Duration::ZERO, + timeouts: TIMEOUTS.clone(), + sync_retry_interval: SYNC_RETRY_INTERVAL, + ..Default::default() + }, ); + let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let res = manager .run_height( &mut context, diff --git a/crates/apollo_consensus_manager/src/consensus_manager.rs b/crates/apollo_consensus_manager/src/consensus_manager.rs index 27e7e7c500a..9d91e6c145c 100644 --- a/crates/apollo_consensus_manager/src/consensus_manager.rs +++ b/crates/apollo_consensus_manager/src/consensus_manager.rs @@ -263,16 +263,9 @@ impl ConsensusManager { QuorumType::Byzantine }; apollo_consensus::RunConsensusArguments { + consensus_config: self.config.consensus_manager_config.clone(), start_active_height: active_height, start_observe_height: observer_height, - validator_id: self.config.consensus_manager_config.dynamic_config.validator_id, - consensus_delay: self.config.consensus_manager_config.static_config.startup_delay, - timeouts: self.config.consensus_manager_config.static_config.timeouts.clone(), - sync_retry_interval: self - .config - .consensus_manager_config - .static_config - .sync_retry_interval, quorum_type, } } From 9cbf781d0026b17892d15398bfa11c510c495c3c Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:07:53 +0200 Subject: [PATCH 193/313] bench_tools: support deserialization of criterion change (#9698) --- crates/bench_tools/src/types/estimates.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/bench_tools/src/types/estimates.rs b/crates/bench_tools/src/types/estimates.rs index 62ea94836c5..62f7ba01530 100644 --- a/crates/bench_tools/src/types/estimates.rs +++ b/crates/bench_tools/src/types/estimates.rs @@ -1,29 +1,34 @@ use serde::Deserialize; /// Criterion benchmark estimates. -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Default)] #[allow(dead_code)] pub struct Estimates { pub mean: Stat, pub median: Stat, - pub std_dev: Stat, - pub median_abs_dev: Stat, + #[serde(default)] + pub std_dev: Option, + #[serde(default)] + pub median_abs_dev: Option, + #[serde(default)] pub slope: Option, } /// Statistical estimate with confidence interval. -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Default)] #[allow(dead_code)] pub struct Stat { pub point_estimate: f64, + #[serde(default)] pub standard_error: f64, pub confidence_interval: ConfidenceInterval, } /// Confidence interval bounds. -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Default)] #[allow(dead_code)] pub struct ConfidenceInterval { + #[serde(default)] pub confidence_level: f64, pub lower_bound: f64, pub upper_bound: f64, From d69f6e235f2947d7a1e56ac980e0863d2b065508 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 30 Oct 2025 11:19:17 +0200 Subject: [PATCH 194/313] apollo_integration_tests: add consts to anvil pre-funded accounts (#7784) (#9710) Easier to debug and to understand what these are, also explicit dependency on `AnvilInstance`, which will soon be hidden. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../apollo_integration_tests/src/flow_test_setup.rs | 7 ++++--- crates/papyrus_base_layer/src/test_utils.rs | 11 +++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/crates/apollo_integration_tests/src/flow_test_setup.rs b/crates/apollo_integration_tests/src/flow_test_setup.rs index ad1faf1c148..95b8c8de542 100644 --- a/crates/apollo_integration_tests/src/flow_test_setup.rs +++ b/crates/apollo_integration_tests/src/flow_test_setup.rs @@ -40,7 +40,8 @@ use papyrus_base_layer::test_utils::{ ethereum_base_layer_config_for_anvil, make_block_history_on_anvil, spawn_anvil_and_deploy_starknet_l1_contract, - DEFAULT_ANVIL_ADDITIONAL_ADDRESS_INDEX, + ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS, + OTHER_ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS, }; use starknet_api::block::BlockNumber; use starknet_api::consensus_transaction::ConsensusTransaction; @@ -127,8 +128,8 @@ impl FlowTestSetup { spawn_anvil_and_deploy_starknet_l1_contract(&base_layer_config, &base_layer_url).await; // Send some transactions to L1 so it has a history of blocks to scrape gas prices from. - let sender_address = anvil.addresses()[DEFAULT_ANVIL_ADDITIONAL_ADDRESS_INDEX]; - let receiver_address = anvil.addresses()[DEFAULT_ANVIL_ADDITIONAL_ADDRESS_INDEX + 1]; + let sender_address = ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS; + let receiver_address = OTHER_ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS; make_block_history_on_anvil( sender_address, receiver_address, diff --git a/crates/papyrus_base_layer/src/test_utils.rs b/crates/papyrus_base_layer/src/test_utils.rs index c52ef15a4a3..1869cea3689 100644 --- a/crates/papyrus_base_layer/src/test_utils.rs +++ b/crates/papyrus_base_layer/src/test_utils.rs @@ -3,7 +3,7 @@ use std::process::Command; use alloy::network::TransactionBuilder; use alloy::node_bindings::{Anvil, AnvilInstance, NodeError as AnvilError}; -use alloy::primitives::U256; +use alloy::primitives::{address as ethereum_address, U256}; use alloy::providers::Provider; use alloy::rpc::types::TransactionRequest; use colored::*; @@ -38,7 +38,14 @@ pub const DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS: &str = "0x5fbdb2315678afecb367f032d // Given an `AnvilInstance`, this address can be retrieved by calling `anvil.addresses()[0]`. pub const DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS: StarkHash = StarkHash::from_hex_unchecked("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); -pub const DEFAULT_ANVIL_ADDITIONAL_ADDRESS_INDEX: usize = 3; +/// One of the 10 pre-funded Anvil preloaded accounts. Retrieved by calling `anvil.addresses()[3]`. +// TODO(Gilad): consider moving into anvil base layer. +pub const ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS: EthereumContractAddress = + ethereum_address!("0x90F79bf6EB2c4f870365E785982E1f101E93b906"); +/// One of the 10 pre-funded Anvil preloaded accounts. Retrieved by calling `anvil.addresses()[4]`. +// TODO(Gilad): consider moving into anvil base layer. +pub const OTHER_ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS: EthereumContractAddress = + ethereum_address!("0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65"); // *** // DEPRECATED: Use the anvil constructor, this constructor is deprecated as it uses ganache. From b321dfff39a929f58b6c8e57495a5af1a2c12ba6 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:22:23 +0200 Subject: [PATCH 195/313] bench_tools: run and compare benchmark (#9699) --- crates/bench_tools/src/comparison.rs | 80 ++++++++++++++++++++++++++++ crates/bench_tools/src/lib.rs | 1 + crates/bench_tools/src/main.rs | 30 +++++++++++ crates/bench_tools/src/runner.rs | 44 +++++++++++++++ 4 files changed, 155 insertions(+) create mode 100644 crates/bench_tools/src/comparison.rs diff --git a/crates/bench_tools/src/comparison.rs b/crates/bench_tools/src/comparison.rs new file mode 100644 index 00000000000..9a8e5f2454f --- /dev/null +++ b/crates/bench_tools/src/comparison.rs @@ -0,0 +1,80 @@ +use std::fs; +use std::path::PathBuf; + +use crate::types::estimates::Estimates; + +/// Result of a benchmark comparison. +#[derive(Debug)] +pub struct BenchmarkComparison { + pub name: String, + pub change_percentage: f64, + pub exceeds_limit: bool, +} + +type RegressionError = (String, Vec); +type BenchmarkComparisonsResult = Result, RegressionError>; + +/// Loads change estimates from criterion's change directory for a given benchmark. +/// Panics if the change file doesn't exist. +fn load_change_estimates(bench_name: &str) -> Estimates { + let change_path = + PathBuf::from("target/criterion").join(bench_name).join("change/estimates.json"); + + if !change_path.exists() { + panic!( + "Change file not found for benchmark '{}': {}\nThis likely means no baseline exists. \ + Run the benchmark at least once before using run-and-compare.", + bench_name, + change_path.display() + ); + } + + let data = fs::read_to_string(&change_path) + .unwrap_or_else(|e| panic!("Failed to read {}: {}", change_path.display(), e)); + + serde_json::from_str(&data).unwrap_or_else(|e| { + panic!("Failed to deserialize {}: {}\nContent: {}", change_path.display(), e, data) + }) +} + +/// Converts change estimates to percentage. +/// The mean.point_estimate in change/estimates.json represents fractional change +/// (e.g., 0.0706 = 7.06% change). +pub(crate) fn get_regression_percentage(change_estimates: &Estimates) -> f64 { + change_estimates.mean.point_estimate * 100.0 +} + +/// Checks all benchmarks for regressions against a specified limit. +/// Returns a vector of comparison results for all benchmarks. +/// If any benchmark exceeds the regression limit, returns an error with detailed results. +/// Panics if change file is not found for any benchmark. +pub fn check_regressions( + bench_names: &[&str], + regression_limit: f64, +) -> BenchmarkComparisonsResult { + let mut results = Vec::new(); + let mut exceeded_count = 0; + + for bench_name in bench_names { + let change_estimates = load_change_estimates(bench_name); + let change_percentage = get_regression_percentage(&change_estimates); + let exceeds_limit = change_percentage > regression_limit; + + if exceeds_limit { + exceeded_count += 1; + } + + results.push(BenchmarkComparison { + name: bench_name.to_string(), + change_percentage, + exceeds_limit, + }); + } + + if exceeded_count > 0 { + let error_msg = format!("{} benchmark(s) exceeded regression threshold!", exceeded_count); + Err((error_msg, results)) + } else { + Ok(results) + } +} diff --git a/crates/bench_tools/src/lib.rs b/crates/bench_tools/src/lib.rs index 85dca4a6c0f..9fce6716173 100644 --- a/crates/bench_tools/src/lib.rs +++ b/crates/bench_tools/src/lib.rs @@ -1,5 +1,6 @@ #[cfg(test)] pub(crate) mod benches; +pub mod comparison; pub mod gcs; #[cfg(test)] pub mod gcs_test; diff --git a/crates/bench_tools/src/main.rs b/crates/bench_tools/src/main.rs index bda64a7e22e..ce38bb985c7 100644 --- a/crates/bench_tools/src/main.rs +++ b/crates/bench_tools/src/main.rs @@ -30,6 +30,22 @@ enum Commands { #[arg(long)] input_dir: Option, }, + /// Run benchmarks, compare to previous run, and fail if regression exceeds limit. + RunAndCompare { + /// Package name to run benchmarks for. + #[arg(short, long)] + package: String, + /// Output directory for results. + #[arg(short, long)] + out: String, + /// Optional: Local directory containing input files. If not provided, inputs will be + /// downloaded from GCS for benchmarks that require them. + #[arg(long)] + input_dir: Option, + /// Maximum acceptable regression percentage (e.g., 5.0 for 5%). + #[arg(long)] + regression_limit: f64, + }, /// List benchmarks for a package. List { /// Package name to list benchmarks for. If not provided, lists all benchmarks. @@ -59,6 +75,20 @@ fn main() { bench_tools::runner::run_benchmarks(&benchmarks, input_dir.as_deref(), &out); } + Commands::RunAndCompare { package, out, input_dir, regression_limit } => { + let benchmarks = find_benchmarks_by_package(&package); + + if benchmarks.is_empty() { + panic!("No benchmarks found for package: {}", package); + } + + bench_tools::runner::run_and_compare_benchmarks( + &benchmarks, + input_dir.as_deref(), + &out, + regression_limit, + ); + } Commands::List { package } => match package { Some(package_name) => { let benchmarks = find_benchmarks_by_package(&package_name); diff --git a/crates/bench_tools/src/runner.rs b/crates/bench_tools/src/runner.rs index 1a071e5071b..2526d4bfb91 100644 --- a/crates/bench_tools/src/runner.rs +++ b/crates/bench_tools/src/runner.rs @@ -106,3 +106,47 @@ pub fn run_benchmarks(benchmarks: &[&BenchmarkConfig], input_dir: Option<&str>, println!("\n✓ All benchmarks completed! Results saved to: {}", output_dir); } + +/// Runs benchmarks and compares them against previous results, failing if regression exceeds limit. +pub fn run_and_compare_benchmarks( + benchmarks: &[&BenchmarkConfig], + input_dir: Option<&str>, + output_dir: &str, + regression_limit: f64, +) { + // Run benchmarks first. + run_benchmarks(benchmarks, input_dir, output_dir); + + // Collect all criterion benchmark names from configs. + let mut bench_names = Vec::new(); + for bench in benchmarks { + bench_names.extend(bench.criterion_benchmark_names.unwrap_or(&[bench.name])); + } + + println!("\n📊 Checking for performance regressions (limit: {}%):", regression_limit); + let regression_result = crate::comparison::check_regressions(&bench_names, regression_limit); + + match regression_result { + Ok(_) => { + println!("\n✅ All benchmarks passed regression check!"); + } + Err((error_msg, results)) => { + // Some benchmarks exceeded the limit - print detailed results. + println!("\nBenchmark Results:"); + for result in results { + if result.exceeds_limit { + println!( + " ❌ {}: {:+.2}% (EXCEEDS {:.1}% limit)", + result.name, result.change_percentage, regression_limit + ); + } else { + println!( + " ✓ {}: {:+.2}% (within {:.1}% limit)", + result.name, result.change_percentage, regression_limit + ); + } + } + panic!("\n{}", error_msg); + } + } +} From 99612c174796466f004a0955dc3e04e8d9a31847 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 30 Oct 2025 12:23:51 +0200 Subject: [PATCH 196/313] apollo_integration_tests: use `AnvilBaseLayer` (#7785) (#9711) TODO: will soon make `send_message_to_l2` a method on `AnvilBaseLayer`, as it interacts directly with L1, thus it will no longer be necessary to interact with the internal starknet contract via `anvil.ethereum_base_layer_contract.contract`. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/flow_test_setup.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/crates/apollo_integration_tests/src/flow_test_setup.rs b/crates/apollo_integration_tests/src/flow_test_setup.rs index 95b8c8de542..0a50b4214da 100644 --- a/crates/apollo_integration_tests/src/flow_test_setup.rs +++ b/crates/apollo_integration_tests/src/flow_test_setup.rs @@ -2,7 +2,6 @@ use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; -use alloy::node_bindings::AnvilInstance; use apollo_consensus_manager_config::config::ConsensusManagerConfig; use apollo_http_server::test_utils::HttpTestClient; use apollo_http_server_config::config::HttpServerConfig; @@ -31,18 +30,17 @@ use mempool_test_utils::starknet_api_test_utils::{ AccountTransactionGenerator, MultiAccountTransactionGenerator, }; +use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; use papyrus_base_layer::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, L1ToL2MessageArgs, - StarknetL1Contract, }; use papyrus_base_layer::test_utils::{ - ethereum_base_layer_config_for_anvil, make_block_history_on_anvil, - spawn_anvil_and_deploy_starknet_l1_contract, ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS, OTHER_ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS, }; +use papyrus_base_layer::BaseLayerContract; use starknet_api::block::BlockNumber; use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::core::{ChainId, ContractAddress}; @@ -78,10 +76,9 @@ pub struct FlowTestSetup { pub sequencer_0: FlowSequencerSetup, pub sequencer_1: FlowSequencerSetup, - // Handle for L1 server: the server is dropped when handle is dropped. - #[allow(dead_code)] - l1_handle: AnvilInstance, - starknet_l1_contract: StarknetL1Contract, + // Ethereum base layer coupled with an Anvil server instance, the server is dropped when the + // instance is dropped. + pub anvil_base_layer: AnvilBaseLayer, // The transactions that were streamed in the consensus proposals, used for asserting the right // transactions are batched. @@ -122,10 +119,9 @@ impl FlowTestSetup { .try_into() .unwrap(); - let (base_layer_config, base_layer_url) = - ethereum_base_layer_config_for_anvil(Some(available_ports.get_next_port())); - let (anvil, starknet_l1_contract) = - spawn_anvil_and_deploy_starknet_l1_contract(&base_layer_config, &base_layer_url).await; + let anvil_base_layer = AnvilBaseLayer::new().await; + let base_layer_url = anvil_base_layer.get_url().await.unwrap(); + let base_layer_config = anvil_base_layer.ethereum_base_layer.config.clone(); // Send some transactions to L1 so it has a history of blocks to scrape gas prices from. let sender_address = ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS; @@ -181,7 +177,7 @@ impl FlowTestSetup { ) .await; - Self { sequencer_0, sequencer_1, l1_handle: anvil, starknet_l1_contract, accumulated_txs } + Self { sequencer_0, sequencer_1, anvil_base_layer, accumulated_txs } } pub fn chain_id(&self) -> &ChainId { @@ -199,7 +195,11 @@ impl FlowTestSetup { pub async fn send_messages_to_l2(&self, l1_to_l2_messages_args: &[L1ToL2MessageArgs]) { for l1_to_l2_message_args in l1_to_l2_messages_args { - self.starknet_l1_contract.send_message_to_l2(l1_to_l2_message_args).await; + self.anvil_base_layer + .ethereum_base_layer + .contract + .send_message_to_l2(l1_to_l2_message_args) + .await; } } } From 1509bb600fd62643ba05be6d1e1ff8835bad261b Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 30 Oct 2025 13:49:24 +0200 Subject: [PATCH 197/313] apollo_integration_tests: use `AnvilBaseLayer` in integration test (#7786) (#9712) Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/integration_test_manager.rs | 68 +++++-------------- .../src/anvil_base_layer.rs | 18 +++-- crates/papyrus_base_layer/src/test_utils.rs | 3 + 3 files changed, 33 insertions(+), 56 deletions(-) diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index 56e2db85908..f04b655ecc1 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -5,7 +5,6 @@ use std::panic; use std::path::PathBuf; use std::time::Duration; -use alloy::node_bindings::AnvilInstance; use apollo_http_server::test_utils::HttpTestClient; use apollo_http_server_config::config::HttpServerConfig; use apollo_infra_utils::dumping::serialize_to_file; @@ -30,15 +29,9 @@ use mempool_test_utils::starknet_api_test_utils::{ AccountId, MultiAccountTransactionGenerator, }; -use papyrus_base_layer::ethereum_base_layer_contract::{ - EthereumBaseLayerConfig, - StarknetL1Contract, -}; -use papyrus_base_layer::test_utils::{ - anvil_mine_blocks, - ethereum_base_layer_config_for_anvil, - spawn_anvil_and_deploy_starknet_l1_contract, -}; +use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; +use papyrus_base_layer::test_utils::anvil_mine_blocks; +use papyrus_base_layer::BaseLayerContract; use starknet_api::block::BlockNumber; use starknet_api::core::{ChainId, Nonce}; use starknet_api::execution_resources::GasAmount; @@ -48,7 +41,6 @@ use starknet_api::transaction::TransactionHash; use tokio::join; use tokio_util::task::AbortOnDropHandle; use tracing::{info, instrument}; -use url::Url; use crate::executable_setup::{ExecutableSetup, NodeExecutionId}; use crate::monitoring_utils::{ @@ -259,10 +251,9 @@ pub struct IntegrationTestManager { idle_nodes: HashMap, running_nodes: HashMap, tx_generator: MultiAccountTransactionGenerator, - // Handle for L1 server: the server is dropped when handle is dropped. - #[allow(dead_code)] - l1_handle: AnvilInstance, - starknet_l1_contract: StarknetL1Contract, + // Ethereum base layer coupled with an Anvil server instance, the server is dropped when the + // instance is dropped. + anvil_base_layer: AnvilBaseLayer, } impl IntegrationTestManager { @@ -285,27 +276,6 @@ impl IntegrationTestManager { ) .await; - fn get_base_layer_config(sequencers_setup: &NodeSetup) -> (EthereumBaseLayerConfig, Url) { - // TODO(Tsabary): the pattern of iterating over executables to find the relevant config - // should be unified and improved, throughout. - for executable_setup in &sequencers_setup.executables { - // Must find both base layer config and url in the same executable, then return - // them. - if let Some(config) = &executable_setup.get_config().base_layer_config { - let base_layer_config = config; - if let Some(l1_monitor_config) = - &executable_setup.get_config().l1_endpoint_monitor_config - { - let base_layer_url = l1_monitor_config.ordered_l1_endpoint_urls[0].clone(); - return (base_layer_config.clone(), base_layer_url); - } - } - } - unreachable!("No executable with a set base layer config.") - } - let (base_layer_config, base_layer_url) = - get_base_layer_config(sequencers_setup.first().unwrap()); - // TODO(Tsabary): these should be functions of `NodeSetup`. fn get_l1_gas_price_scraper_config( sequencers_setup: &NodeSetup, @@ -323,8 +293,7 @@ impl IntegrationTestManager { let l1_gas_price_scraper_config = get_l1_gas_price_scraper_config(sequencers_setup.first().unwrap()); - let (anvil, starknet_l1_contract) = - spawn_anvil_and_deploy_starknet_l1_contract(&base_layer_config, &base_layer_url).await; + let anvil_base_layer = AnvilBaseLayer::new().await; // Send some transactions to L1 so it has a history of blocks to scrape gas prices from. let num_blocks_needed_on_l1 = l1_gas_price_scraper_config.number_of_blocks_for_mean + l1_gas_price_scraper_config.finality; @@ -336,20 +305,17 @@ impl IntegrationTestManager { MIN_EXPECTED_BLOCK_NUMBER ); - anvil_mine_blocks(base_layer_config.clone(), MIN_EXPECTED_BLOCK_NUMBER, &base_layer_url) - .await; + anvil_mine_blocks( + anvil_base_layer.ethereum_base_layer.config.clone(), + MIN_EXPECTED_BLOCK_NUMBER, + &anvil_base_layer.get_url().await.expect("Failed to get anvil url."), + ) + .await; let idle_nodes = create_map(sequencers_setup, |node| node.get_node_index()); let running_nodes = HashMap::new(); - Self { - node_indices, - idle_nodes, - running_nodes, - tx_generator, - l1_handle: anvil, - starknet_l1_contract, - } + Self { node_indices, idle_nodes, running_nodes, tx_generator, anvil_base_layer } } pub fn get_idle_nodes(&self) -> &HashMap { @@ -707,7 +673,7 @@ impl IntegrationTestManager { let send_l1_handler_tx_fn = &mut |l1_handler_tx| { send_message_to_l2_and_calculate_tx_hash( l1_handler_tx, - &self.starknet_l1_contract, + &self.anvil_base_layer.ethereum_base_layer.contract, &chain_id, ) }; @@ -922,8 +888,8 @@ async fn get_sequencer_setup_configs( let mut base_layer_ports = available_ports_generator .next() .expect("Failed to get an AvailablePorts instance for base layer config"); - let (base_layer_config, base_layer_url) = - ethereum_base_layer_config_for_anvil(Some(base_layer_ports.get_next_port())); + let base_layer_config = AnvilBaseLayer::config(); + let base_layer_url = AnvilBaseLayer::url(); let mut nodes = Vec::new(); diff --git a/crates/papyrus_base_layer/src/anvil_base_layer.rs b/crates/papyrus_base_layer/src/anvil_base_layer.rs index 5ab670ea40d..b35b1e19cde 100644 --- a/crates/papyrus_base_layer/src/anvil_base_layer.rs +++ b/crates/papyrus_base_layer/src/anvil_base_layer.rs @@ -58,11 +58,8 @@ impl AnvilBaseLayer { Starknet::deploy(anvil_client.clone()).await.unwrap(); - let url: Url = format!("http://127.0.0.1:{}", Self::DEFAULT_ANVIL_PORT).parse().unwrap(); - let config = EthereumBaseLayerConfig { - starknet_contract_address: Self::DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS.parse().unwrap(), - ..Default::default() - }; + let config = Self::config(); + let url = Self::url(); let root_client = anvil_client.root().clone(); let contract = Starknet::new(config.starknet_contract_address, root_client); @@ -71,6 +68,17 @@ impl AnvilBaseLayer { ethereum_base_layer: EthereumBaseLayerContract { config, contract, url }, } } + + pub fn url() -> Url { + format!("http://127.0.0.1:{}", Self::DEFAULT_ANVIL_PORT).parse().unwrap() + } + + pub fn config() -> EthereumBaseLayerConfig { + EthereumBaseLayerConfig { + starknet_contract_address: Self::DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS.parse().unwrap(), + ..Default::default() + } + } } #[async_trait] diff --git a/crates/papyrus_base_layer/src/test_utils.rs b/crates/papyrus_base_layer/src/test_utils.rs index 1869cea3689..cdd2530dc4e 100644 --- a/crates/papyrus_base_layer/src/test_utils.rs +++ b/crates/papyrus_base_layer/src/test_utils.rs @@ -165,6 +165,9 @@ pub async fn deploy_starknet_l1_contract( Starknet::deploy(ethereum_base_layer_contract.contract.provider().clone()).await.unwrap() } +// FIXME: This should be part of AnvilBaseLayer, however the usage in the simulator doesn't allow +// that, since it is coupled with a manual invocation of an anvil instance that is managed inside +// the github workflow. pub async fn make_block_history_on_anvil( sender_address: EthereumContractAddress, receiver_address: EthereumContractAddress, From 6c3c7c93258e32d8b3cfd3bc61c7baa38764fddd Mon Sep 17 00:00:00 2001 From: einat-starkware Date: Thu, 30 Oct 2025 13:56:38 +0200 Subject: [PATCH 198/313] starknet_os: add opcode_instances to OS metrics (#9853) --- crates/starknet_committer_and_os_cli/src/os_cli/run_os_cli.rs | 3 +++ crates/starknet_os/src/metrics.rs | 3 +++ crates/starknet_os/src/opcode_instances.rs | 2 ++ crates/starknet_os/src/runner.rs | 1 + 4 files changed, 9 insertions(+) diff --git a/crates/starknet_committer_and_os_cli/src/os_cli/run_os_cli.rs b/crates/starknet_committer_and_os_cli/src/os_cli/run_os_cli.rs index 343f5bf960f..eed838a00f9 100644 --- a/crates/starknet_committer_and_os_cli/src/os_cli/run_os_cli.rs +++ b/crates/starknet_committer_and_os_cli/src/os_cli/run_os_cli.rs @@ -9,6 +9,7 @@ use serde::Serialize; use starknet_os::hint_processor::os_logger::OsTransactionTrace; use starknet_os::hints::enum_definition::AllHints; use starknet_os::metrics::{AggregatorMetrics, OsMetrics, ProgramRunInfo}; +use starknet_os::opcode_instances::OpcodeInstanceCounts; use starknet_types_core::felt::Felt; use tracing::info; use tracing::level_filters::LevelFilter; @@ -135,6 +136,7 @@ pub(crate) struct OsCliMetrics { pub deprecated_syscall_usages: Vec, pub run_info: OsCliRunInfo, pub execution_resources: ExecutionResources, + pub opcode_instances: OpcodeInstanceCounts, } impl From for OsCliMetrics { @@ -144,6 +146,7 @@ impl From for OsCliMetrics { deprecated_syscall_usages: metrics.deprecated_syscall_usages, run_info: metrics.run_info.into(), execution_resources: metrics.execution_resources, + opcode_instances: metrics.opcode_instances, } } } diff --git a/crates/starknet_os/src/metrics.rs b/crates/starknet_os/src/metrics.rs index ef359b25623..4680008ab54 100644 --- a/crates/starknet_os/src/metrics.rs +++ b/crates/starknet_os/src/metrics.rs @@ -6,6 +6,7 @@ use cairo_vm::vm::runners::cairo_runner::{CairoRunner, ExecutionResources}; use serde::Serialize; use crate::hint_processor::snos_hint_processor::SnosHintProcessor; +use crate::opcode_instances::{get_opcode_instances, OpcodeInstanceCounts}; #[derive(Debug, Serialize)] pub struct ProgramRunInfo { @@ -32,6 +33,7 @@ pub struct OsMetrics { pub deprecated_syscall_usages: Vec, pub run_info: ProgramRunInfo, pub execution_resources: ExecutionResources, + pub opcode_instances: OpcodeInstanceCounts, } #[derive(Debug, Serialize)] @@ -52,6 +54,7 @@ impl OsMetrics { .get_deprecated_syscall_usages(), run_info: ProgramRunInfo::new(runner), execution_resources: runner.get_execution_resources()?, + opcode_instances: get_opcode_instances(runner), }) } } diff --git a/crates/starknet_os/src/opcode_instances.rs b/crates/starknet_os/src/opcode_instances.rs index 300c2d77a8e..d8bdd16c860 100644 --- a/crates/starknet_os/src/opcode_instances.rs +++ b/crates/starknet_os/src/opcode_instances.rs @@ -1,5 +1,6 @@ use cairo_vm::types::relocatable::MaybeRelocatable; use cairo_vm::vm::runners::cairo_runner::CairoRunner; +use serde::Serialize; use starknet_types_core::felt::Felt; fn instruction_to_u128(felt: &Felt) -> Result { @@ -18,6 +19,7 @@ enum OpcodeExt { Unknown, } +#[derive(Debug, Serialize)] pub struct OpcodeInstanceCounts { pub blake_opcode_count: usize, } diff --git a/crates/starknet_os/src/runner.rs b/crates/starknet_os/src/runner.rs index 4cbf7091bab..0ca20f44e71 100644 --- a/crates/starknet_os/src/runner.rs +++ b/crates/starknet_os/src/runner.rs @@ -51,6 +51,7 @@ fn run_program<'a, HP: HintProcessor + CommonHintProcessor<'a>>( hint_processor: &mut HP, ) -> Result { // Init CairoRunConfig. + // TODO(Einat): Set trace_enabled to false once blake opcodes are counted in the VM. let cairo_run_config = CairoRunConfig { layout, relocate_mem: true, trace_enabled: true, ..Default::default() }; let allow_missing_builtins = cairo_run_config.allow_missing_builtins.unwrap_or(false); From d18bc01895e766161e5e2fc505e4ef64c2047e97 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:16:05 +0200 Subject: [PATCH 199/313] bench_tools: fix committer benchmark config (#9807) --- crates/bench_tools/src/types/benchmark_config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bench_tools/src/types/benchmark_config.rs b/crates/bench_tools/src/types/benchmark_config.rs index 020f196a4d4..4b12aa70804 100644 --- a/crates/bench_tools/src/types/benchmark_config.rs +++ b/crates/bench_tools/src/types/benchmark_config.rs @@ -37,9 +37,9 @@ pub const BENCHMARKS: &[BenchmarkConfig] = &[ BenchmarkConfig { name: "single_tree_flow", package: "starknet_committer_and_os_cli", - cmd_args: &["bench", "-p", "starknet_committer_and_os_cli", "single_tree_flow"], + cmd_args: &["bench", "-p", "starknet_committer_and_os_cli", "tree_computation_flow"], input_dir: Some("crates/starknet_committer_and_os_cli/test_inputs"), - criterion_benchmark_names: None, // Single benchmark with same name. + criterion_benchmark_names: Some(&["tree_computation_flow"]), }, BenchmarkConfig { name: "gateway_apply_block", From cf045b9a1925fac4fc7498f3288f0794cc47b46c Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:52:13 +0200 Subject: [PATCH 200/313] ci: use benchtools to benchmark the committer (#9707) --- .github/workflows/committer_ci.yml | 82 ++++-------------------------- 1 file changed, 11 insertions(+), 71 deletions(-) diff --git a/.github/workflows/committer_ci.yml b/.github/workflows/committer_ci.yml index beb628b9358..7228f13c48d 100644 --- a/.github/workflows/committer_ci.yml +++ b/.github/workflows/committer_ci.yml @@ -66,7 +66,7 @@ jobs: runs-on: namespace-profile-medium-ubuntu-24-04-amd64 if: ${{ github.event_name == 'pull_request' }} steps: - # Checkout the base branch to get the old code. + # Checkout the base branch to benchmark the old code. - uses: actions/checkout@v4 with: ref: ${{ github.base_ref }} @@ -88,87 +88,27 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} - # Download the old benchmark inputs. + # Auth with GCS for bench_tools to download inputs. - id: auth uses: "google-github-actions/auth@v2" with: credentials_json: ${{ secrets.COMMITER_PRODUCTS_EXT_WRITER_JSON }} - uses: "google-github-actions/setup-gcloud@v2" - - run: echo "OLD_BENCH_INPUT_FILES_PREFIX=$(cat ./crates/starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix)" >> $GITHUB_ENV - - run: gcloud storage cp -r gs://committer-testing-artifacts/$OLD_BENCH_INPUT_FILES_PREFIX/* ./crates/starknet_committer_and_os_cli/test_inputs - # List the existing benchmarks. - - run: | - cargo bench -p starknet_committer_and_os_cli -- --list | grep ': benchmark$' | sed -e "s/: benchmark$//" > benchmarks_list.txt + # Benchmark the base branch code. + - run: cargo run -p bench_tools -- run --package starknet_committer_and_os_cli --out /tmp/base_results - # Benchmark the old code. - - run: cargo bench -p starknet_committer_and_os_cli + # Save the input files from the base branch to use in the second benchmark. + - run: cp -r crates/starknet_committer_and_os_cli/test_inputs /tmp/test_inputs - # Backup the downloaded files to avoid re-downloading them if they didn't change (overwritten by checkout). - - run: mv ./crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json ./crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json_bu - - run: mv ./crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json ./crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json_bu - - # Checkout the new code. + # Checkout the current branch to benchmark the new code. - uses: actions/checkout@v4 with: clean: false - - run: echo "NEW_BENCH_INPUT_FILES_PREFIX=$(cat ./crates/starknet_committer_and_os_cli/src/committer_cli/tests/flow_test_files_prefix)" >> $GITHUB_ENV - # If the pip requirements on the old commit are different from the new commit, re-install them. + # Re-install pip requirements in case they changed between branches. - run: pip install -r scripts/requirements.txt - # Input files didn't change. - - if: env.OLD_BENCH_INPUT_FILES_PREFIX == env.NEW_BENCH_INPUT_FILES_PREFIX - run: | - mv ./crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json_bu ./crates/starknet_committer_and_os_cli/test_inputs/tree_flow_inputs.json - mv ./crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json_bu ./crates/starknet_committer_and_os_cli/test_inputs/committer_flow_inputs.json - - # Input files did change, download new inputs. - - if: env.OLD_BENCH_INPUT_FILES_PREFIX != env.NEW_BENCH_INPUT_FILES_PREFIX - run: | - gcloud storage cp -r gs://committer-testing-artifacts/$NEW_BENCH_INPUT_FILES_PREFIX/* ./crates/starknet_committer_and_os_cli/test_inputs - - # Benchmark the new code, splitting the benchmarks, and prepare the results for posting a comment. - - run: bash ./crates/starknet_committer_and_os_cli/benches/bench_split_and_prepare_post.sh benchmarks_list.txt benchmark_comment_body.txt - - - run: echo BENCHES_RESULT=$(cat benchmark_comment_body.txt) >> $GITHUB_ENV - - # Comment with a link to the workflow (or update existing comment on rerun). - - name: Find Comment - if: github.event_name == 'pull_request' - uses: starkware-libs/find-comment@v3 - id: find-benchmark-comment - with: - token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ github.event.pull_request.number }} - comment-author: "github-actions[bot]" - body-includes: Benchmark movements - - - name: Create comment - # If the PR number is found and the comment is not found, create a new comment. - if: github.event_name == 'pull_request' - && steps.find-benchmark-comment.outputs.comment-id == '' - uses: starkware-libs/create-or-update-comment@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ github.event.pull_request.number }} - body: ${{ env.BENCHES_RESULT }} - - - name: Update comment - # If the PR number is found and the comment exists, update it. - if: github.event_name == 'pull_request' - && steps.find-benchmark-comment.outputs.comment-id != '' - uses: starkware-libs/create-or-update-comment@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - comment-id: ${{ steps.find-benchmark-comment.outputs.comment-id }} - edit-mode: replace - body: ${{ env.BENCHES_RESULT }} - - # Fail the job if benchmarks exceeded the threshold (after posting the comment). - - name: Check benchmark results - run: | - if grep -q "CI WILL FAIL" benchmark_comment_body.txt; then - echo "Benchmarks exceeded the regression threshold. See the PR comment for details." - exit 1 - fi + # Benchmark the current branch and compare to the previous run. + # Use the saved inputs. + - run: cargo run -p bench_tools -- run-and-compare --package starknet_committer_and_os_cli --out /tmp/new_results --regression-limit 8.0 --input-dir /tmp/test_inputs From e536918775e43152a308ff79555e8e19df177694 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:04:46 +0200 Subject: [PATCH 201/313] blockifier: fix transfer bechmark (#9741) --- crates/blockifier/benches/main.rs | 30 +++- .../src/test_utils/transfers_generator.rs | 157 ++++++++++++------ 2 files changed, 132 insertions(+), 55 deletions(-) diff --git a/crates/blockifier/benches/main.rs b/crates/blockifier/benches/main.rs index cc7c3be5ec3..c0a76867277 100644 --- a/crates/blockifier/benches/main.rs +++ b/crates/blockifier/benches/main.rs @@ -18,13 +18,17 @@ use blockifier::test_utils::transfers_generator::{ }; #[cfg(feature = "cairo_native")] use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; // TODO(Arni): Consider how to run this benchmark both with and without setting the allocator. Maybe // hide this macro call under a feature, and run this benchmark regularly or with // `cargo bench --bench blockifier --feature=specified_allocator` set_global_allocator!(); +/// Benchmarks the execution phase of the transfers flow. +/// The sender account is chosen round-robin. +/// The recipient account is chosen randomly. +/// The transactions are executed concurrently. pub fn transfers_benchmark(c: &mut Criterion) { let transfers_generator_config = TransfersGeneratorConfig { recipient_generator_type: RecipientGeneratorType::Random, @@ -33,14 +37,26 @@ pub fn transfers_benchmark(c: &mut Criterion) { ..Default::default() }; let mut transfers_generator = TransfersGenerator::new(transfers_generator_config); - // Create a benchmark group called "transfers", which iterates over the accounts round-robin - // and performs transfers. + // Benchmark only the execution phase (run_block_of_transfers call). + // Transaction generation and state setup happen for each iteration but are not timed. c.bench_function("transfers", |benchmark| { - benchmark.iter(|| { - transfers_generator.execute_block_of_transfers(None); - }) + benchmark.iter_batched( + || { + // Setup: prepare transactions and executor (not measured). + transfers_generator.prepare_to_run_block_of_transfers(None) + }, + |(txs, mut executor_wrapper)| { + // Measured: execute the transactions. + TransfersGenerator::run_block_of_transfers(&txs, &mut executor_wrapper, None) + }, + BatchSize::SmallInput, + ) }); } -criterion_group!(benches, transfers_benchmark); +criterion_group! { + name = benches; + config = Criterion::default().sample_size(50); + targets = transfers_benchmark +} criterion_main!(benches); diff --git a/crates/blockifier/src/test_utils/transfers_generator.rs b/crates/blockifier/src/test_utils/transfers_generator.rs index 14b3c8c7191..03a1c87c249 100644 --- a/crates/blockifier/src/test_utils/transfers_generator.rs +++ b/crates/blockifier/src/test_utils/transfers_generator.rs @@ -22,12 +22,12 @@ use crate::blockifier::config::{ConcurrencyConfig, TransactionExecutorConfig}; use crate::blockifier::transaction_executor::{ BlockExecutionSummary, TransactionExecutor, - TransactionExecutorError, DEFAULT_STACK_SIZE, }; use crate::concurrency::worker_pool::WorkerPool; use crate::context::{BlockContext, ChainInfo}; -use crate::state::cached_state::StateMaps; +use crate::state::cached_state::CachedState; +use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::{RunnableCairo1, BALANCE}; use crate::transaction::account_transaction::AccountTransaction; @@ -87,6 +87,16 @@ pub struct TransfersGenerator { config: TransfersGeneratorConfig, } +/// Enum to wrap both executor types for unified handling. +#[allow(clippy::large_enum_variant)] +pub enum ExecutorWrapper { + Concurrent( + ConcurrentTransactionExecutor, + Arc>>, + ), + Sequential(TransactionExecutor), +} + impl TransfersGenerator { pub fn new(config: TransfersGeneratorConfig) -> Self { let account_contract = FeatureContract::AccountWithoutValidations(config.cairo_version); @@ -161,15 +171,28 @@ impl TransfersGenerator { } } - #[allow(clippy::type_complexity)] - fn _run_txs( - &self, - txs: Vec, - execution_deadline: Option, - ) -> ( - Vec>, - BlockExecutionSummary, - ) { + /// Prepares transactions and executor for running a block. + /// Returns the transactions and the executor wrapper. + pub fn prepare_to_run_block_of_transfers( + &mut self, + timeout: Option, + ) -> (Vec, ExecutorWrapper) { + // Reset nonce manager since we create a fresh state. + self.nonce_manager = NonceManager::default(); + + // Generate transactions + let mut txs: Vec = Vec::with_capacity(self.config.n_txs); + for _ in 0..self.config.n_txs { + let sender_address = self.account_addresses[self.sender_index]; + let recipient_address = self.get_next_recipient(); + self.sender_index = (self.sender_index + 1) % self.account_addresses.len(); + + let tx = self.generate_transfer(sender_address, recipient_address); + let account_tx = AccountTransaction::new_for_sequencing(tx); + txs.push(Transaction::Account(account_tx)); + } + + let execution_deadline = timeout.map(|timeout_duration| Instant::now() + timeout_duration); let state = test_state( &self.chain_info, self.config.balance, @@ -180,32 +203,81 @@ impl TransfersGenerator { stack_size: self.config.stack_size, }; - if executor_config.concurrency_config.enabled { + let executor_wrapper = if executor_config.concurrency_config.enabled { let worker_pool = Arc::new(WorkerPool::start(&executor_config.get_worker_pool_config())); - let mut executor = ConcurrentTransactionExecutor::new_for_testing( + let executor = ConcurrentTransactionExecutor::new_for_testing( state, self.block_context.clone(), worker_pool.clone(), execution_deadline, ); + ExecutorWrapper::Concurrent(executor, worker_pool) + } else { + let executor = + TransactionExecutor::new(state, self.block_context.clone(), executor_config); + ExecutorWrapper::Sequential(executor) + }; - let results = executor.add_txs_and_wait(&txs); - let block_summary = executor.close_block(results.len()).unwrap(); + (txs, executor_wrapper) + } - drop(executor); - Arc::try_unwrap(worker_pool) - .expect("More than one instance of worker pool exists") - .join(); + /// Runs the prepared transactions on the executor. + /// Asserts that none of the transactions reverted. + /// Returns the execution results. + pub fn run_block_of_transfers( + txs: &[Transaction], + executor_wrapper: &mut ExecutorWrapper, + execution_deadline: Option, + ) -> Vec { + let results = match executor_wrapper { + ExecutorWrapper::Concurrent(ref mut executor, _) => executor.add_txs_and_wait(txs), + ExecutorWrapper::Sequential(ref mut executor) => { + executor.execute_txs(txs, execution_deadline) + } + }; - (results, block_summary) - } else { - let mut executor = - TransactionExecutor::new(state, self.block_context.clone(), executor_config); - let results = executor.execute_txs(&txs, execution_deadline); - (results, executor.finalize().unwrap()) + // Extract execution infos and validate that no transactions reverted. + results + .into_iter() + .map(|result| { + let (execution_info, _state_maps) = result.unwrap(); + assert!(!execution_info.is_reverted()); + execution_info + }) + .collect() + } + + /// Finalizes the executor and validates native execution of the transactions. + /// Returns the block execution summary and execution infos. + pub fn summarize_run_block_of_transfers( + executor_wrapper: ExecutorWrapper, + execution_infos: Vec, + cairo_version: CairoVersion, + ) -> (BlockExecutionSummary, Vec) { + // Finalize executor and get block summary. + let block_summary = match executor_wrapper { + ExecutorWrapper::Concurrent(mut executor, worker_pool) => { + let block_summary = executor.close_block(execution_infos.len()).unwrap(); + + drop(executor); + Arc::try_unwrap(worker_pool) + .expect("More than one instance of worker pool exists") + .join(); + + block_summary + } + ExecutorWrapper::Sequential(mut executor) => executor.finalize().unwrap(), + }; + + // Validate native execution. + let expected_cairo_native = cairo_version.is_cairo_native(); + for execution_info in &execution_infos { + execution_info.check_call_infos_native_execution(expected_cairo_native); } + + (block_summary, execution_infos) } /// Generates and executes transfer transactions. @@ -214,31 +286,20 @@ impl TransfersGenerator { &mut self, timeout: Option, ) -> (BlockExecutionSummary, Vec) { - let mut txs: Vec = Vec::with_capacity(self.config.n_txs); - for _ in 0..self.config.n_txs { - let sender_address = self.account_addresses[self.sender_index]; - let recipient_address = self.get_next_recipient(); - self.sender_index = (self.sender_index + 1) % self.account_addresses.len(); - - let tx = self.generate_transfer(sender_address, recipient_address); - let account_tx = AccountTransaction::new_for_sequencing(tx); - txs.push(Transaction::Account(account_tx)); - } - let execution_deadline = timeout.map(|timeout| Instant::now() + timeout); - let (results, block_summary) = self._run_txs(txs, execution_deadline); - // Execution infos of transactions that were executed. - let mut collected_execution_infos = Vec::::new(); - for result in results { - let execution_info = &result.unwrap().0; + // Prepare: generates transactions and creates executor. + let (txs, mut executor_wrapper) = self.prepare_to_run_block_of_transfers(timeout); - assert!(!execution_info.is_reverted()); - - let expected_cairo_native = self.config.cairo_version.is_cairo_native(); - execution_info.check_call_infos_native_execution(expected_cairo_native); - collected_execution_infos.push(execution_info.clone()); - } + // Run: executes the transactions and asserts that none of them reverted. + let execution_deadline = timeout.map(|timeout_duration| Instant::now() + timeout_duration); + let execution_infos = + Self::run_block_of_transfers(&txs, &mut executor_wrapper, execution_deadline); - (block_summary, collected_execution_infos) + // Summarize: finalizes executor, and validates native execution (if applicable). + Self::summarize_run_block_of_transfers( + executor_wrapper, + execution_infos, + self.config.cairo_version, + ) // TODO(Avi, 01/06/2024): Run the same transactions concurrently on a new state and compare // the state diffs. From 63d8f923146a6fcf50b43b2c6aee62ec13d1ea04 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:08:22 +0200 Subject: [PATCH 202/313] apollo_rpc_execution: get compiled class hash v2 from class manager (#9869) --- .../apollo_rpc_execution/src/state_reader.rs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/apollo_rpc_execution/src/state_reader.rs b/crates/apollo_rpc_execution/src/state_reader.rs index 71f5180630e..c04ab12e86f 100644 --- a/crates/apollo_rpc_execution/src/state_reader.rs +++ b/crates/apollo_rpc_execution/src/state_reader.rs @@ -213,14 +213,20 @@ impl BlockifierStateReader for ExecutionStateReader { class_hash: ClassHash, _compiled_class: &RunnableCompiledClass, ) -> StateResult { - // Try to read the compiled class hash v2 from the dedicated stateless table. - // If it's missing (e.g., class not declared/Cairo0), return the default value. - let maybe_hash = self - .storage_reader - .begin_ro_txn() - .map_err(storage_err_to_state_err)? - .get_executable_class_hash_v2(&class_hash) - .map_err(storage_err_to_state_err)?; + let maybe_hash = + if let Some((class_manager_client, run_time_handle)) = &self.class_manager_handle { + // First, try getting from class manager if available. + run_time_handle + .block_on(class_manager_client.get_executable_class_hash_v2(class_hash)) + .map_err(|e| StateError::StateReadError(e.to_string()))? + } else { + // Fall back to reading from storage. + self.storage_reader + .begin_ro_txn() + .map_err(storage_err_to_state_err)? + .get_executable_class_hash_v2(&class_hash) + .map_err(storage_err_to_state_err)? + }; maybe_hash.ok_or(StateError::MissingCompiledClassHashV2(class_hash)) } From 6eff8b34f63721f72a623d03fbd770ad09e2ece4 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 30 Oct 2025 15:28:44 +0200 Subject: [PATCH 203/313] apollo_integration_tests: remove out of scope assertion in test (#7787) (#9713) * l1: use `AnvilBaseLayer` in integration test * l1: remove out of scope assertion in test No need to test this, it's testing Anvil, also isn't relevant to this test. --------- Co-authored-by: giladchase Co-authored-by: Gilad Chase --- crates/papyrus_base_layer/src/base_layer_test.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index 274794df7c2..a964741f159 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -138,18 +138,6 @@ async fn events_from_other_contract() { let _anvil = anvil_instance_from_url(&this_url); let this_contract = EthereumBaseLayerContract::new(this_config.clone(), this_url.clone()); - // Test: get_proved_block_at_unknown_block_number. - // TODO(Arni): turn this into a unit test, with its own anvil instance. - assert!( - this_contract - .get_proved_block_at(123) - .await - .unwrap_err() - // This error is nested way too deep inside `alloy`. - .to_string() - .contains("BlockOutOfRangeError") - ); - // Test: Get events from L1 contract and other instances of this L1 contract. // Setup. From a6ddef87e9e28a7be6e573a4d8742bfee80c069f Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:45:52 +0200 Subject: [PATCH 204/313] bench_tools: font capture output when running a benchmark (#9860) --- crates/bench_tools/src/runner.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bench_tools/src/runner.rs b/crates/bench_tools/src/runner.rs index 2526d4bfb91..bb3eb8e3348 100644 --- a/crates/bench_tools/src/runner.rs +++ b/crates/bench_tools/src/runner.rs @@ -48,13 +48,13 @@ fn prepare_inputs(bench: &BenchmarkConfig, input_dir: Option<&str>) { fn run_single_benchmark(bench: &BenchmarkConfig) { println!("Running: {}", bench.name); - let output = std::process::Command::new("cargo") + let status = std::process::Command::new("cargo") .args(bench.cmd_args) - .output() + .status() .unwrap_or_else(|e| panic!("Failed to execute {}: {}", bench.name, e)); - if !output.status.success() { - panic!("\nBenchmark {} failed:\n{}", bench.name, String::from_utf8_lossy(&output.stderr)); + if !status.success() { + panic!("\nBenchmark {} failed with exit code: {:?}", bench.name, status.code()); } } From 2648fe8027849ceba933dbae262312626dbcc607 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:47:29 +0200 Subject: [PATCH 205/313] blockifier: add migration state diff to bouncer state diff size (#9839) --- crates/blockifier/src/bouncer.rs | 11 +++++++++-- crates/blockifier/src/state/cached_state.rs | 10 +++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/crates/blockifier/src/bouncer.rs b/crates/blockifier/src/bouncer.rs index 0ed1ccdf258..44ae9959a08 100644 --- a/crates/blockifier/src/bouncer.rs +++ b/crates/blockifier/src/bouncer.rs @@ -322,7 +322,7 @@ impl CasmHashComputationData { /// Tracks which classes need migration from V1 to V2 compiled hashes and /// accumulates the estimated execution resources required to perform the migration. struct CasmHashMigrationData { - class_hashes_to_migrate: HashMap, + pub(crate) class_hashes_to_migrate: HashMap, resources: EstimatedExecutionResources, } @@ -859,6 +859,13 @@ pub fn get_tx_weights( executed_class_hashes, versioned_constants, )?; + // Total state changes keys are the sum of marginal state changes keys and the + // migration state changes. + let mut total_state_changes_keys = StateChangesKeys { + compiled_class_hash_keys: migration_data.class_hashes_to_migrate.keys().cloned().collect(), + ..Default::default() + }; + total_state_changes_keys.extend(state_changes_keys); let blake_opcode_gas = bouncer_config.blake_weight; @@ -903,7 +910,7 @@ pub fn get_tx_weights( l1_gas: message_starknet_l1gas, message_segment_length: message_resources.message_segment_length, n_events: tx_resources.starknet_resources.archival_data.event_summary.n_events, - state_diff_size: get_onchain_data_segment_length(&state_changes_keys.count()), + state_diff_size: get_onchain_data_segment_length(&total_state_changes_keys.count()), sierra_gas: total_sierra_gas, n_txs: 1, proving_gas: total_proving_gas, diff --git a/crates/blockifier/src/state/cached_state.rs b/crates/blockifier/src/state/cached_state.rs index cf19890c145..4baee6a22e8 100644 --- a/crates/blockifier/src/state/cached_state.rs +++ b/crates/blockifier/src/state/cached_state.rs @@ -637,13 +637,13 @@ impl From for CommitmentStateDiff { #[cfg_attr(any(feature = "testing", test), derive(Clone))] #[derive(Debug, Default, Eq, PartialEq)] pub struct StateChangesKeys { - nonce_keys: HashSet, - class_hash_keys: HashSet, - storage_keys: HashSet, - compiled_class_hash_keys: HashSet, + pub(crate) nonce_keys: HashSet, + pub(crate) class_hash_keys: HashSet, + pub(crate) storage_keys: HashSet, + pub(crate) compiled_class_hash_keys: HashSet, // Note: this field may not be consistent with the above keys; specifically, it may be // strictlly contained in them. For example, as a result of a `difference` operation. - modified_contracts: HashSet, + pub(crate) modified_contracts: HashSet, } impl StateChangesKeys { From 1cae54e647ad6454859567e6ec333fe21f5f15e9 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 30 Oct 2025 15:55:35 +0200 Subject: [PATCH 206/313] scripts: Remove (wrong) to_lower for service argument (#9824) --- scripts/prod/update_config_and_restart_nodes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index 0f0ccf1b609..6ef96b2f981 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -70,8 +70,6 @@ def service_type_converter(service_name: str) -> Service: if service_name.startswith("Service."): service_name = service_name[8:] - service_name = service_name.lower() - try: return Service[service_name] except KeyError: From 5cd17f3985d9e5173d4b12c30ebaf312ffce0f21 Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:15:02 +0200 Subject: [PATCH 207/313] apollo_consensus: enable dynamic consensus config between heights (#9766) --- Cargo.lock | 1 + crates/apollo_consensus/Cargo.toml | 2 + crates/apollo_consensus/src/manager.rs | 39 +++++++- crates/apollo_consensus/src/manager_test.rs | 95 +++++++++++++++++++ .../src/consensus_manager.rs | 1 + 5 files changed, 135 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca570498e86..e2ecab92fcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1161,6 +1161,7 @@ dependencies = [ name = "apollo_consensus" version = "0.16.0-rc.1" dependencies = [ + "apollo_config_manager_types", "apollo_consensus_config", "apollo_infra_utils", "apollo_metrics", diff --git a/crates/apollo_consensus/Cargo.toml b/crates/apollo_consensus/Cargo.toml index 429fe30bd74..da1559471e2 100644 --- a/crates/apollo_consensus/Cargo.toml +++ b/crates/apollo_consensus/Cargo.toml @@ -10,6 +10,7 @@ description = "Reach consensus for Starknet" testing = [] [dependencies] +apollo_config_manager_types.workspace = true apollo_consensus_config.workspace = true apollo_infra_utils.workspace = true apollo_metrics.workspace = true @@ -32,6 +33,7 @@ tokio = { workspace = true, features = ["sync"] } tracing.workspace = true [dev-dependencies] +apollo_config_manager_types = { workspace = true, features = ["testing"] } apollo_network = { workspace = true, features = ["testing"] } apollo_network_types = { workspace = true, features = ["testing"] } apollo_storage = { workspace = true, features = ["testing"] } diff --git a/crates/apollo_consensus/src/manager.rs b/crates/apollo_consensus/src/manager.rs index d6e500b95b3..73a46272199 100644 --- a/crates/apollo_consensus/src/manager.rs +++ b/crates/apollo_consensus/src/manager.rs @@ -11,7 +11,8 @@ mod manager_test; use std::collections::BTreeMap; -use apollo_consensus_config::config::ConsensusConfig; +use apollo_config_manager_types::communication::SharedConfigManagerClient; +use apollo_consensus_config::config::{ConsensusConfig, ConsensusDynamicConfig}; use apollo_network::network_manager::BroadcastTopicClientTrait; use apollo_network_types::network_types::BroadcastedMessageMetadata; use apollo_protobuf::consensus::{ProposalInit, Vote}; @@ -38,9 +39,10 @@ use crate::types::{BroadcastVoteChannel, ConsensusContext, ConsensusError, Decis use crate::votes_threshold::QuorumType; /// Arguments for running consensus. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct RunConsensusArguments { - /// Consensus configuration (dynamic + static parameters). + /// Consensus configuration (static + dynamic). Static fields are used directly; dynamic + /// fields are refreshed at height boundaries via `config_manager_client` when provided. pub consensus_config: ConsensusConfig, /// The height at which the node may participate in consensus (if it is a validator). pub start_active_height: BlockNumber, @@ -48,6 +50,20 @@ pub struct RunConsensusArguments { pub start_observe_height: BlockNumber, /// Set to Byzantine by default. Using Honest means we trust all validators. Use with caution! pub quorum_type: QuorumType, + /// Optional client for fetching dynamic consensus config between heights. + pub config_manager_client: Option, +} + +impl std::fmt::Debug for RunConsensusArguments { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RunConsensusArguments") + .field("start_active_height", &self.start_active_height) + .field("start_observe_height", &self.start_observe_height) + .field("dynamic_config", &self.consensus_config.dynamic_config) + .field("static_config", &self.consensus_config.static_config) + .field("quorum_type", &self.quorum_type) + .finish() + } } /// Run consensus indefinitely. @@ -92,6 +108,18 @@ where run_consensus_args.quorum_type, ); loop { + if let Some(client) = &run_consensus_args.config_manager_client { + match client.get_consensus_dynamic_config().await { + Ok(dynamic_cfg) => { + manager.set_dynamic_config(dynamic_cfg); + } + Err(e) => { + error!( + "get_consensus_dynamic_config failed: {e}. Using previous dynamic config." + ); + } + } + } let must_observer = current_height < run_consensus_args.start_active_height; match manager .run_height( @@ -162,6 +190,11 @@ impl MultiHeightManager { } } + /// Apply the full dynamic consensus configuration. Call only between heights. + pub(crate) fn set_dynamic_config(&mut self, cfg: ConsensusDynamicConfig) { + self.consensus_config.dynamic_config = cfg; + } + /// Run the consensus algorithm for a single height. /// /// A height of consensus ends either when the node learns of a decision, either by consensus diff --git a/crates/apollo_consensus/src/manager_test.rs b/crates/apollo_consensus/src/manager_test.rs index e58d18fb17a..d23c9acc375 100644 --- a/crates/apollo_consensus/src/manager_test.rs +++ b/crates/apollo_consensus/src/manager_test.rs @@ -1,6 +1,9 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; use std::time::Duration; use std::vec; +use apollo_config_manager_types::communication::MockConfigManagerClient; use apollo_consensus_config::config::{ ConsensusConfig, ConsensusDynamicConfig, @@ -203,6 +206,7 @@ async fn run_consensus_sync() { start_active_height: BlockNumber(1), start_observe_height: BlockNumber(1), quorum_type: QuorumType::Byzantine, + config_manager_client: None, }; // Start at height 1. tokio::spawn(async move { @@ -350,3 +354,94 @@ async fn timely_message_handling() { proposal_receiver_sender.try_send(mpsc::channel(1).1).unwrap(); assert!(vote_sender.send((vote.clone(), metadata.clone())).now_or_never().is_some()); } + +#[tokio::test] +async fn run_consensus_dynamic_client_updates_validator_between_heights() { + let TestSubscriberChannels { mock_network, subscriber_channels } = + mock_register_broadcast_topic().unwrap(); + // Keep a handle to the vote sender so the paired receiver stays alive. + let _vote_sender = mock_network.broadcasted_messages_sender; + let (_proposal_receiver_sender, proposal_receiver_receiver) = mpsc::channel(CHANNEL_SIZE); + + // Context with expectations: H1 we are the validator, learn height via sync; at H2 we are the + // proposer. + let mut context = MockTestContext::new(); + context.expect_set_height_and_round().returning(move |_, _| ()); + context.expect_validators().returning(move |h: BlockNumber| { + if h == BlockNumber(1) { vec![*VALIDATOR_ID] } else { vec![*PROPOSER_ID] } + }); + context.expect_proposer().returning(move |h: BlockNumber, _| { + if h == BlockNumber(1) { *VALIDATOR_ID } else { *PROPOSER_ID } + }); + context.expect_try_sync().withf(move |h| *h == BlockNumber(1)).times(1).returning(|_| true); + context.expect_try_sync().returning(|_| false); + context.expect_broadcast().returning(move |_| Ok(())); + + // In this test, build_proposal should be called only when the dynamic config returns that we + // are the proposer, which happens at H2. + context + .expect_build_proposal() + .withf(move |init, _| init.height == BlockNumber(2) && init.proposer == *PROPOSER_ID) + .returning(move |_, _| { + let (sender, receiver) = oneshot::channel(); + sender.send(ProposalCommitment(Felt::TWO)).unwrap(); + receiver + }) + .times(1); + // Expect a decision at height 2. + let (decision_tx, decision_rx) = oneshot::channel(); + context + .expect_decision_reached() + .withf(move |_, votes| votes.first().map(|v| v.height) == Some(2)) + .return_once(move |_, _| { + let _ = decision_tx.send(()); + Ok(()) + }) + .times(1); + + // Dynamic client mock: H1 -> VALIDATOR_ID, H2 -> PROPOSER_ID + let mut mock_client = MockConfigManagerClient::new(); + let call_count = Arc::new(AtomicUsize::new(0)); + let call_count_clone = Arc::clone(&call_count); + mock_client.expect_get_consensus_dynamic_config().times(2).returning(move || { + let n = call_count_clone.fetch_add(1, Ordering::SeqCst); + if n == 0 { + Ok(apollo_consensus_config::config::ConsensusDynamicConfig { + validator_id: *VALIDATOR_ID, + }) + } else { + Ok(apollo_consensus_config::config::ConsensusDynamicConfig { + validator_id: *PROPOSER_ID, + }) + } + }); + + let consensus_config = ConsensusConfig::from_parts( + ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, + ConsensusStaticConfig { + startup_delay: Duration::ZERO, + timeouts: TIMEOUTS.clone(), + sync_retry_interval: SYNC_RETRY_INTERVAL, + ..Default::default() + }, + ); + let run_consensus_args = RunConsensusArguments { + start_active_height: BlockNumber(1), + start_observe_height: BlockNumber(1), + consensus_config, + quorum_type: QuorumType::Byzantine, + config_manager_client: Some(Arc::new(mock_client)), + }; + + // Spawn consensus and wait for a decision at height 2. + tokio::spawn(async move { + run_consensus( + run_consensus_args, + context, + subscriber_channels.into(), + proposal_receiver_receiver, + ) + .await + }); + decision_rx.await.unwrap(); +} diff --git a/crates/apollo_consensus_manager/src/consensus_manager.rs b/crates/apollo_consensus_manager/src/consensus_manager.rs index 9d91e6c145c..479c965c52a 100644 --- a/crates/apollo_consensus_manager/src/consensus_manager.rs +++ b/crates/apollo_consensus_manager/src/consensus_manager.rs @@ -267,6 +267,7 @@ impl ConsensusManager { start_active_height: active_height, start_observe_height: observer_height, quorum_type, + config_manager_client: Some(Arc::clone(&self.config_manager_client)), } } From cae4263ec04d528e8f83d5d9361ff9b888a9c69c Mon Sep 17 00:00:00 2001 From: lev-starkware <155880815+lev-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:42:43 +0200 Subject: [PATCH 208/313] apollo_batcher: improve transaction execution result logging (#9864) --- crates/apollo_batcher/src/batcher.rs | 42 ++++++++++++++++++---------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/crates/apollo_batcher/src/batcher.rs b/crates/apollo_batcher/src/batcher.rs index 31e899bdfaa..6035e5339a0 100644 --- a/crates/apollo_batcher/src/batcher.rs +++ b/crates/apollo_batcher/src/batcher.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::fmt::Write; use std::sync::Arc; use apollo_batcher_config::config::BatcherConfig; @@ -924,25 +925,36 @@ fn log_txs_execution_result( proposal_id: ProposalId, result: &Result>, ) { - // Constructing log message. if let Ok(block_artifacts) = result { - let mut log_msg = format!( + let execution_infos = &block_artifacts.execution_data.execution_infos; + let rejected_hashes = &block_artifacts.execution_data.rejected_tx_hashes; + + // Estimate capacity: base message + (hash + status) per transaction + // TransactionHash is 66 chars (0x + 64 hex), status is ~12 chars, separator is 4 chars + // Total per transaction: ~82 chars + const CHARS_PER_TX: usize = 82; + const BASE_CAPACITY: usize = 80; // Base message length + let total_txs = execution_infos.len() + rejected_hashes.len(); + let estimated_capacity = BASE_CAPACITY + total_txs * CHARS_PER_TX; + + let mut log_msg = String::with_capacity(estimated_capacity); + let _ = write!( + &mut log_msg, "Finished generating proposal {} with {} transactions", proposal_id, - block_artifacts.execution_data.execution_infos.len(), + execution_infos.len(), ); - block_artifacts.execution_data.execution_infos.iter().for_each(|(tx_hash, info)| { - log_msg.push_str(&format!(", {tx_hash}:")); - if info.revert_error.is_some() { - log_msg.push_str(" Reverted"); - } else { - log_msg.push_str(" Successful"); - } - }); - block_artifacts.execution_data.rejected_tx_hashes.iter().for_each(|tx_hash| { - log_msg.push_str(&format!(", {tx_hash}: Rejected")); - }); - info!(log_msg); + + for (tx_hash, info) in execution_infos { + let status = if info.revert_error.is_some() { "Reverted" } else { "Successful" }; + let _ = write!(&mut log_msg, ", {tx_hash}: {status}"); + } + + for tx_hash in rejected_hashes { + let _ = write!(&mut log_msg, ", {tx_hash}: Rejected"); + } + + info!("{}", log_msg); } } From 479ceb570ac8c433772dd1e7c79a1ab57ac72c2f Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 30 Oct 2025 17:07:45 +0200 Subject: [PATCH 209/313] blockifier: disable concurrency in transfers benchmark (#9867) --- crates/blockifier/benches/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/blockifier/benches/main.rs b/crates/blockifier/benches/main.rs index c0a76867277..fd7fa9b4c79 100644 --- a/crates/blockifier/benches/main.rs +++ b/crates/blockifier/benches/main.rs @@ -11,6 +11,7 @@ //! `cargo bench --bench blockifier --features "cairo_native"`. use apollo_infra_utils::set_global_allocator; +use blockifier::blockifier::config::ConcurrencyConfig; use blockifier::test_utils::transfers_generator::{ RecipientGeneratorType, TransfersGenerator, @@ -34,6 +35,7 @@ pub fn transfers_benchmark(c: &mut Criterion) { recipient_generator_type: RecipientGeneratorType::Random, #[cfg(feature = "cairo_native")] cairo_version: CairoVersion::Cairo1(RunnableCairo1::Native), + concurrency_config: ConcurrencyConfig::create_for_testing(false), ..Default::default() }; let mut transfers_generator = TransfersGenerator::new(transfers_generator_config); From 213dc6ca238ab616649105d8406a610a8dc93ccb Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 30 Oct 2025 17:30:56 +0200 Subject: [PATCH 210/313] apollo_integration_tests: use `AnvilBaseLayer` in multi-contract events test (#7788) (#9714) Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../papyrus_base_layer/src/base_layer_test.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index a964741f159..f792cba3f01 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -11,6 +11,7 @@ use starknet_api::transaction::L1HandlerTransaction; use starknet_api::{calldata, contract_address, felt}; use url::Url; +use crate::anvil_base_layer::AnvilBaseLayer; use crate::constants::{EventIdentifier, LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER}; use crate::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, @@ -19,11 +20,7 @@ use crate::ethereum_base_layer_contract::{ L1ToL2MessageArgs, Starknet, }; -use crate::test_utils::{ - anvil_instance_from_url, - ethereum_base_layer_config_for_anvil, - DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, -}; +use crate::test_utils::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS; use crate::{BaseLayerContract, L1Event}; // TODO(Gilad): Use everywhere instead of relying on the confusing `#[ignore]` api to mark slow @@ -127,6 +124,8 @@ async fn get_gas_price_and_timestamps() { assert_eq!(header.blob_fee, expected_original_blob_calc); } +// Ensure that the base layer instance filters out events from other deployments of the core +// contract. #[tokio::test] async fn events_from_other_contract() { if !in_ci() { @@ -134,19 +133,18 @@ async fn events_from_other_contract() { } const EVENT_IDENTIFIERS: &[EventIdentifier] = &[LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER]; - let (this_config, this_url) = ethereum_base_layer_config_for_anvil(None); - let _anvil = anvil_instance_from_url(&this_url); - let this_contract = EthereumBaseLayerContract::new(this_config.clone(), this_url.clone()); + let anvil_base_layer = AnvilBaseLayer::new().await; + // Anvil base layer already auto-deployed a starknet contract. + let this_contract = &anvil_base_layer.ethereum_base_layer.contract; - // Test: Get events from L1 contract and other instances of this L1 contract. // Setup. - // Deploy the contract to the anvil instance. - Starknet::deploy(this_contract.contract.provider().clone()).await.unwrap(); // Deploy another instance of the contract to the same anvil instance. - let other_contract = Starknet::deploy(this_contract.contract.provider().clone()).await.unwrap(); + let provider = this_contract.provider().clone(); + let other_contract = Starknet::deploy(provider).await.unwrap(); + assert_ne!( - this_contract.contract.address(), + this_contract.address(), other_contract.address(), "The two contracts should be different." ); @@ -158,7 +156,6 @@ async fn events_from_other_contract() { ..Default::default() }; let this_receipt = this_contract - .contract .send_message_to_l2(&L1ToL2MessageArgs { tx: this_l1_handler.clone(), l1_tx_nonce: 2 }) .await; assert!(this_receipt.status()); @@ -180,8 +177,11 @@ async fn events_from_other_contract() { let max_block_number = this_block_number.max(other_block_number).saturating_add(1); // Test the events. - let mut events = - this_contract.events(min_block_number..=max_block_number, EVENT_IDENTIFIERS).await.unwrap(); + let mut events = anvil_base_layer + .ethereum_base_layer + .events(min_block_number..=max_block_number, EVENT_IDENTIFIERS) + .await + .unwrap(); assert_eq!(events.len(), 1, "Expected only events from this contract."); assert_matches!(events.remove(0), L1Event::LogMessageToL2 { tx, .. } if tx == this_l1_handler); From 426dfac91fd7deee66fc57a24e283471d20ea9d7 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 30 Oct 2025 18:13:37 +0200 Subject: [PATCH 211/313] apollo_integration_tests: remove eth l1 nonce from `send_messages_to_l2` (#8261) (#9715) * l1: use `AnvilBaseLayer` in multi-contract events test * l1: remove eth l1 nonce from `send_messages_to_l2` Alloy can now auto-bump nonce automatically when using Anvil, via `AnvilBaseLayer`. Next commit will remove nonce tracking from starknet_api_test_utils.rs --------- Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/flow_test_setup.rs | 22 ++++++------ crates/apollo_integration_tests/src/utils.rs | 34 +++++++++---------- .../tests/end_to_end_flow_test.rs | 5 ++- .../src/starknet_api_test_utils.rs | 12 +++---- .../papyrus_base_layer/src/base_layer_test.rs | 9 ++--- .../src/ethereum_base_layer_contract.rs | 12 +------ 6 files changed, 35 insertions(+), 59 deletions(-) diff --git a/crates/apollo_integration_tests/src/flow_test_setup.rs b/crates/apollo_integration_tests/src/flow_test_setup.rs index 0a50b4214da..bd33f71a854 100644 --- a/crates/apollo_integration_tests/src/flow_test_setup.rs +++ b/crates/apollo_integration_tests/src/flow_test_setup.rs @@ -31,10 +31,7 @@ use mempool_test_utils::starknet_api_test_utils::{ MultiAccountTransactionGenerator, }; use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; -use papyrus_base_layer::ethereum_base_layer_contract::{ - EthereumBaseLayerConfig, - L1ToL2MessageArgs, -}; +use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; use papyrus_base_layer::test_utils::{ make_block_history_on_anvil, ARBITRARY_ANVIL_L1_ACCOUNT_ADDRESS, @@ -46,7 +43,12 @@ use starknet_api::consensus_transaction::ConsensusTransaction; use starknet_api::core::{ChainId, ContractAddress}; use starknet_api::execution_resources::GasAmount; use starknet_api::rpc_transaction::RpcTransaction; -use starknet_api::transaction::{TransactionHash, TransactionHasher, TransactionVersion}; +use starknet_api::transaction::{ + L1HandlerTransaction, + TransactionHash, + TransactionHasher, + TransactionVersion, +}; use starknet_types_core::felt::Felt; use tokio::sync::Mutex; use tracing::{debug, instrument, Instrument}; @@ -193,13 +195,9 @@ impl FlowTestSetup { .chain_id } - pub async fn send_messages_to_l2(&self, l1_to_l2_messages_args: &[L1ToL2MessageArgs]) { - for l1_to_l2_message_args in l1_to_l2_messages_args { - self.anvil_base_layer - .ethereum_base_layer - .contract - .send_message_to_l2(l1_to_l2_message_args) - .await; + pub async fn send_messages_to_l2(&self, l1_handlers: &[L1HandlerTransaction]) { + for l1_handler in l1_handlers { + self.anvil_base_layer.ethereum_base_layer.contract.send_message_to_l2(l1_handler).await; } } } diff --git a/crates/apollo_integration_tests/src/utils.rs b/crates/apollo_integration_tests/src/utils.rs index 921180183e1..3cf1f1e6403 100644 --- a/crates/apollo_integration_tests/src/utils.rs +++ b/crates/apollo_integration_tests/src/utils.rs @@ -62,7 +62,6 @@ use blockifier_test_utils::contracts::FeatureContract; use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator}; use papyrus_base_layer::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, - L1ToL2MessageArgs, StarknetL1Contract, }; use serde::Deserialize; @@ -72,7 +71,7 @@ use starknet_api::core::{ChainId, ContractAddress}; use starknet_api::execution_resources::GasAmount; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::fields::ContractAddressSalt; -use starknet_api::transaction::{TransactionHash, TransactionHasher}; +use starknet_api::transaction::{L1HandlerTransaction, TransactionHash, TransactionHasher}; use starknet_types_core::felt::Felt; use tokio::task::JoinHandle; use tracing::{debug, info, Instrument}; @@ -91,7 +90,7 @@ pub const N_TXS_IN_FIRST_BLOCK: usize = 2; pub type CreateRpcTxsFn = fn(&mut MultiAccountTransactionGenerator) -> Vec; pub type CreateL1ToL2MessagesArgsFn = - fn(&mut MultiAccountTransactionGenerator) -> Vec; + fn(&mut MultiAccountTransactionGenerator) -> Vec; pub type TestTxHashesFn = fn(&[TransactionHash]) -> Vec; pub trait TestScenario { @@ -99,7 +98,7 @@ pub trait TestScenario { &self, tx_generator: &mut MultiAccountTransactionGenerator, account_id: AccountId, - ) -> (Vec, Vec); + ) -> (Vec, Vec); fn n_txs(&self) -> usize; } @@ -114,7 +113,7 @@ impl TestScenario for ConsensusTxs { &self, tx_generator: &mut MultiAccountTransactionGenerator, account_id: AccountId, - ) -> (Vec, Vec) { + ) -> (Vec, Vec) { ( create_invoke_txs(tx_generator, account_id, self.n_invoke_txs), create_l1_to_l2_messages_args(tx_generator, self.n_l1_handler_txs), @@ -133,7 +132,7 @@ impl TestScenario for DeclareTx { &self, tx_generator: &mut MultiAccountTransactionGenerator, account_id: AccountId, - ) -> (Vec, Vec) { + ) -> (Vec, Vec) { let declare_tx = tx_generator.account_with_id_mut(account_id).generate_declare_of_contract_class(); (vec![declare_tx], vec![]) @@ -151,7 +150,7 @@ impl TestScenario for DeployAndInvokeTxs { &self, tx_generator: &mut MultiAccountTransactionGenerator, account_id: AccountId, - ) -> (Vec, Vec) { + ) -> (Vec, Vec) { let txs = create_deploy_account_tx_and_invoke_tx(tx_generator, account_id); assert_eq!( txs.len(), @@ -525,20 +524,17 @@ pub fn create_invoke_txs( pub fn create_l1_to_l2_messages_args( tx_generator: &mut MultiAccountTransactionGenerator, n_txs: usize, -) -> Vec { +) -> Vec { (0..n_txs).map(|_| tx_generator.create_l1_to_l2_message_args()).collect() } pub async fn send_message_to_l2_and_calculate_tx_hash( - send_message_to_l2_args: L1ToL2MessageArgs, + l1_handler: L1HandlerTransaction, starknet_l1_contract: &StarknetL1Contract, chain_id: &ChainId, ) -> TransactionHash { - starknet_l1_contract.send_message_to_l2(&send_message_to_l2_args).await; - send_message_to_l2_args - .tx - .calculate_transaction_hash(chain_id, &send_message_to_l2_args.tx.version) - .unwrap() + starknet_l1_contract.send_message_to_l2(&l1_handler).await; + l1_handler.calculate_transaction_hash(chain_id, &l1_handler.version).unwrap() } async fn send_rpc_txs<'a, Fut>( @@ -562,7 +558,7 @@ where pub async fn run_test_scenario<'a, Fut>( tx_generator: &mut MultiAccountTransactionGenerator, create_rpc_txs_fn: CreateRpcTxsFn, - l1_to_l2_message_args: Vec, + l1_handlers: Vec, send_rpc_tx_fn: &'a mut dyn Fn(RpcTransaction) -> Fut, test_tx_hashes_fn: TestTxHashesFn, chain_id: &ChainId, @@ -570,9 +566,11 @@ pub async fn run_test_scenario<'a, Fut>( where Fut: Future + 'a, { - let mut tx_hashes: Vec = l1_to_l2_message_args + let mut tx_hashes: Vec = l1_handlers .iter() - .map(|args| args.tx.calculate_transaction_hash(chain_id, &args.tx.version).unwrap()) + .map(|l1_handler| { + l1_handler.calculate_transaction_hash(chain_id, &l1_handler.version).unwrap() + }) .collect(); let rpc_txs = create_rpc_txs_fn(tx_generator); @@ -586,7 +584,7 @@ pub async fn send_consensus_txs<'a, 'b, FutA, FutB>( account_id: AccountId, test_scenario: &impl TestScenario, send_rpc_tx_fn: &'a mut dyn Fn(RpcTransaction) -> FutA, - send_l1_handler_tx_fn: &'b mut dyn Fn(L1ToL2MessageArgs) -> FutB, + send_l1_handler_tx_fn: &'b mut dyn Fn(L1HandlerTransaction) -> FutB, ) -> Vec where FutA: Future + 'a, diff --git a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs index f647278716f..c1ebba1efa8 100644 --- a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs +++ b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs @@ -8,9 +8,8 @@ use apollo_integration_tests::utils::{ }; use blockifier::bouncer::BouncerWeights; use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; -use papyrus_base_layer::ethereum_base_layer_contract::L1ToL2MessageArgs; use starknet_api::rpc_transaction::RpcTransaction; -use starknet_api::transaction::TransactionHash; +use starknet_api::transaction::{L1HandlerTransaction, TransactionHash}; use crate::common::{end_to_end_flow, test_single_tx, TestScenario}; @@ -65,7 +64,7 @@ pub fn create_test_scenarios() -> Vec { fn create_l1_to_l2_message_args( tx_generator: &mut MultiAccountTransactionGenerator, -) -> Vec { +) -> Vec { const N_TXS: usize = 1; create_l1_to_l2_messages_args(tx_generator, N_TXS) } diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index 542ad4aceec..76ea153c940 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -8,7 +8,6 @@ use assert_matches::assert_matches; use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use blockifier_test_utils::calldata::{create_calldata, create_trivial_calldata}; use blockifier_test_utils::contracts::FeatureContract; -use papyrus_base_layer::ethereum_base_layer_contract::L1ToL2MessageArgs; use papyrus_base_layer::test_utils::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS; use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::block::GasPrice; @@ -188,14 +187,13 @@ impl L1HandlerTransactionGenerator { /// Creates an L1 handler transaction calling the "l1_handler_set_value" entry point in /// [TestContract](FeatureContract::TestContract). - fn create_l1_to_l2_message_args(&mut self) -> L1ToL2MessageArgs { - let l1_tx_nonce = self.l1_tx_nonce; + fn create_l1_to_l2_message_args(&mut self) -> L1HandlerTransaction { self.l1_tx_nonce += 1; // TODO(Arni): Get test contract from test setup. let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); - let l1_handler_tx = L1HandlerTransaction { + L1HandlerTransaction { contract_address: test_contract.get_instance_address(0), // TODO(Arni): Consider saving this value as a lazy constant. entry_point_selector: selector_from_name("l1_handler_set_value"), @@ -206,9 +204,7 @@ impl L1HandlerTransactionGenerator { felt!("0x44") // value ], ..Default::default() - }; - - L1ToL2MessageArgs { tx: l1_handler_tx, l1_tx_nonce } + } } fn n_generated_txs(&self) -> u64 { @@ -373,7 +369,7 @@ impl MultiAccountTransactionGenerator { .collect() } - pub fn create_l1_to_l2_message_args(&mut self) -> L1ToL2MessageArgs { + pub fn create_l1_to_l2_message_args(&mut self) -> L1HandlerTransaction { self.l1_handler_tx_generator.create_l1_to_l2_message_args() } diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index f792cba3f01..8b9beaa601b 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -17,7 +17,6 @@ use crate::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, EthereumBaseLayerContract, EthereumBaseLayerError, - L1ToL2MessageArgs, Starknet, }; use crate::test_utils::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS; @@ -155,9 +154,7 @@ async fn events_from_other_contract() { calldata: calldata!(DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, felt!("0x1"), felt!("0x2")), ..Default::default() }; - let this_receipt = this_contract - .send_message_to_l2(&L1ToL2MessageArgs { tx: this_l1_handler.clone(), l1_tx_nonce: 2 }) - .await; + let this_receipt = this_contract.send_message_to_l2(&this_l1_handler.clone()).await; assert!(this_receipt.status()); let this_block_number = this_receipt.block_number.unwrap(); @@ -167,9 +164,7 @@ async fn events_from_other_contract() { calldata: calldata!(DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, felt!("0x1"), felt!("0x2")), ..Default::default() }; - let other_receipt = other_contract - .send_message_to_l2(&L1ToL2MessageArgs { tx: other_l1_handler.clone(), l1_tx_nonce: 3 }) - .await; + let other_receipt = other_contract.send_message_to_l2(&other_l1_handler.clone()).await; assert!(other_receipt.status()); let other_block_number = other_receipt.block_number.unwrap(); diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index 00c6c53e99a..ae45f8a6f65 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -51,12 +51,6 @@ sol!( /// L2 from this contract, which appear on the corresponding base layer. pub type StarknetL1Contract = Starknet::StarknetInstance; -#[cfg(any(feature = "testing", test))] -pub struct L1ToL2MessageArgs { - pub tx: starknet_api::transaction::L1HandlerTransaction, - pub l1_tx_nonce: u64, -} - #[cfg(any(feature = "testing", test))] impl StarknetL1Contract { /// Converts a given [L1 handler transaction](starknet_api::transaction::L1HandlerTransaction) @@ -64,13 +58,11 @@ impl StarknetL1Contract { /// triggers the L1 entry point which sends the message to L2. pub async fn send_message_to_l2( &self, - l1_to_l2_message_args: &L1ToL2MessageArgs, + l1_handler: &starknet_api::transaction::L1HandlerTransaction, ) -> alloy::rpc::types::TransactionReceipt { use alloy::primitives::U256; const PAID_FEE_ON_L1: U256 = U256::from_be_slice(b"paid"); // Arbitrary value. - let L1ToL2MessageArgs { tx: l1_handler, l1_tx_nonce } = l1_to_l2_message_args; - tracing::info!("Sending message to L2 with the l1 nonce: {l1_tx_nonce}"); let l2_contract_address = l1_handler.contract_address.0.key().to_hex_string().parse().unwrap(); let l2_entry_point = l1_handler.entry_point_selector.0.to_hex_string().parse().unwrap(); @@ -85,8 +77,6 @@ impl StarknetL1Contract { msg // Sets a non-zero fee to be paid on L1. .value(PAID_FEE_ON_L1) - // Sets the nonce of the L1 handler transaction, to avoid L1 nonce collisions. - .nonce(*l1_tx_nonce) // Sends the transaction to the Starknet L1 contract. For debugging purposes, replace // `.send()` with `.call_raw()` to retrieve detailed error messages from L1. .send().await.expect("Transaction submission to Starknet L1 contract failed.") From 44ce2ff7d2e9eb2136366d5cece44ee775555abd Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 30 Oct 2025 22:15:33 +0200 Subject: [PATCH 212/313] apollo_integration_tests: change nonce into n_txs in starknet_api_test_utils (#8262) (#9716) Used to have l1 nonce tracking before we added nonce support to alloy client. Now all that's needed is n_txs for assertions in the test. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/starknet_api_test_utils.rs | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index 76ea153c940..9c548d55a15 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -170,16 +170,9 @@ pub type AccountId = usize; type SharedNonceManager = Rc>; +#[derive(Debug, Default)] struct L1HandlerTransactionGenerator { - // The L1 nonce for the next created L1 handler transaction. - l1_tx_nonce: u64, -} - -impl Default for L1HandlerTransactionGenerator { - /// The Anvil instance is spawned with a nonce of 1 for the account [Self::L1_ACCOUNT_ADDRESS]. - fn default() -> Self { - Self { l1_tx_nonce: 1 } - } + n_generated_txs: usize, } impl L1HandlerTransactionGenerator { @@ -188,7 +181,8 @@ impl L1HandlerTransactionGenerator { /// Creates an L1 handler transaction calling the "l1_handler_set_value" entry point in /// [TestContract](FeatureContract::TestContract). fn create_l1_to_l2_message_args(&mut self) -> L1HandlerTransaction { - self.l1_tx_nonce += 1; + self.n_generated_txs += 1; + // TODO(Arni): Get test contract from test setup. let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); @@ -206,10 +200,6 @@ impl L1HandlerTransactionGenerator { ..Default::default() } } - - fn n_generated_txs(&self) -> u64 { - self.l1_tx_nonce - 1 - } } // TODO(Yair): Separate MultiAccountTransactionGenerator to phases: @@ -286,8 +276,9 @@ impl MultiAccountTransactionGenerator { contract_address_salt: tx_gen.contract_address_salt, }) .collect(); - let l1_handler_tx_generator = - L1HandlerTransactionGenerator { l1_tx_nonce: self.l1_handler_tx_generator.l1_tx_nonce }; + let l1_handler_tx_generator = L1HandlerTransactionGenerator { + n_generated_txs: self.l1_handler_tx_generator.n_generated_txs, + }; Self { account_tx_generators, nonce_manager, l1_handler_tx_generator } } @@ -374,10 +365,7 @@ impl MultiAccountTransactionGenerator { } pub fn n_l1_txs(&self) -> usize { - self.l1_handler_tx_generator - .n_generated_txs() - .try_into() - .expect("Failed to convert nonce to usize") + self.l1_handler_tx_generator.n_generated_txs } } From 8d55e96e4ef87cec46c9e97bbcf3477c4437cf29 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Fri, 31 Oct 2025 09:16:42 +0200 Subject: [PATCH 213/313] apollo_integration_tests: move send_messages_to_l2 util into `AnvilBaseLayer` (#8264) (#9718) Encodes an `L1HandlerTransaction` so that it can be sent to L1. Move into a method on `AnvilBaseLayer` for most cases, instead of adding a method to the auto-generated `Starknet` solidity contract. Using a free function to allow calling this function on multiple Starknet contracts (as is the case on sepolia with legacy contracts). Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/flow_test_setup.rs | 2 +- .../src/integration_test_manager.rs | 2 +- crates/apollo_integration_tests/src/utils.rs | 10 ++--- .../tests/scraper_end_to_end.rs | 2 +- .../src/anvil_base_layer.rs | 42 ++++++++++++++++++- .../papyrus_base_layer/src/base_layer_test.rs | 6 +-- .../src/ethereum_base_layer_contract.rs | 34 --------------- 7 files changed, 51 insertions(+), 47 deletions(-) diff --git a/crates/apollo_integration_tests/src/flow_test_setup.rs b/crates/apollo_integration_tests/src/flow_test_setup.rs index bd33f71a854..095f9f7fe20 100644 --- a/crates/apollo_integration_tests/src/flow_test_setup.rs +++ b/crates/apollo_integration_tests/src/flow_test_setup.rs @@ -197,7 +197,7 @@ impl FlowTestSetup { pub async fn send_messages_to_l2(&self, l1_handlers: &[L1HandlerTransaction]) { for l1_handler in l1_handlers { - self.anvil_base_layer.ethereum_base_layer.contract.send_message_to_l2(l1_handler).await; + self.anvil_base_layer.send_message_to_l2(l1_handler).await; } } } diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index f04b655ecc1..21c99872da5 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -673,7 +673,7 @@ impl IntegrationTestManager { let send_l1_handler_tx_fn = &mut |l1_handler_tx| { send_message_to_l2_and_calculate_tx_hash( l1_handler_tx, - &self.anvil_base_layer.ethereum_base_layer.contract, + &self.anvil_base_layer, &chain_id, ) }; diff --git a/crates/apollo_integration_tests/src/utils.rs b/crates/apollo_integration_tests/src/utils.rs index 3cf1f1e6403..fafa898c781 100644 --- a/crates/apollo_integration_tests/src/utils.rs +++ b/crates/apollo_integration_tests/src/utils.rs @@ -60,10 +60,8 @@ use blockifier::context::ChainInfo; use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use blockifier_test_utils::contracts::FeatureContract; use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator}; -use papyrus_base_layer::ethereum_base_layer_contract::{ - EthereumBaseLayerConfig, - StarknetL1Contract, -}; +use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; +use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; use serde::Deserialize; use serde_json::{json, to_value}; use starknet_api::block::BlockNumber; @@ -530,10 +528,10 @@ pub fn create_l1_to_l2_messages_args( pub async fn send_message_to_l2_and_calculate_tx_hash( l1_handler: L1HandlerTransaction, - starknet_l1_contract: &StarknetL1Contract, + anvil_base_layer: &AnvilBaseLayer, chain_id: &ChainId, ) -> TransactionHash { - starknet_l1_contract.send_message_to_l2(&l1_handler).await; + anvil_base_layer.send_message_to_l2(&l1_handler).await; l1_handler.calculate_transaction_hash(chain_id, &l1_handler.version).unwrap() } diff --git a/crates/apollo_l1_provider/tests/scraper_end_to_end.rs b/crates/apollo_l1_provider/tests/scraper_end_to_end.rs index 84523544d1d..96331ce9259 100644 --- a/crates/apollo_l1_provider/tests/scraper_end_to_end.rs +++ b/crates/apollo_l1_provider/tests/scraper_end_to_end.rs @@ -149,7 +149,7 @@ async fn scraper_end_to_end() { let mut scraper = L1Scraper::new( l1_scraper_config, Arc::new(l1_provider_client), - base_layer.clone(), + base_layer.ethereum_base_layer.clone(), event_identifiers_to_track(), l1_start_block, ) diff --git a/crates/papyrus_base_layer/src/anvil_base_layer.rs b/crates/papyrus_base_layer/src/anvil_base_layer.rs index b35b1e19cde..be8dbeab4b3 100644 --- a/crates/papyrus_base_layer/src/anvil_base_layer.rs +++ b/crates/papyrus_base_layer/src/anvil_base_layer.rs @@ -1,10 +1,13 @@ use std::ops::RangeInclusive; use alloy::node_bindings::NodeError as AnvilError; +use alloy::primitives::U256; use alloy::providers::{DynProvider, Provider, ProviderBuilder}; +use alloy::rpc::types::TransactionReceipt; use async_trait::async_trait; use colored::*; use starknet_api::block::BlockHashAndNumber; +use starknet_api::transaction::L1HandlerTransaction; use url::Url; use crate::ethereum_base_layer_contract::{ @@ -12,6 +15,7 @@ use crate::ethereum_base_layer_contract::{ EthereumBaseLayerContract, EthereumBaseLayerError, Starknet, + StarknetL1Contract, }; use crate::{BaseLayerContract, L1BlockHeader, L1BlockNumber, L1BlockReference, L1Event}; @@ -22,7 +26,7 @@ use crate::{BaseLayerContract, L1BlockHeader, L1BlockNumber, L1BlockReference, L /// unit tests is not supported and is discouraged, since unit tests should not need to run a whole /// L1 (and they are parallelized, which creates port issues). For unit tests, prefer using /// `ProviderBuilder::new().on_mocked_client` to mock L1. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct AnvilBaseLayer { pub anvil_provider: DynProvider, pub ethereum_base_layer: EthereumBaseLayerContract, @@ -69,6 +73,13 @@ impl AnvilBaseLayer { } } + pub async fn send_message_to_l2( + &self, + l1_handler: &L1HandlerTransaction, + ) -> TransactionReceipt { + send_message_to_l2(&self.ethereum_base_layer.contract, l1_handler).await + } + pub fn url() -> Url { format!("http://127.0.0.1:{}", Self::DEFAULT_ANVIL_PORT).parse().unwrap() } @@ -141,3 +152,32 @@ impl BaseLayerContract for AnvilBaseLayer { unimplemented!("Anvil base layer is tied to a an Anvil server, url is fixed.") } } + +/// Converts a given [L1 handler transaction](starknet_api::transaction::L1HandlerTransaction) +/// to match the interface of the given [starknet l1 contract](StarknetL1Contract), and +/// triggers the L1 entry point, which sends the message to L2. +pub async fn send_message_to_l2( + starknet_core_contract: &StarknetL1Contract, + l1_handler: &L1HandlerTransaction, +) -> TransactionReceipt { + const PAID_FEE_ON_L1: U256 = U256::from_be_slice(b"paid"); // Arbitrary value. + + let l2_contract_address = l1_handler.contract_address.0.key().to_hex_string().parse().unwrap(); + let l2_entry_point = l1_handler.entry_point_selector.0.to_hex_string().parse().unwrap(); + + // The calldata of an L1 handler transaction consists of the L1 sender address followed by + // the transaction payload. We remove the sender address to extract the message + // payload. + let payload = + l1_handler.calldata.0[1..].iter().map(|x| x.to_hex_string().parse().unwrap()).collect(); + let msg = starknet_core_contract.sendMessageToL2(l2_contract_address, l2_entry_point, payload); + + msg + // Sets a non-zero fee to be paid on L1. + .value(PAID_FEE_ON_L1) + // Sends the transaction to the Starknet L1 contract. For debugging purposes, replace + // `.send()` with `.call_raw()` to retrieve detailed error messages from L1. + .send().await.expect("Transaction submission to Starknet L1 contract failed.") + // Waits until the transaction is received on L1 and then fetches its receipt. + .get_receipt().await.expect("Transaction was not received on L1 or receipt retrieval failed.") +} diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index 8b9beaa601b..036c2b8db0e 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -11,7 +11,7 @@ use starknet_api::transaction::L1HandlerTransaction; use starknet_api::{calldata, contract_address, felt}; use url::Url; -use crate::anvil_base_layer::AnvilBaseLayer; +use crate::anvil_base_layer::{send_message_to_l2, AnvilBaseLayer}; use crate::constants::{EventIdentifier, LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER}; use crate::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, @@ -154,7 +154,7 @@ async fn events_from_other_contract() { calldata: calldata!(DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, felt!("0x1"), felt!("0x2")), ..Default::default() }; - let this_receipt = this_contract.send_message_to_l2(&this_l1_handler.clone()).await; + let this_receipt = send_message_to_l2(this_contract, &this_l1_handler.clone()).await; assert!(this_receipt.status()); let this_block_number = this_receipt.block_number.unwrap(); @@ -164,7 +164,7 @@ async fn events_from_other_contract() { calldata: calldata!(DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, felt!("0x1"), felt!("0x2")), ..Default::default() }; - let other_receipt = other_contract.send_message_to_l2(&other_l1_handler.clone()).await; + let other_receipt = send_message_to_l2(&other_contract, &other_l1_handler.clone()).await; assert!(other_receipt.status()); let other_block_number = other_receipt.block_number.unwrap(); diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index ae45f8a6f65..00ef6d92e8f 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -51,40 +51,6 @@ sol!( /// L2 from this contract, which appear on the corresponding base layer. pub type StarknetL1Contract = Starknet::StarknetInstance; -#[cfg(any(feature = "testing", test))] -impl StarknetL1Contract { - /// Converts a given [L1 handler transaction](starknet_api::transaction::L1HandlerTransaction) - /// to match the interface of the given [starknet l1 contract](StarknetL1Contract), and - /// triggers the L1 entry point which sends the message to L2. - pub async fn send_message_to_l2( - &self, - l1_handler: &starknet_api::transaction::L1HandlerTransaction, - ) -> alloy::rpc::types::TransactionReceipt { - use alloy::primitives::U256; - const PAID_FEE_ON_L1: U256 = U256::from_be_slice(b"paid"); // Arbitrary value. - - let l2_contract_address = - l1_handler.contract_address.0.key().to_hex_string().parse().unwrap(); - let l2_entry_point = l1_handler.entry_point_selector.0.to_hex_string().parse().unwrap(); - - // The calldata of an L1 handler transaction consists of the L1 sender address followed by - // the transaction payload. We remove the sender address to extract the message - // payload. - let payload = - l1_handler.calldata.0[1..].iter().map(|x| x.to_hex_string().parse().unwrap()).collect(); - let msg = self.sendMessageToL2(l2_contract_address, l2_entry_point, payload); - - msg - // Sets a non-zero fee to be paid on L1. - .value(PAID_FEE_ON_L1) - // Sends the transaction to the Starknet L1 contract. For debugging purposes, replace - // `.send()` with `.call_raw()` to retrieve detailed error messages from L1. - .send().await.expect("Transaction submission to Starknet L1 contract failed.") - // Waits until the transaction is received on L1 and then fetches its receipt. - .get_receipt().await.expect("Transaction was not received on L1 or receipt retrieval failed.") - } -} - #[derive(Clone, Debug)] pub struct EthereumBaseLayerContract { pub url: Url, From ea9f4d82715c423d7dde4cbbd47148119ac098ad Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Fri, 31 Oct 2025 09:48:19 +0200 Subject: [PATCH 214/313] apollo_integration_tests: convert events_from_other_contracts test into integration test (#7789) (#9719) It requires anvil, so should not be run as a unit test Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/anvil_base_layer.rs | 3 + .../papyrus_base_layer/src/base_layer_test.rs | 68 +--------------- .../tests/events_from_other_contracts.rs | 78 +++++++++++++++++++ 3 files changed, 83 insertions(+), 66 deletions(-) create mode 100644 crates/papyrus_base_layer/tests/events_from_other_contracts.rs diff --git a/crates/papyrus_base_layer/src/anvil_base_layer.rs b/crates/papyrus_base_layer/src/anvil_base_layer.rs index be8dbeab4b3..9165432d260 100644 --- a/crates/papyrus_base_layer/src/anvil_base_layer.rs +++ b/crates/papyrus_base_layer/src/anvil_base_layer.rs @@ -7,6 +7,7 @@ use alloy::rpc::types::TransactionReceipt; use async_trait::async_trait; use colored::*; use starknet_api::block::BlockHashAndNumber; +use starknet_api::hash::StarkHash; use starknet_api::transaction::L1HandlerTransaction; use url::Url; @@ -33,6 +34,8 @@ pub struct AnvilBaseLayer { } impl AnvilBaseLayer { + pub const DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS: StarkHash = + StarkHash::from_hex_unchecked("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); const DEFAULT_ANVIL_PORT: u16 = 8545; const DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS: &str = "0x5fbdb2315678afecb367f032d93f642f64180aa3"; diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index 036c2b8db0e..e7271f7e46c 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -6,21 +6,16 @@ use alloy::rpc::types::{Block, BlockTransactions, Header as AlloyRpcHeader}; use assert_matches::assert_matches; use pretty_assertions::assert_eq; use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; -use starknet_api::core::EntryPointSelector; -use starknet_api::transaction::L1HandlerTransaction; -use starknet_api::{calldata, contract_address, felt}; +use starknet_api::felt; use url::Url; -use crate::anvil_base_layer::{send_message_to_l2, AnvilBaseLayer}; -use crate::constants::{EventIdentifier, LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER}; use crate::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, EthereumBaseLayerContract, EthereumBaseLayerError, Starknet, }; -use crate::test_utils::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS; -use crate::{BaseLayerContract, L1Event}; +use crate::BaseLayerContract; // TODO(Gilad): Use everywhere instead of relying on the confusing `#[ignore]` api to mark slow // tests. @@ -122,62 +117,3 @@ async fn get_gas_price_and_timestamps() { let expected_original_blob_calc = 19; assert_eq!(header.blob_fee, expected_original_blob_calc); } - -// Ensure that the base layer instance filters out events from other deployments of the core -// contract. -#[tokio::test] -async fn events_from_other_contract() { - if !in_ci() { - return; - } - const EVENT_IDENTIFIERS: &[EventIdentifier] = &[LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER]; - - let anvil_base_layer = AnvilBaseLayer::new().await; - // Anvil base layer already auto-deployed a starknet contract. - let this_contract = &anvil_base_layer.ethereum_base_layer.contract; - - // Setup. - - // Deploy another instance of the contract to the same anvil instance. - let provider = this_contract.provider().clone(); - let other_contract = Starknet::deploy(provider).await.unwrap(); - - assert_ne!( - this_contract.address(), - other_contract.address(), - "The two contracts should be different." - ); - - let this_l1_handler = L1HandlerTransaction { - contract_address: contract_address!("0x12"), - entry_point_selector: EntryPointSelector(felt!("0x34")), - calldata: calldata!(DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, felt!("0x1"), felt!("0x2")), - ..Default::default() - }; - let this_receipt = send_message_to_l2(this_contract, &this_l1_handler.clone()).await; - assert!(this_receipt.status()); - let this_block_number = this_receipt.block_number.unwrap(); - - let other_l1_handler = L1HandlerTransaction { - contract_address: contract_address!("0x56"), - entry_point_selector: EntryPointSelector(felt!("0x78")), - calldata: calldata!(DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, felt!("0x1"), felt!("0x2")), - ..Default::default() - }; - let other_receipt = send_message_to_l2(&other_contract, &other_l1_handler.clone()).await; - assert!(other_receipt.status()); - let other_block_number = other_receipt.block_number.unwrap(); - - let min_block_number = this_block_number.min(other_block_number).saturating_sub(1); - let max_block_number = this_block_number.max(other_block_number).saturating_add(1); - - // Test the events. - let mut events = anvil_base_layer - .ethereum_base_layer - .events(min_block_number..=max_block_number, EVENT_IDENTIFIERS) - .await - .unwrap(); - - assert_eq!(events.len(), 1, "Expected only events from this contract."); - assert_matches!(events.remove(0), L1Event::LogMessageToL2 { tx, .. } if tx == this_l1_handler); -} diff --git a/crates/papyrus_base_layer/tests/events_from_other_contracts.rs b/crates/papyrus_base_layer/tests/events_from_other_contracts.rs new file mode 100644 index 00000000000..170a6bcd0e5 --- /dev/null +++ b/crates/papyrus_base_layer/tests/events_from_other_contracts.rs @@ -0,0 +1,78 @@ +use assert_matches::assert_matches; +use papyrus_base_layer::anvil_base_layer::{send_message_to_l2, AnvilBaseLayer}; +use papyrus_base_layer::constants::{EventIdentifier, LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER}; +use papyrus_base_layer::ethereum_base_layer_contract::Starknet; +use papyrus_base_layer::{BaseLayerContract, L1Event}; +use pretty_assertions::assert_eq; +use starknet_api::core::EntryPointSelector; +use starknet_api::transaction::L1HandlerTransaction; +use starknet_api::{calldata, contract_address, felt}; + +pub fn in_ci() -> bool { + std::env::var("CI").is_ok() +} + +// Ensure that the base layer instance filters out events from other deployments of the core +// contract. +#[tokio::test] +async fn events_from_other_contract() { + if !in_ci() { + return; + } + const EVENT_IDENTIFIERS: &[EventIdentifier] = &[LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER]; + + let anvil_base_layer = AnvilBaseLayer::new().await; + // Anvil base layer already auto-deployed a starknet contract. + let this_contract = &anvil_base_layer.ethereum_base_layer.contract; + + // Setup. + + // Deploy another instance of the contract to the same anvil instance. + let other_contract = Starknet::deploy(this_contract.provider().clone()).await.unwrap(); + assert_ne!( + this_contract.address(), + other_contract.address(), + "The two contracts should be different." + ); + + let this_l1_handler = L1HandlerTransaction { + contract_address: contract_address!("0x12"), + entry_point_selector: EntryPointSelector(felt!("0x34")), + calldata: calldata!( + AnvilBaseLayer::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, + felt!("0x1"), + felt!("0x2") + ), + ..Default::default() + }; + let this_receipt = send_message_to_l2(this_contract, &this_l1_handler.clone()).await; + assert!(this_receipt.status()); + let this_block_number = this_receipt.block_number.unwrap(); + + let other_l1_handler = L1HandlerTransaction { + contract_address: contract_address!("0x56"), + entry_point_selector: EntryPointSelector(felt!("0x78")), + calldata: calldata!( + AnvilBaseLayer::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS, + felt!("0x1"), + felt!("0x2") + ), + ..Default::default() + }; + let other_receipt = send_message_to_l2(&other_contract, &other_l1_handler.clone()).await; + assert!(other_receipt.status()); + let other_block_number = other_receipt.block_number.unwrap(); + + let min_block_number = this_block_number.min(other_block_number).saturating_sub(1); + let max_block_number = this_block_number.max(other_block_number).saturating_add(1); + + // Test the events. + let mut events = anvil_base_layer + .ethereum_base_layer + .events(min_block_number..=max_block_number, EVENT_IDENTIFIERS) + .await + .unwrap(); + + assert_eq!(events.len(), 1, "Expected only events from this contract."); + assert_matches!(events.remove(0), L1Event::LogMessageToL2 { tx, .. } if tx == this_l1_handler); +} From 0fddc3f2770f7b3b44635acd019003e1a7a8c66d Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Fri, 31 Oct 2025 10:29:44 +0200 Subject: [PATCH 215/313] apollo_integration_tests: remove unused test-utils in favor of `AnvilBaseLayer` (#7790) (#9720) `AnvilBaseLayer` already replaced their usage in previous work. Lingering usage in simulator replaced with manual deploy, this cannot use anvil base layer since it is not using alloy to run Anvil, but manually running it through bash in the github workflow. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/bin/sequencer_simulator.rs | 11 +++-- crates/papyrus_base_layer/src/test_utils.rs | 41 ------------------- 2 files changed, 8 insertions(+), 44 deletions(-) diff --git a/crates/apollo_integration_tests/src/bin/sequencer_simulator.rs b/crates/apollo_integration_tests/src/bin/sequencer_simulator.rs index ba8a81d4b30..da432f06b32 100644 --- a/crates/apollo_integration_tests/src/bin/sequencer_simulator.rs +++ b/crates/apollo_integration_tests/src/bin/sequencer_simulator.rs @@ -13,9 +13,12 @@ use apollo_integration_tests::utils::{ }; use clap::Parser; use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; -use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; +use papyrus_base_layer::ethereum_base_layer_contract::{ + EthereumBaseLayerConfig, + EthereumBaseLayerContract, + Starknet, +}; use papyrus_base_layer::test_utils::{ - deploy_starknet_l1_contract, make_block_history_on_anvil, DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS, }; @@ -135,7 +138,9 @@ async fn initialize_anvil_state(sender_address: Address, receiver_address: Addre let (base_layer_config, base_layer_url) = build_base_layer_config_for_testing(); - deploy_starknet_l1_contract(base_layer_config.clone(), &base_layer_url).await; + let ethereum_base_layer_contract = + EthereumBaseLayerContract::new(base_layer_config.clone(), base_layer_url.clone()); + Starknet::deploy(ethereum_base_layer_contract.contract.provider().clone()).await.unwrap(); make_block_history_on_anvil( sender_address, diff --git a/crates/papyrus_base_layer/src/test_utils.rs b/crates/papyrus_base_layer/src/test_utils.rs index cdd2530dc4e..9d0e9c5d91e 100644 --- a/crates/papyrus_base_layer/src/test_utils.rs +++ b/crates/papyrus_base_layer/src/test_utils.rs @@ -18,17 +18,12 @@ use crate::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, EthereumBaseLayerContract, EthereumContractAddress, - Starknet, - StarknetL1Contract, }; type TestEthereumNodeHandle = (GanacheInstance, TempDir); const MINIMAL_GANACHE_VERSION: u8 = 7; -// See Anvil documentation: -// https://docs.rs/ethers-core/latest/ethers_core/utils/struct.Anvil.html#method.new. -const DEFAULT_ANVIL_PORT: u16 = 8545; // This address is commonly used as the L1 address of the Starknet core contract. // TODO(Arni): Replace with constant with use of `AnvilInstance::address(&self)`. pub const DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS: &str = "0x5fbdb2315678afecb367f032d93f642f64180aa3"; @@ -129,42 +124,6 @@ pub fn anvil(port: Option) -> AnvilInstance { }) } -pub fn ethereum_base_layer_config_for_anvil(port: Option) -> (EthereumBaseLayerConfig, Url) { - // Use the specified port if provided; otherwise, default to Anvil's default port. - let non_optional_port = port.unwrap_or(DEFAULT_ANVIL_PORT); - let endpoint = format!("http://localhost:{non_optional_port}"); - let url = Url::parse(&endpoint).unwrap(); - let config = EthereumBaseLayerConfig { - starknet_contract_address: DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS.parse().unwrap(), - ..Default::default() - }; - (config, url) -} - -pub fn anvil_instance_from_url(url: &Url) -> AnvilInstance { - let port = url.port(); - let anvil = anvil(port); - assert_eq!(url, &anvil.endpoint_url(), "Unexpected config for Anvil instance."); - anvil -} - -pub async fn spawn_anvil_and_deploy_starknet_l1_contract( - config: &EthereumBaseLayerConfig, - url: &Url, -) -> (AnvilInstance, StarknetL1Contract) { - let anvil = anvil_instance_from_url(url); - let starknet_l1_contract = deploy_starknet_l1_contract(config.clone(), url).await; - (anvil, starknet_l1_contract) -} - -pub async fn deploy_starknet_l1_contract( - config: EthereumBaseLayerConfig, - url: &Url, -) -> StarknetL1Contract { - let ethereum_base_layer_contract = EthereumBaseLayerContract::new(config, url.clone()); - Starknet::deploy(ethereum_base_layer_contract.contract.provider().clone()).await.unwrap() -} - // FIXME: This should be part of AnvilBaseLayer, however the usage in the simulator doesn't allow // that, since it is coupled with a manual invocation of an anvil instance that is managed inside // the github workflow. From 649e92d6fa82e14d23b461adc8b96ce95facc104 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Fri, 31 Oct 2025 11:00:39 +0200 Subject: [PATCH 216/313] apollo_integration_tests: move anvil test util into single use-case (#7791) (#9721) Only this test now needs to initialize multiple anvil instances, since it's testing l1 node-switching. All other use cases were previously converted to use the more robust anvil base layer. Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../tests/happy_flow.rs | 17 +++++++++--- crates/papyrus_base_layer/src/test_utils.rs | 26 ------------------- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/crates/apollo_l1_endpoint_monitor/tests/happy_flow.rs b/crates/apollo_l1_endpoint_monitor/tests/happy_flow.rs index 36ec56893cb..58a226d6978 100644 --- a/crates/apollo_l1_endpoint_monitor/tests/happy_flow.rs +++ b/crates/apollo_l1_endpoint_monitor/tests/happy_flow.rs @@ -1,7 +1,7 @@ +use alloy::node_bindings::{Anvil, AnvilInstance}; use apollo_l1_endpoint_monitor::monitor::L1EndpointMonitor; use apollo_l1_endpoint_monitor_config::config::L1EndpointMonitorConfig; use apollo_l1_endpoint_monitor_types::L1EndpointMonitorError; -use papyrus_base_layer::test_utils::anvil; use url::Url; /// Integration test: two Anvil nodes plus a bogus endpoint to exercise cycling and failure. @@ -11,9 +11,10 @@ async fn end_to_end_cycle_and_recovery() { // IMPORTANT: This is one of the only cases where two anvil nodes are needed simultaneously, // since we are flow testing two separate L1 nodes. Other tests should never use more than one // at a time! - let good_node_1 = anvil(None); + let good_node_1 = anvil(); let good_url_1 = good_node_1.endpoint_url(); - let good_node_2 = anvil(None); + let good_node_2 = anvil(); + let good_url_2 = good_node_2.endpoint_url(); // Bogus endpoint on port 1 that is likely to be unbound, see the unit tests for more details. @@ -56,7 +57,7 @@ async fn end_to_end_cycle_and_recovery() { } // ANVIL node 1 has risen! - let good_node_1 = anvil(None); + let good_node_1 = anvil(); // Anvil is configured to use an ephemeral port, so this new node will be bound to a fresh port. // We cannot reuse the previous URL since the old port may no longer be available. let good_url_1 = good_node_1.endpoint_url(); @@ -66,3 +67,11 @@ async fn end_to_end_cycle_and_recovery() { assert_eq!(active3, good_url_1); assert_eq!(monitor.current_l1_endpoint_index, 1); } + +// IMPORTANT: this util is needed since this specific test must run two L1 instances by definition, +// for all other integration tests that need anvil use "anvil base layer". +fn anvil() -> AnvilInstance { + Anvil::new() + .try_spawn() + .expect("Anvil not installed, see anvil base layer for installation instructions.") +} diff --git a/crates/papyrus_base_layer/src/test_utils.rs b/crates/papyrus_base_layer/src/test_utils.rs index 9d0e9c5d91e..72d05b2acb9 100644 --- a/crates/papyrus_base_layer/src/test_utils.rs +++ b/crates/papyrus_base_layer/src/test_utils.rs @@ -2,11 +2,9 @@ use std::fs::File; use std::process::Command; use alloy::network::TransactionBuilder; -use alloy::node_bindings::{Anvil, AnvilInstance, NodeError as AnvilError}; use alloy::primitives::{address as ethereum_address, U256}; use alloy::providers::Provider; use alloy::rpc::types::TransactionRequest; -use colored::*; use ethers::utils::{Ganache, GanacheInstance}; use starknet_api::hash::StarkHash; use tar::Archive; @@ -100,30 +98,6 @@ pub fn get_test_ethereum_node() -> (TestEthereumNodeHandle, EthereumContractAddr ((ganache, ganache_db), SN_CONTRACT_ADDR.to_string().parse().unwrap()) } -// TODO(Arni): Make port non-optional. -// Spin up Anvil instance, a local Ethereum node, dies when dropped. -pub fn anvil(port: Option) -> AnvilInstance { - let mut anvil = Anvil::new(); - // If the port is not set explicitly, a random ephemeral port is bound and used. - if let Some(port) = port { - anvil = anvil.port(port); - } - - anvil.try_spawn().unwrap_or_else(|error| match error { - AnvilError::SpawnError(e) if e.to_string().contains("No such file or directory") => { - panic!( - "\n{}\n{}\n", - "Anvil binary not found!".bold().red(), - "Install instructions (for local development):\n - cargo install --git \ - https://github.com/foundry-rs/foundry anvil --locked --tag=v0.3.0" - .yellow() - ) - } - _ => panic!("Failed to spawn Anvil: {}", error.to_string().red()), - }) -} - // FIXME: This should be part of AnvilBaseLayer, however the usage in the simulator doesn't allow // that, since it is coupled with a manual invocation of an anvil instance that is managed inside // the github workflow. From ae63f6373bce66c47edd6b69713258b9ff7e01e8 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Fri, 31 Oct 2025 12:09:25 +0200 Subject: [PATCH 217/313] apollo_integration_tests: move anvil and associated tests into integration test crate (#8444) (#9722) These should only run as integration tests anyway, and since anvil is now there, it is the natural location for them (alternatively adding integration tests as a dev-dep will be expensive in compilation time). Co-authored-by: giladchase Co-authored-by: Gilad Chase --- Cargo.lock | 6 +++++- crates/apollo_integration_tests/Cargo.toml | 5 +++++ .../src/anvil_base_layer.rs | 19 ++++++++++++------- .../src/flow_test_setup.rs | 2 +- .../src/integration_test_manager.rs | 2 +- crates/apollo_integration_tests/src/lib.rs | 1 + crates/apollo_integration_tests/src/utils.rs | 2 +- .../tests/events_from_other_contracts.rs | 2 +- .../tests/l1_events_scraper_end_to_end.rs} | 2 +- crates/papyrus_base_layer/Cargo.toml | 2 -- crates/papyrus_base_layer/src/lib.rs | 1 - 11 files changed, 28 insertions(+), 16 deletions(-) rename crates/{papyrus_base_layer => apollo_integration_tests}/src/anvil_base_layer.rs (97%) rename crates/{papyrus_base_layer => apollo_integration_tests}/tests/events_from_other_contracts.rs (97%) rename crates/{apollo_l1_provider/tests/scraper_end_to_end.rs => apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs} (98%) diff --git a/Cargo.lock b/Cargo.lock index e2ecab92fcd..8a5d443645a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1583,7 +1583,9 @@ dependencies = [ "apollo_l1_gas_price", "apollo_l1_gas_price_provider_config", "apollo_l1_gas_price_types", + "apollo_l1_provider", "apollo_l1_provider_config", + "apollo_l1_provider_types", "apollo_l1_scraper_config", "apollo_mempool_config", "apollo_mempool_p2p_config", @@ -1600,17 +1602,20 @@ dependencies = [ "apollo_storage", "apollo_test_utils", "assert_matches", + "async-trait", "axum", "blockifier", "blockifier_test_utils", "cairo-lang-starknet-classes", "clap", + "colored 3.0.0", "futures", "hex", "indexmap 2.11.0", "mempool_test_utils", "metrics 0.24.2", "metrics-exporter-prometheus", + "mockall", "papyrus_base_layer", "pretty_assertions", "rstest", @@ -9708,7 +9713,6 @@ dependencies = [ "apollo_l1_endpoint_monitor_types", "assert_matches", "async-trait", - "colored 3.0.0", "ethers", "ethers-core", "futures", diff --git a/crates/apollo_integration_tests/Cargo.toml b/crates/apollo_integration_tests/Cargo.toml index a309b3709b7..d13572f889e 100644 --- a/crates/apollo_integration_tests/Cargo.toml +++ b/crates/apollo_integration_tests/Cargo.toml @@ -53,11 +53,13 @@ apollo_state_sync_metrics.workspace = true apollo_storage = { workspace = true, features = ["testing"] } apollo_test_utils.workspace = true assert_matches.workspace = true +async-trait.workspace = true axum.workspace = true blockifier = { workspace = true, features = ["testing"] } blockifier_test_utils.workspace = true cairo-lang-starknet-classes.workspace = true clap = { workspace = true, features = ["derive"] } +colored.workspace = true futures.workspace = true hex.workspace = true indexmap.workspace = true @@ -76,9 +78,12 @@ url.workspace = true [dev-dependencies] apollo_infra.workspace = true +apollo_l1_provider.workspace = true +apollo_l1_provider_types = { workspace = true, features = ["testing"] } futures.workspace = true metrics.workspace = true metrics-exporter-prometheus.workspace = true +mockall.workspace = true pretty_assertions.workspace = true rstest.workspace = true diff --git a/crates/papyrus_base_layer/src/anvil_base_layer.rs b/crates/apollo_integration_tests/src/anvil_base_layer.rs similarity index 97% rename from crates/papyrus_base_layer/src/anvil_base_layer.rs rename to crates/apollo_integration_tests/src/anvil_base_layer.rs index 9165432d260..49e68eb9271 100644 --- a/crates/papyrus_base_layer/src/anvil_base_layer.rs +++ b/crates/apollo_integration_tests/src/anvil_base_layer.rs @@ -6,19 +6,24 @@ use alloy::providers::{DynProvider, Provider, ProviderBuilder}; use alloy::rpc::types::TransactionReceipt; use async_trait::async_trait; use colored::*; -use starknet_api::block::BlockHashAndNumber; -use starknet_api::hash::StarkHash; -use starknet_api::transaction::L1HandlerTransaction; -use url::Url; - -use crate::ethereum_base_layer_contract::{ +use papyrus_base_layer::ethereum_base_layer_contract::{ EthereumBaseLayerConfig, EthereumBaseLayerContract, EthereumBaseLayerError, Starknet, StarknetL1Contract, }; -use crate::{BaseLayerContract, L1BlockHeader, L1BlockNumber, L1BlockReference, L1Event}; +use papyrus_base_layer::{ + BaseLayerContract, + L1BlockHeader, + L1BlockNumber, + L1BlockReference, + L1Event, +}; +use starknet_api::block::BlockHashAndNumber; +use starknet_api::hash::StarkHash; +use starknet_api::transaction::L1HandlerTransaction; +use url::Url; /// Initialize an anvil instance under the default port and deploy the Starknet contract. /// diff --git a/crates/apollo_integration_tests/src/flow_test_setup.rs b/crates/apollo_integration_tests/src/flow_test_setup.rs index 095f9f7fe20..f7f122c9c3e 100644 --- a/crates/apollo_integration_tests/src/flow_test_setup.rs +++ b/crates/apollo_integration_tests/src/flow_test_setup.rs @@ -30,7 +30,6 @@ use mempool_test_utils::starknet_api_test_utils::{ AccountTransactionGenerator, MultiAccountTransactionGenerator, }; -use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; use papyrus_base_layer::test_utils::{ make_block_history_on_anvil, @@ -54,6 +53,7 @@ use tokio::sync::Mutex; use tracing::{debug, instrument, Instrument}; use url::Url; +use crate::anvil_base_layer::AnvilBaseLayer; use crate::state_reader::{StorageTestHandles, StorageTestSetup}; use crate::utils::{ create_consensus_manager_configs_from_network_configs, diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index 21c99872da5..1bd849f3d40 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -29,7 +29,6 @@ use mempool_test_utils::starknet_api_test_utils::{ AccountId, MultiAccountTransactionGenerator, }; -use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; use papyrus_base_layer::test_utils::anvil_mine_blocks; use papyrus_base_layer::BaseLayerContract; use starknet_api::block::BlockNumber; @@ -42,6 +41,7 @@ use tokio::join; use tokio_util::task::AbortOnDropHandle; use tracing::{info, instrument}; +use crate::anvil_base_layer::AnvilBaseLayer; use crate::executable_setup::{ExecutableSetup, NodeExecutionId}; use crate::monitoring_utils::{ assert_no_reverted_txs, diff --git a/crates/apollo_integration_tests/src/lib.rs b/crates/apollo_integration_tests/src/lib.rs index 92e8dd84bf8..9eae4cf8c86 100644 --- a/crates/apollo_integration_tests/src/lib.rs +++ b/crates/apollo_integration_tests/src/lib.rs @@ -1,3 +1,4 @@ +pub mod anvil_base_layer; pub mod executable_setup; pub mod flow_test_setup; pub mod integration_test_manager; diff --git a/crates/apollo_integration_tests/src/utils.rs b/crates/apollo_integration_tests/src/utils.rs index fafa898c781..9992f9f820f 100644 --- a/crates/apollo_integration_tests/src/utils.rs +++ b/crates/apollo_integration_tests/src/utils.rs @@ -60,7 +60,6 @@ use blockifier::context::ChainInfo; use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use blockifier_test_utils::contracts::FeatureContract; use mempool_test_utils::starknet_api_test_utils::{AccountId, MultiAccountTransactionGenerator}; -use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerConfig; use serde::Deserialize; use serde_json::{json, to_value}; @@ -75,6 +74,7 @@ use tokio::task::JoinHandle; use tracing::{debug, info, Instrument}; use url::Url; +use crate::anvil_base_layer::AnvilBaseLayer; use crate::state_reader::StorageTestConfig; pub const ACCOUNT_ID_0: AccountId = 0; diff --git a/crates/papyrus_base_layer/tests/events_from_other_contracts.rs b/crates/apollo_integration_tests/tests/events_from_other_contracts.rs similarity index 97% rename from crates/papyrus_base_layer/tests/events_from_other_contracts.rs rename to crates/apollo_integration_tests/tests/events_from_other_contracts.rs index 170a6bcd0e5..e6651f39227 100644 --- a/crates/papyrus_base_layer/tests/events_from_other_contracts.rs +++ b/crates/apollo_integration_tests/tests/events_from_other_contracts.rs @@ -1,5 +1,5 @@ +use apollo_integration_tests::anvil_base_layer::{send_message_to_l2, AnvilBaseLayer}; use assert_matches::assert_matches; -use papyrus_base_layer::anvil_base_layer::{send_message_to_l2, AnvilBaseLayer}; use papyrus_base_layer::constants::{EventIdentifier, LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER}; use papyrus_base_layer::ethereum_base_layer_contract::Starknet; use papyrus_base_layer::{BaseLayerContract, L1Event}; diff --git a/crates/apollo_l1_provider/tests/scraper_end_to_end.rs b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs similarity index 98% rename from crates/apollo_l1_provider/tests/scraper_end_to_end.rs rename to crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs index 96331ce9259..3b2e200f29d 100644 --- a/crates/apollo_l1_provider/tests/scraper_end_to_end.rs +++ b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs @@ -2,13 +2,13 @@ use std::sync::Arc; use std::time::Duration; use alloy::primitives::U256; +use apollo_integration_tests::anvil_base_layer::AnvilBaseLayer; use apollo_l1_provider::event_identifiers_to_track; use apollo_l1_provider::l1_scraper::{fetch_start_block, L1Scraper}; use apollo_l1_provider_types::{Event, MockL1ProviderClient}; use apollo_l1_scraper_config::config::L1ScraperConfig; use mockall::predicate::eq; use mockall::Sequence; -use papyrus_base_layer::anvil_base_layer::AnvilBaseLayer; use papyrus_base_layer::test_utils::DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS; use papyrus_base_layer::BaseLayerContract; use starknet_api::block::BlockTimestamp; diff --git a/crates/papyrus_base_layer/Cargo.toml b/crates/papyrus_base_layer/Cargo.toml index 160eb6c98e0..4b8a088cff7 100644 --- a/crates/papyrus_base_layer/Cargo.toml +++ b/crates/papyrus_base_layer/Cargo.toml @@ -16,7 +16,6 @@ alloy = { workspace = true, features = ["contract", "json-rpc", "node-bindings", apollo_config.workspace = true apollo_l1_endpoint_monitor_types.workspace = true async-trait.workspace = true -colored.workspace = true ethers.workspace = true futures.workspace = true hex.workspace = true @@ -35,7 +34,6 @@ validator.workspace = true [dev-dependencies] apollo_l1_endpoint_monitor_types = { workspace = true, features = ["testing"] } assert_matches.workspace = true -colored.workspace = true ethers-core.workspace = true pretty_assertions.workspace = true starknet-types-core.workspace = true diff --git a/crates/papyrus_base_layer/src/lib.rs b/crates/papyrus_base_layer/src/lib.rs index 963aa0c4a0c..c5c13560f7c 100644 --- a/crates/papyrus_base_layer/src/lib.rs +++ b/crates/papyrus_base_layer/src/lib.rs @@ -14,7 +14,6 @@ use starknet_api::transaction::fields::{Calldata, Fee}; use starknet_api::transaction::L1HandlerTransaction; use url::Url; -pub mod anvil_base_layer; pub mod constants; pub mod ethereum_base_layer_contract; pub mod monitored_base_layer; From 2f65482ac1e5fb948e347b77eed66c9ec94b75a9 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Fri, 31 Oct 2025 12:54:25 +0200 Subject: [PATCH 218/313] apollo_integration_tests: ban `anvil` in unit tests (#8458) (#9723) Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/anvil_base_layer.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/apollo_integration_tests/src/anvil_base_layer.rs b/crates/apollo_integration_tests/src/anvil_base_layer.rs index 49e68eb9271..de4254caf18 100644 --- a/crates/apollo_integration_tests/src/anvil_base_layer.rs +++ b/crates/apollo_integration_tests/src/anvil_base_layer.rs @@ -44,10 +44,19 @@ impl AnvilBaseLayer { const DEFAULT_ANVIL_PORT: u16 = 8545; const DEFAULT_ANVIL_L1_DEPLOYED_ADDRESS: &str = "0x5fbdb2315678afecb367f032d93f642f64180aa3"; - /// Note: if you have port conflicts, this is because you are running anvil in unit tests, see - /// usage docstring of the struct. Alternatively, you might have a zombie anvil instance - /// running, but that should be impossible if using this service. + /// Note: if you have port conflicts, you might have a zombie anvil instance + /// running, but that should be impossible if using through this service, you probably have a + /// manually triggered Anvil instance somewhere in your shell. pub async fn new() -> Self { + let is_unit_test = cfg!(test); + if is_unit_test { + panic!( + "Don't use Anvil in unit tests, only in integration tests defined in the \ + integration tests crate. For unit tests, mock l1 using `alloy`'s mocked_provider \ + interface." + ); + } + // TODO(Arni): Remove the allow(deprecated) once we remove the deprecated function. #[allow(deprecated)] let anvil_client = ProviderBuilder::new() From 13b9881b07dc169da1f995b49808cb978da02452 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Fri, 31 Oct 2025 19:23:48 +0200 Subject: [PATCH 219/313] apollo_integration_tests: add mocked starknet contract (#8459) (#9724) * apollo_integration_tests: ban `anvil` in unit tests * l1: add mocked starknet contract Mocked contract has mocked initialize and update state functions, but is otherwise identical, is intended for use in anvil-based integraiton tests. Scraper test needed a fix, it wasn't passing fee, and not that the contract is initialized it checks this. Also the cancellation request wasn't sent from the correct sender, which was also not previously checked. --------- Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../src/anvil_base_layer.rs | 115 +++- .../tests/l1_events_scraper_end_to_end.rs | 43 +- .../mocked_starknet_state_update_test.rs | 90 +++ .../StarknetForSequencerTesting.json | 557 ++++++++++++++++++ .../src/ethereum_base_layer_contract.rs | 10 + 5 files changed, 795 insertions(+), 20 deletions(-) create mode 100644 crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs create mode 100644 crates/papyrus_base_layer/resources/StarknetForSequencerTesting.json diff --git a/crates/apollo_integration_tests/src/anvil_base_layer.rs b/crates/apollo_integration_tests/src/anvil_base_layer.rs index de4254caf18..c00c74a44aa 100644 --- a/crates/apollo_integration_tests/src/anvil_base_layer.rs +++ b/crates/apollo_integration_tests/src/anvil_base_layer.rs @@ -1,9 +1,11 @@ use std::ops::RangeInclusive; use alloy::node_bindings::NodeError as AnvilError; -use alloy::primitives::U256; +use alloy::primitives::{I256, U256}; use alloy::providers::{DynProvider, Provider, ProviderBuilder}; use alloy::rpc::types::TransactionReceipt; +use alloy::sol; +use alloy::sol_types::SolValue; use async_trait::async_trait; use colored::*; use papyrus_base_layer::ethereum_base_layer_contract::{ @@ -84,10 +86,13 @@ impl AnvilBaseLayer { let root_client = anvil_client.root().clone(); let contract = Starknet::new(config.starknet_contract_address, root_client); - Self { + let anvil_base_layer = Self { anvil_provider: anvil_client.erased(), ethereum_base_layer: EthereumBaseLayerContract { config, contract, url }, - } + }; + anvil_base_layer.initialize_mocked_starknet_contract().await; + + anvil_base_layer } pub async fn send_message_to_l2( @@ -107,6 +112,66 @@ impl AnvilBaseLayer { ..Default::default() } } + + pub async fn update_mocked_starknet_contract_state( + &self, + update: MockedStateUpdate, + ) -> Result<(), EthereumBaseLayerError> { + // Size out output in the starknet contract, most of these aren't checked in the mock. + let mut output = vec![U256::from(0); starknet_output::HEADER_SIZE + 2]; + + output[starknet_output::PREV_BLOCK_NUMBER_OFFSET] = U256::from(update.new_block_number - 1); + output[starknet_output::NEW_BLOCK_NUMBER_OFFSET] = U256::from(update.new_block_number); + output[starknet_output::PREV_BLOCK_HASH_OFFSET] = U256::from(update.prev_block_hash); + output[starknet_output::NEW_BLOCK_HASH_OFFSET] = U256::from(update.new_block_hash); + + // Run eth_call first, which simulates the tx and returns errors, unlike eth_send which + // executes without returning errors or output from the contract. + // Note: if this fails and this is the first state update, make sure to set the previous + // block number as 1 and the previous block hash as 0, as documented in the contract + // initializer. + self.ethereum_base_layer + .contract + .updateState(output.clone(), Default::default()) + .call() + .await?; + + self.ethereum_base_layer + .contract + .updateState(output, Default::default()) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + Ok(()) + } + + /// Initialize the mocked Starknet contract with default test values and first block number and + /// hash as 1. + /// + /// Other values are boilerplate to match the offsets in the Starknet solidity contract, a + /// better mock can remove those as well. + /// NOTE: right now this is coupled with the conditionally compiled mocked starknet account at + /// EthereumBaseLayer; It'd be best if it could be included here instead, but this seems + /// nontrivial without duplicating EthereumBaseLayer, which is self-defeating for a test. + async fn initialize_mocked_starknet_contract(&self) { + let init_data = InitializeData { + programHash: U256::from(1), + configHash: U256::from(1), + initialState: StateUpdate { + blockNumber: I256::from_dec_str("1").unwrap(), + ..Default::default() + }, + ..Default::default() + }; + + let encoded_data = init_data.abi_encode(); + let builder = self.ethereum_base_layer.contract.initializeMock(encoded_data.into()); + builder.send().await.unwrap().get_receipt().await.unwrap(); + } } #[async_trait] @@ -198,3 +263,47 @@ pub async fn send_message_to_l2( // Waits until the transaction is received on L1 and then fetches its receipt. .get_receipt().await.expect("Transaction was not received on L1 or receipt retrieval failed.") } + +pub struct MockedStateUpdate { + pub new_block_number: u64, + pub new_block_hash: u64, + // Consider caching and auto-filling this for better UX. + pub prev_block_hash: u64, +} + +// The following structures are used with a mocked version of the Starknet L1 contract. +// This mocked contract (starknet_for_testing.json) differs from the production contract: +// - Includes an `initializeMock` function that bypasses governance requirements. +// - The `updateState` function doesn't require special permissions. +// - Removed a bunch of checks and functionality not necessary and that was difficult to mock,and +// that are not called from the sequencer at this time. +// - Used exclusively for integration testing with Anvil. +sol! { + #[derive(Debug, Default)] + struct StateUpdate { + uint256 globalRoot; + int256 blockNumber; + uint256 blockHash; + } + + #[derive(Debug, Default)] + struct InitializeData { + uint256 programHash; + uint256 aggregatorProgramHash; + address verifier; + uint256 configHash; + StateUpdate initialState; + } +} + +/// Output offsets from the Starknet solidity contract. These correspond to `StarknetOutput`, +/// defined in the public `Output.sol` contract. These are the only offsets for values currently +/// used in the starknet contract mock, if more are needed, which isn't likely, grab the offsets +/// from Output.sol. +mod starknet_output { + pub const PREV_BLOCK_NUMBER_OFFSET: usize = 2; + pub const NEW_BLOCK_NUMBER_OFFSET: usize = 3; + pub const PREV_BLOCK_HASH_OFFSET: usize = 4; + pub const NEW_BLOCK_HASH_OFFSET: usize = 5; + pub const HEADER_SIZE: usize = 10; +} diff --git a/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs index 3b2e200f29d..22cdbcdc50f 100644 --- a/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs +++ b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs @@ -37,27 +37,35 @@ async fn scraper_end_to_end() { // Send messages from L1 to L2. let l2_contract_address = "0x12"; let l2_entry_point = "0x34"; - let message_to_l2_0 = contract.sendMessageToL2( - l2_contract_address.parse().unwrap(), - l2_entry_point.parse().unwrap(), - vec![U256::from(1_u8), U256::from(2_u8)], - ); - let message_to_l2_1 = contract.sendMessageToL2( - l2_contract_address.parse().unwrap(), - l2_entry_point.parse().unwrap(), - vec![U256::from(3_u8), U256::from(4_u8)], - ); + let fee = 1_u8; + let message_to_l2_0 = contract + .sendMessageToL2( + l2_contract_address.parse().unwrap(), + l2_entry_point.parse().unwrap(), + vec![U256::from(1_u8), U256::from(2_u8)], + ) + .value(U256::from(fee)); + let message_to_l2_1 = contract + .sendMessageToL2( + l2_contract_address.parse().unwrap(), + l2_entry_point.parse().unwrap(), + vec![U256::from(3_u8), U256::from(4_u8)], + ) + .value(U256::from(fee)); let nonce_of_message_to_l2_0 = U256::from(0_u8); - let request_cancel_message_0 = contract.startL1ToL2MessageCancellation( - l2_contract_address.parse().unwrap(), - l2_entry_point.parse().unwrap(), - vec![U256::from(1_u8), U256::from(2_u8)], - nonce_of_message_to_l2_0, - ); + let request_cancel_message_0 = contract + .startL1ToL2MessageCancellation( + l2_contract_address.parse().unwrap(), + l2_entry_point.parse().unwrap(), + vec![U256::from(1_u8), U256::from(2_u8)], + nonce_of_message_to_l2_0, + ) + .from(DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS.to_hex_string().parse().unwrap()); // Send the transactions to Anvil, and record the timestamps of the blocks they are included in. let mut l1_handler_timestamps: Vec = Vec::with_capacity(2); for msg in &[message_to_l2_0, message_to_l2_1] { + msg.call().await.unwrap(); // Query for errors. let receipt = msg.send().await.unwrap().get_receipt().await.unwrap(); l1_handler_timestamps.push( base_layer @@ -69,6 +77,7 @@ async fn scraper_end_to_end() { ); } + request_cancel_message_0.call().await.unwrap(); // Query for errors; let cancel_receipt = request_cancel_message_0.send().await.unwrap().get_receipt().await.unwrap(); let cancel_timestamp = base_layer @@ -95,7 +104,7 @@ async fn scraper_end_to_end() { let expected_executable_l1_handler_0 = ExecutableL1HandlerTransaction { tx_hash: tx_hash_first_tx, tx: expected_l1_handler_0, - paid_fee_on_l1: Fee(0), + paid_fee_on_l1: Fee(fee.into()), }; let first_expected_log = Event::L1HandlerTransaction { l1_handler_tx: expected_executable_l1_handler_0.clone(), diff --git a/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs b/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs new file mode 100644 index 00000000000..d65f388cdbc --- /dev/null +++ b/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs @@ -0,0 +1,90 @@ +use alloy::primitives::{I256, U256}; +use alloy::providers::Provider; +use alloy::rpc::types::eth::Filter as EthEventFilter; +use alloy::sol_types::SolEventInterface; +use apollo_integration_tests::anvil_base_layer::{AnvilBaseLayer, MockedStateUpdate}; +use papyrus_base_layer::ethereum_base_layer_contract::Starknet; +use papyrus_base_layer::BaseLayerContract; +use pretty_assertions::assert_eq; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; + +#[tokio::test] +async fn test_mocked_starknet_state_update() { + let base_layer = AnvilBaseLayer::new().await; + + // Check that the contract was initialized (during the construction above). + let no_finality = 0; + let genesis_block_number = 1; + let genesis_block_hash = 0; + let initial_state = base_layer.latest_proved_block(no_finality).await.unwrap().unwrap(); + assert_eq!( + initial_state.number, + BlockNumber(genesis_block_number), + "Starknet contract was not initiailized." + ); + assert_eq!( + initial_state.hash, + BlockHash(genesis_block_hash.into()), + "Starknet contract was not initiailized." + ); + + // Negative flow: update state should always have sequential block numbers. + let wrong_next_block_number = genesis_block_number + 2; + let incorrect_new_block_number_result = base_layer + .update_mocked_starknet_contract_state(MockedStateUpdate { + new_block_number: wrong_next_block_number, + new_block_hash: 2, + prev_block_hash: genesis_block_hash, + }) + .await; + assert!( + incorrect_new_block_number_result + .unwrap_err() + .to_string() + .contains("INVALID_PREV_BLOCK_NUMBER") + ); + + // Happy flow. + let next_block_number = genesis_block_number + 1; + let new_block_hash = 2; + base_layer + .update_mocked_starknet_contract_state(MockedStateUpdate { + new_block_number: next_block_number, + new_block_hash, + prev_block_hash: genesis_block_hash, + }) + .await + .unwrap(); + + let updated_block_number_and_hash = + base_layer.latest_proved_block(no_finality).await.unwrap().unwrap(); + assert_eq!( + updated_block_number_and_hash, + BlockHashAndNumber { + number: BlockNumber(next_block_number), + hash: BlockHash(new_block_hash.into()) + } + ); + + // Check that LogStateUpdate event was emitted (we don't use this event in the sequencer at the + // time this was written). + let event = base_layer + .ethereum_base_layer + .contract + .provider() + .get_logs(&EthEventFilter::new().from_block(1)) + .await + .unwrap(); + let event = event.first().unwrap(); + + match Starknet::StarknetEvents::decode_log(&event.inner).unwrap().data { + Starknet::StarknetEvents::LogStateUpdate(state_update) => { + assert_eq!( + state_update.blockNumber, + I256::from_dec_str(&next_block_number.to_string()).unwrap(), + ); + assert_eq!(state_update.blockHash, U256::from(new_block_hash)); + } + _ => panic!("Expected LogStateUpdate event"), + } +} diff --git a/crates/papyrus_base_layer/resources/StarknetForSequencerTesting.json b/crates/papyrus_base_layer/resources/StarknetForSequencerTesting.json new file mode 100644 index 00000000000..4a337e6be78 --- /dev/null +++ b/crates/papyrus_base_layer/resources/StarknetForSequencerTesting.json @@ -0,0 +1,557 @@ +{ + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fromAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "toAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "ConsumedMessageToL1", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "ConsumedMessageToL2", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fromAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "toAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "LogMessageToL1", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "LogMessageToL2", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "globalRoot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "blockNumber", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "blockHash", + "type": "uint256" + } + ], + "name": "LogStateUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "MessageToL2Canceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "MessageToL2CancellationStarted", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "cancelL1ToL2Message", + "outputs": [ + { "internalType": "bytes32", "name": "", "type": "bytes32" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "configHash", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fromAddress", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "consumeMessageFromL2", + "outputs": [ + { "internalType": "bytes32", "name": "", "type": "bytes32" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "feeCollector", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaxL1MsgFee", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes", "name": "initData", "type": "bytes" } + ], + "name": "initializeMock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "l1ToL2MessageCancellations", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1ToL2MessageNonce", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "l1ToL2Messages", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "fromAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "l1ToL2MsgHash", + "outputs": [ + { "internalType": "bytes32", "name": "", "type": "bytes32" } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "l2ToL1Messages", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fromAddress", + "type": "uint256" + }, + { + "internalType": "address", + "name": "toAddress", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "l2ToL1MsgHash", + "outputs": [ + { "internalType": "bytes32", "name": "", "type": "bytes32" } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "messageCancellationDelay", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "programHash", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + } + ], + "name": "sendMessageToL2", + "outputs": [ + { "internalType": "bytes32", "name": "", "type": "bytes32" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "toAddress", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "selector", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "payload", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "startL1ToL2MessageCancellation", + "outputs": [ + { "internalType": "bytes32", "name": "", "type": "bytes32" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stateBlockHash", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stateBlockNumber", + "outputs": [ + { "internalType": "int256", "name": "", "type": "int256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stateRoot", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "programOutput", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "onchainDataSize", + "type": "uint256" + } + ], + "name": "updateState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b506120458061001c5f395ff3fe60806040526004361061011b575f3560e01c806377c7d7a91161009d5780639be446bf116100625780639be446bf146102c7578063a46efaf3146102e6578063b64b673714610305578063c415b95c14610324578063e1f1176d14610350575f5ffd5b806377c7d7a91461024d5780637a98660b1461026c5780638303bd8a1461028b5780638a9bf0901461029f5780639588eca2146102b3575f5ffd5b80633e3aa6c5116100e35780633e3aa6c5146101ac57806354eccba4146101d45780636170ff1b146101ee57806363142fb81461020d5780636e107a8c1461022e575f5ffd5b8063018cccdf1461011f5780632c9dd5c01461014657806335befa5d14610165578063382d83e3146101795780633d8a5df81461018d575b5f5ffd5b34801561012a575f5ffd5b50610133610364565b6040519081526020015b60405180910390f35b348015610151575f5ffd5b506101336101603660046119b3565b6103a8565b348015610170575f5ffd5b5061013361049b565b348015610184575f5ffd5b506101336104ad565b348015610198575f5ffd5b506101336101a7366004611a11565b6104bf565b6101bf6101ba366004611a67565b610503565b6040805192835260208301919091520161013d565b3480156101df575f5ffd5b50670de0b6b3a7640000610133565b3480156101f9575f5ffd5b50610133610208366004611a9e565b610694565b348015610218575f5ffd5b5061022c610227366004611af4565b6108a8565b005b348015610239575f5ffd5b5061022c610248366004611b3c565b610990565b348015610258575f5ffd5b50610133610267366004611baa565b6109fa565b348015610277575f5ffd5b50610133610286366004611a9e565b610a13565b348015610296575f5ffd5b50610133610aed565b3480156102aa575f5ffd5b50610133610b0f565b3480156102be575f5ffd5b50610133610b31565b3480156102d2575f5ffd5b506101336102e1366004611baa565b610b40565b3480156102f1575f5ffd5b50610133610300366004611baa565b610b49565b348015610310575f5ffd5b5061013361031f366004611bc1565b610b52565b34801561032f575f5ffd5b50610338610b9c565b6040516001600160a01b03909116815260200161013d565b34801561035b575f5ffd5b50610133610bdb565b5f6103a36040518060400160405280602081526020017f535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4e4f4e4345815250610bf9565b905090565b5f5f6103b6853386866104bf565b90505f6103c1610c2c565b5f8381526020919091526040902054116104225760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f4d4553534147455f544f5f434f4e53554d4500000000000060448201526064015b60405180910390fd5b336001600160a01b0316857f7a06c571aa77f34d9706c51e5d8122b5595aebeaa34233bfe866f22befb973b1868660405161045e929190611c5c565b60405180910390a36001610470610c2c565b5f8381526020019081526020015f205f82825461048d9190611c8b565b909155509095945050505050565b5f6104a4610c4e565b60010154905090565b5f6104b6610c4e565b60020154905090565b6040515f906104e39086906001600160a01b03871690859087908290602001611cc5565b604051602081830303815290604052805190602001209050949350505050565b5f5f5f341161055e5760405162461bcd60e51b815260206004820152602160248201527f4c315f4d53475f4645455f4d5553545f42455f475245415445525f5448414e5f6044820152600360fc1b6064820152608401610419565b670de0b6b3a76400003411156105b65760405162461bcd60e51b815260206004820152601760248201527f4d41585f4c315f4d53475f4645455f45584345454445440000000000000000006044820152606401610419565b5f6105bf610364565b905061060c6040518060400160405280602081526020017f535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4e4f4e43458152508260016106079190611cee565b610c97565b8587336001600160a01b03167fdb80dd488acf86d17c747445b0eabb5d57c541d3bd7b6b87af987858e5066b2b8888863460405161064d9493929190611d01565b60405180910390a45f610664338989898987610b52565b9050610671346001611cee565b610679610cc9565b5f838152602091909152604090205597909650945050505050565b5f8486336001600160a01b03167f8abd2ec2e0a10c82f5b60ea00455fa96c41fd144f225fcc52b8d83d94f803ed88787876040516106d493929190611d27565b60405180910390a45f6106eb338888888888610b52565b90505f6106f6610cc9565b5f8381526020919091526040812054915081900361074d5760405162461bcd60e51b81526020600482015260146024820152731393d7d35154d4d051d157d513d7d0d05390d15360621b6044820152606401610419565b5f610756610ceb565b5f848152602091909152604081205491508190036107c15760405162461bcd60e51b815260206004820152602260248201527f4d4553534147455f43414e43454c4c4154494f4e5f4e4f545f52455155455354604482015261115160f21b6064820152608401610419565b5f6107ca610aed565b6107d49083611cee565b9050818110156108265760405162461bcd60e51b815260206004820152601c60248201527f43414e43454c5f414c4c4f5745445f54494d455f4f564552464c4f57000000006044820152606401610419565b804210156108825760405162461bcd60e51b8152602060048201526024808201527f4d4553534147455f43414e43454c4c4154494f4e5f4e4f545f414c4c4f57454460448201526317d6515560e21b6064820152608401610419565b5f61088b610cc9565b5f8681526020919091526040902055509198975050505050505050565b600a82116108f85760405162461bcd60e51b815260206004820152601960248201527f535441524b4e45545f4f55545055545f544f4f5f53484f5254000000000000006044820152606401610419565b61090c8383610905610c4e565b9190610d0d565b8282600881811061091f5761091f611d4a565b905060200201355f1461096d5760405162461bcd60e51b8152602060048201526016602482015275554e45585045435445445f4b5a475f44415f464c414760501b6044820152606401610419565b6109778383610da1565b61098b8383610984610c4e565b9190610f3c565b505050565b610998610f9d565b156109e65780156109e25760405162461bcd60e51b8152602060048201526014602482015273554e45585045435445445f494e49545f4441544160601b6044820152606401610419565b5050565b6109f08282610fad565b6109e28282611057565b5f610a03610cc9565b5f92835260205250604090205490565b5f8486336001600160a01b03167f2e00dccd686fd6823ec7dc3e125582aa82881b6ff5f6b5a73856e1ea8338a3be878787604051610a5393929190611d27565b60405180910390a45f610a6a338888888888610b52565b90505f610a75610cc9565b5f8381526020919091526040902054905080610aca5760405162461bcd60e51b81526020600482015260146024820152731393d7d35154d4d051d157d513d7d0d05390d15360621b6044820152606401610419565b42610ad3610ceb565b5f8481526020919091526040902055509695505050505050565b5f6103a36040518060600160405280602d8152602001611f4c602d9139610bf9565b5f6103a3604051806060016040528060268152602001611f2660269139610bf9565b5f610b3a610c4e565b54919050565b5f610a03610ceb565b5f610a03610c2c565b6040515f90610b7a906001600160a01b0389169088908590899088908a908290602001611d5e565b6040516020818303038152906040528051906020012090509695505050505050565b5f6103a36040518060400160405280601f81526020017f4645455f434f4c4c454354494f4e5f414444524553535f534c4f545f54414700815250610bf9565b5f6103a3604051806060016040528060248152602001611f79602491395b5f5f82604051602001610c0c9190611d95565b60408051601f198184030181529190528051602090910120549392505050565b5f6103a3604051806060016040528060238152602001611f9d602391396110b8565b5f5f6040518060600160405280602a8152602001611fc0602a9139604051602001610c799190611d95565b60408051601f19818403018152919052805160209091012092915050565b5f82604051602001610ca99190611d95565b604051602081830303815290604052805190602001209050818155505050565b5f6103a3604051806060016040528060268152602001611fea602691396110b8565b5f6103a3604051806060016040528060308152602001611ef6603091396110b8565b5f83600101545f1903610d2c575067080000000000001160c01b610d33565b5060018301545b8083836002818110610d4757610d47611d4a565b9050602002013514610d9b5760405162461bcd60e51b815260206004820152601960248201527f494e56414c49445f505245565f424c4f434b5f4e554d424552000000000000006044820152606401610419565b50505050565b610dab82826110ea565b81816009818110610dbe57610dbe611d4a565b905060200201355f14610e135760405162461bcd60e51b815260206004820152601960248201527f46554c4c5f4f55545055545f4e4f545f535550504f52544544000000000000006044820152606401610419565b610e278282610e20610c4e565b919061117d565b5f610e328383611293565b90505f610e3d611330565b9050610e5e6001610e5085858189611dab565b610e58610c2c565b85611356565b610e689083611cee565b9150610e825f610e7a85858189611dab565b610e58610cc9565b610e8c9083611cee565b9150828214610edd5760405162461bcd60e51b815260206004820152601860248201527f535441524b4e45545f4f55545055545f544f4f5f4c4f4e4700000000000000006044820152606401610419565b5f610ee6610c4e565b805460018201546002830154604080519384526020840192909252908201529091507fd342ddf7a308dec111745b00315c14b7efb2bdae570a6856e088ed0c65a3576c9060600160405180910390a15050505050565b81816003818110610f4f57610f4f611d4a565b9050602002013583600101541461098b5760405162461bcd60e51b81526020600482015260126024820152715245454e5452414e43595f4641494c55524560701b6044820152606401610419565b5f610fa6610b0f565b1515919050565b60e08114610ff65760405162461bcd60e51b8152602060048201526016602482015275494c4c4547414c5f494e49545f444154415f53495a4560501b6044820152606401610419565b5f6110046020828486611dd6565b8101906110119190611baa565b9050805f0361098b5760405162461bcd60e51b81526020600482015260126024820152712120a22fa4a724aa24a0a624ad20aa24a7a760711b6044820152606401610419565b5f808061106684860186611dfd565b92509250925061107583611902565b61109c81611081610c4e565b90805182556020810151600183015560400151600290910155565b6110a582611927565b6110b162069780611949565b5050505050565b5f5f826040516020016110cb9190611d95565b60408051601f1981840301815291905280516020909101209392505050565b6001600167080000000000001160c01b01602083028401845b81811015611123578281351061111b575f9350611123565b602001611103565b5050508061098b5760405162461bcd60e51b815260206004820152602160248201527f50524f4752414d5f4f55545055545f56414c55455f4f55545f4f465f52414e476044820152604560f81b6064820152608401610419565b611188838383610d0d565b5f8282600381811061119c5761119c611d4a565b905060200201359050836001015481136111f85760405162461bcd60e51b815260206004820152601860248201527f494e56414c49445f4e45575f424c4f434b5f4e554d42455200000000000000006044820152606401610419565b6001840181905560028401548383600481811061121757611217611d4a565b905060200201351461126b5760405162461bcd60e51b815260206004820152601760248201527f494e56414c49445f505245565f424c4f434b5f484153480000000000000000006044820152606401610419565b8282600581811061127e5761127e611d4a565b90506020020135846002018190555050505050565b5f828260088181106112a7576112a7611d4a565b905060200201355f036112bc5750600a61132a565b5f83836112cb6001600a611cee565b8181106112da576112da611d4a565b9050602002013590508060026112f09190611e86565b6112fb826002611e86565b611307600a6001611cee565b611312906001611cee565b61131c9190611cee565b6113269190611cee565b9150505b92915050565b5f5f61133a610b9c565b90506001600160a01b038116611351573391505090565b919050565b5f5f85855f81811061136a5761136a611d4a565b905060200201359050634000000081106113c65760405162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f4d4553534147455f5345474d454e545f53495a45000000006044820152606401610419565b60015f6113d38383611cee565b90505f896113e25760046113e5565b60025b90505f5b82841015611807575f806113fd8487611cee565b90508a81106114425760405162461bcd60e51b8152602060048201526011602482015270135154d4d051d157d513d3d7d4d213d495607a1b6044820152606401610419565b5f8c8c8381811061145557611455611d4a565b905060200201359050634000000081106114aa5760405162461bcd60e51b81526020600482015260166024820152750929cac82989288bea082b2989e8288be988a9c8ea8960531b6044820152606401610419565b806114b6836001611cee565b6114c09190611cee565b92508b8311156115125760405162461bcd60e51b815260206004820152601960248201527f5452554e43415445445f4d4553534147455f5041594c4f4144000000000000006044820152606401610419565b50508b1561161e575f61152782878d8f611dab565b604051602001611538929190611e9d565b6040516020818303038152906040528051906020012090508b8b60018861155f9190611cee565b81811061156e5761156e611d4a565b905060200201356001600160a01b03168c8c5f8961158c9190611cee565b81811061159b5761159b611d4a565b905060200201357f4264ac208b5fde633ccdd42e0f12c3d6d443a4f3779bbf886925b94665b63a228e8e60038b6115d29190611cee565b6115de92889290611dab565b6040516115ec929190611c5c565b60405180910390a35f81815260208b905260408120805460019290611612908490611cee565b90915550611800915050565b5f61162b82878d8f611dab565b60405160200161163c929190611e9d565b60408051601f1981840301815291815281516020928301205f818152928d9052912054909150806116af5760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f4d4553534147455f544f5f434f4e53554d450000000000006044820152606401610419565b6116ba600182611c8b565b6116c49085611cee565b5f92835260208c90526040832083905593508c90508b6116e5600289611cee565b8181106116f4576116f4611d4a565b9050602002013590505f8c8c60058961170d9190611cee565b61171992869290611dab565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152509293508f92508e915061175c905060038a611cee565b81811061176b5761176b611d4a565b905060200201358d8d60018a6117819190611cee565b81811061179057611790611d4a565b905060200201358e8e5f8b6117a59190611cee565b8181106117b4576117b4611d4a565b905060200201356001600160a01b03167f9592d37825c744e33fa80c469683bbd04d336241bb600b574758efd182abe26a84866040516117f5929190611ea9565b60405180910390a450505b93506113e9565b8284146118565760405162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f4d4553534147455f5345474d454e545f53495a45000000006044820152606401610419565b80156118f3575f876001600160a01b0316826040515f6040518083038185875af1925050503d805f81146118a5576040519150601f19603f3d011682016040523d82523d5f602084013e6118aa565b606091505b50509050806118f15760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610419565b505b50919998505050505050505050565b611924604051806060016040528060268152602001611f266026913982610c97565b50565b611924604051806060016040528060248152602001611f796024913982610c97565b6119246040518060600160405280602d8152602001611f4c602d913982610c97565b5f5f83601f84011261197b575f5ffd5b50813567ffffffffffffffff811115611992575f5ffd5b6020830191508360208260051b85010111156119ac575f5ffd5b9250929050565b5f5f5f604084860312156119c5575f5ffd5b83359250602084013567ffffffffffffffff8111156119e2575f5ffd5b6119ee8682870161196b565b9497909650939450505050565b80356001600160a01b0381168114611351575f5ffd5b5f5f5f5f60608587031215611a24575f5ffd5b84359350611a34602086016119fb565b9250604085013567ffffffffffffffff811115611a4f575f5ffd5b611a5b8782880161196b565b95989497509550505050565b5f5f5f5f60608587031215611a7a575f5ffd5b8435935060208501359250604085013567ffffffffffffffff811115611a4f575f5ffd5b5f5f5f5f5f60808688031215611ab2575f5ffd5b8535945060208601359350604086013567ffffffffffffffff811115611ad6575f5ffd5b611ae28882890161196b565b96999598509660600135949350505050565b5f5f5f60408486031215611b06575f5ffd5b833567ffffffffffffffff811115611b1c575f5ffd5b611b288682870161196b565b909790965060209590950135949350505050565b5f5f60208385031215611b4d575f5ffd5b823567ffffffffffffffff811115611b63575f5ffd5b8301601f81018513611b73575f5ffd5b803567ffffffffffffffff811115611b89575f5ffd5b856020828401011115611b9a575f5ffd5b6020919091019590945092505050565b5f60208284031215611bba575f5ffd5b5035919050565b5f5f5f5f5f5f60a08789031215611bd6575f5ffd5b611bdf876119fb565b95506020870135945060408701359350606087013567ffffffffffffffff811115611c08575f5ffd5b611c1489828a0161196b565b979a9699509497949695608090950135949350505050565b8183525f6001600160fb1b03831115611c43575f5ffd5b8260051b80836020870137939093016020019392505050565b602081525f611c6f602083018486611c2c565b949350505050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561132a5761132a611c77565b5f6001600160fb1b03831115611cb2575f5ffd5b8260051b80838637939093019392505050565b8581528460208201528360408201525f611ce3606083018486611c9e565b979650505050505050565b8082018082111561132a5761132a611c77565b606081525f611d14606083018688611c2c565b6020830194909452506040015292915050565b604081525f611d3a604083018587611c2c565b9050826020830152949350505050565b634e487b7160e01b5f52603260045260245ffd5b8781528660208201528560408201528460608201528360808201525f611d8860a083018486611c9e565b9998505050505050505050565b5f82518060208501845e5f920191825250919050565b5f5f85851115611db9575f5ffd5b83861115611dc5575f5ffd5b5050600583901b0193919092039150565b5f5f85851115611de4575f5ffd5b83861115611df0575f5ffd5b5050820193919092039150565b5f5f5f83850360a0811215611e10575f5ffd5b84359350602085013592506060603f1982011215611e2c575f5ffd5b506040516060810181811067ffffffffffffffff82111715611e5c57634e487b7160e01b5f52604160045260245ffd5b60409081528581013582526060860135602083015260809095013594810194909452509093909250565b808202811582820484141761132a5761132a611c77565b5f611c6f828486611c9e565b604080825283519082018190525f9060208501906060840190835b81811015611ee2578351835260209384019390920191600101611ec4565b505060209390930193909352509291505056fe535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f43414e43454c4c4154494f4e5f4d41505050494e474d4f434b5f535441524b4e45542e305f494e49545f50524f4752414d5f484153485f55494e54535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f43414e43454c4c4154494f4e5f44454c41594d4f434b5f535441524b4e45542e305f535441524b4e45545f434f4e4649475f48415348535441524b4e45545f312e305f4d5347494e475f4c32544f4c315f4d41505050494e474d4f434b5f535441524b4e45542e305f494e49545f535441524b4e45545f53544154455f535452554354535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4d41505050494e475f5632a2646970667358221220d9005266682d99d8505ab7e1245d78941da643a272fac5f08c3c38a0e69e849064736f6c634300081d0033" +} diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index 00ef6d92e8f..f165ba32ede 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -41,6 +41,16 @@ pub type EthereumContractAddress = Address; // Wraps the Starknet contract with a type that implements its interface, and is aware of its // events. + +#[cfg(any(test, feature = "testing"))] +// Mocked Starknet contract for testing (no governance). +sol!( + #[sol(rpc)] + Starknet, + "resources/StarknetForSequencerTesting.json" +); +#[cfg(not(any(test, feature = "testing")))] +// Real Starknet contract for production. sol!( #[sol(rpc)] Starknet, From 472dd05a9782b04e7fc5ff79d964f7eaa89a264c Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Sun, 2 Nov 2025 08:51:03 +0200 Subject: [PATCH 220/313] apollo_consensus: make timeouts + sync_retry_interval dynamic (#9767) --- config/papyrus/default_config.json | 10 ++-- .../src/config_manager_runner_tests.rs | 8 ++- .../src/config_manager_tests.rs | 2 +- crates/apollo_consensus/src/manager.rs | 4 +- crates/apollo_consensus/src/manager_test.rs | 39 +++++++------ crates/apollo_consensus_config/src/config.rs | 52 +++++++++-------- .../app_configs/consensus_manager_config.json | 10 ++-- crates/apollo_integration_tests/src/utils.rs | 13 ++++- .../apollo_node/resources/config_schema.json | 10 ++-- ...fig__config_test__dump_default_config.snap | 56 +++++++++---------- 10 files changed, 108 insertions(+), 96 deletions(-) diff --git a/config/papyrus/default_config.json b/config/papyrus/default_config.json index 92eb759fc35..0ba1b5d03b9 100644 --- a/config/papyrus/default_config.json +++ b/config/papyrus/default_config.json @@ -114,22 +114,22 @@ "privacy": "Public", "value": 5 }, - "consensus.static_config.sync_retry_interval": { + "consensus.dynamic_config.sync_retry_interval": { "description": "The duration (seconds) between sync attempts.", "privacy": "Public", "value": 1.0 }, - "consensus.static_config.timeouts.precommit_timeout": { + "consensus.dynamic_config.timeouts.precommit_timeout": { "description": "The timeout (seconds) for a precommit.", "privacy": "Public", "value": 1.0 }, - "consensus.static_config.timeouts.prevote_timeout": { + "consensus.dynamic_config.timeouts.prevote_timeout": { "description": "The timeout (seconds) for a prevote.", "privacy": "Public", "value": 1.0 }, - "consensus.static_config.timeouts.proposal_timeout": { + "consensus.dynamic_config.timeouts.proposal_timeout": { "description": "The timeout (seconds) for a proposal.", "privacy": "Public", "value": 3.0 @@ -584,4 +584,4 @@ "privacy": "Public", "value": true } -} +} \ No newline at end of file diff --git a/crates/apollo_config_manager/src/config_manager_runner_tests.rs b/crates/apollo_config_manager/src/config_manager_runner_tests.rs index 999af19905f..da1785f9551 100644 --- a/crates/apollo_config_manager/src/config_manager_runner_tests.rs +++ b/crates/apollo_config_manager/src/config_manager_runner_tests.rs @@ -153,6 +153,7 @@ fn log_config_diff_changes() { let old_dynamic_config = NodeDynamicConfig { consensus_dynamic_config: Some(ConsensusDynamicConfig { validator_id: ContractAddress::from(1u128), + ..Default::default() }), ..Default::default() }; @@ -160,6 +161,7 @@ fn log_config_diff_changes() { let new_dynamic_config = NodeDynamicConfig { consensus_dynamic_config: Some(ConsensusDynamicConfig { validator_id: ContractAddress::from(2u128), + ..Default::default() }), ..Default::default() }; @@ -174,7 +176,7 @@ fn log_config_diff_changes() { runner.log_config_diff(&old_dynamic_config, &new_dynamic_config); - assert!(logs_contain( - r#"consensus_dynamic_config changed from {"validator_id":"0x1"} to {"validator_id":"0x2"}"# - )); + assert!(logs_contain("consensus_dynamic_config changed from")); + assert!(logs_contain(r#""validator_id":"0x1""#)); + assert!(logs_contain(r#""validator_id":"0x2""#)); } diff --git a/crates/apollo_config_manager/src/config_manager_tests.rs b/crates/apollo_config_manager/src/config_manager_tests.rs index e3d7ba29fb6..1be2fbf52a2 100644 --- a/crates/apollo_config_manager/src/config_manager_tests.rs +++ b/crates/apollo_config_manager/src/config_manager_tests.rs @@ -31,7 +31,7 @@ async fn test_config_manager_update_config() { // Set a new dynamic config by creating a new consensus dynamic config. For simplicity, we // create an arbitrary one and assert it's not the default one. let new_consensus_dynamic_config = - ConsensusDynamicConfig { validator_id: ValidatorId::from(1_u8) }; + ConsensusDynamicConfig { validator_id: ValidatorId::from(1_u8), ..Default::default() }; assert_ne!( consensus_dynamic_config, new_consensus_dynamic_config, "Consensus dynamic config should be different: {consensus_dynamic_config:#?} != {:#?}", diff --git a/crates/apollo_consensus/src/manager.rs b/crates/apollo_consensus/src/manager.rs index 73a46272199..47498b26bcc 100644 --- a/crates/apollo_consensus/src/manager.rs +++ b/crates/apollo_consensus/src/manager.rs @@ -284,7 +284,7 @@ impl MultiHeightManager { self.consensus_config.dynamic_config.validator_id, validators, self.quorum_type, - self.consensus_config.static_config.timeouts.clone(), + self.consensus_config.dynamic_config.timeouts.clone(), ); let mut shc_events = FuturesUnordered::new(); @@ -301,7 +301,7 @@ impl MultiHeightManager { // Loop over incoming proposals, messages, and self generated events. let clock = DefaultClock; - let sync_retry_interval = self.consensus_config.static_config.sync_retry_interval; + let sync_retry_interval = self.consensus_config.dynamic_config.sync_retry_interval; let mut sync_poll_deadline = clock.now() + sync_retry_interval; loop { self.report_max_cached_block_number_metric(height); diff --git a/crates/apollo_consensus/src/manager_test.rs b/crates/apollo_consensus/src/manager_test.rs index d23c9acc375..27ea2f22943 100644 --- a/crates/apollo_consensus/src/manager_test.rs +++ b/crates/apollo_consensus/src/manager_test.rs @@ -117,13 +117,12 @@ async fn manager_multiple_heights_unordered() { // TODO(Asmaa): Extract to a #[fixture] let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, - ConsensusStaticConfig { - startup_delay: Duration::ZERO, + ConsensusDynamicConfig { + validator_id: *VALIDATOR_ID, timeouts: TIMEOUTS.clone(), sync_retry_interval: SYNC_RETRY_INTERVAL, - ..Default::default() }, + ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, ); let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let mut subscriber_channels = subscriber_channels.into(); @@ -193,13 +192,12 @@ async fn run_consensus_sync() { send(&mut network_sender, prevote(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; send(&mut network_sender, precommit(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, - ConsensusStaticConfig { - startup_delay: Duration::ZERO, + ConsensusDynamicConfig { + validator_id: *VALIDATOR_ID, timeouts: TIMEOUTS.clone(), sync_retry_interval: SYNC_RETRY_INTERVAL, - ..Default::default() }, + ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, ); let run_consensus_args = RunConsensusArguments { consensus_config, @@ -264,13 +262,12 @@ async fn test_timeouts() { context.expect_broadcast().returning(move |_| Ok(())); let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, - ConsensusStaticConfig { - startup_delay: Duration::ZERO, + ConsensusDynamicConfig { + validator_id: *VALIDATOR_ID, timeouts: TIMEOUTS.clone(), sync_retry_interval: SYNC_RETRY_INTERVAL, - ..Default::default() }, + ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, ); let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let manager_handle = tokio::spawn(async move { @@ -329,13 +326,12 @@ async fn timely_message_handling() { while vote_sender.send((vote.clone(), metadata.clone())).now_or_never().is_some() {} let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, - ConsensusStaticConfig { - startup_delay: Duration::ZERO, + ConsensusDynamicConfig { + validator_id: *VALIDATOR_ID, timeouts: TIMEOUTS.clone(), sync_retry_interval: SYNC_RETRY_INTERVAL, - ..Default::default() }, + ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, ); let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let res = manager @@ -408,22 +404,25 @@ async fn run_consensus_dynamic_client_updates_validator_between_heights() { if n == 0 { Ok(apollo_consensus_config::config::ConsensusDynamicConfig { validator_id: *VALIDATOR_ID, + timeouts: TIMEOUTS.clone(), + sync_retry_interval: SYNC_RETRY_INTERVAL, }) } else { Ok(apollo_consensus_config::config::ConsensusDynamicConfig { validator_id: *PROPOSER_ID, + timeouts: TIMEOUTS.clone(), + sync_retry_interval: SYNC_RETRY_INTERVAL, }) } }); let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { validator_id: *VALIDATOR_ID }, - ConsensusStaticConfig { - startup_delay: Duration::ZERO, + ConsensusDynamicConfig { + validator_id: *VALIDATOR_ID, timeouts: TIMEOUTS.clone(), sync_retry_interval: SYNC_RETRY_INTERVAL, - ..Default::default() }, + ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, ); let run_consensus_args = RunConsensusArguments { start_active_height: BlockNumber(1), diff --git a/crates/apollo_consensus_config/src/config.rs b/crates/apollo_consensus_config/src/config.rs index 6f31cf000c3..64bef0999ac 100644 --- a/crates/apollo_consensus_config/src/config.rs +++ b/crates/apollo_consensus_config/src/config.rs @@ -22,6 +22,11 @@ use crate::ValidatorId; pub struct ConsensusDynamicConfig { /// The validator ID of the node. pub validator_id: ValidatorId, + /// Timeouts configuration for consensus. + pub timeouts: TimeoutsConfig, + /// The duration (seconds) between sync attempts. + #[serde(deserialize_with = "deserialize_float_seconds_to_duration")] + pub sync_retry_interval: Duration, } /// Static configuration for consensus that doesn't change during runtime. @@ -30,11 +35,6 @@ pub struct ConsensusStaticConfig { /// The delay (seconds) before starting consensus to give time for network peering. #[serde(deserialize_with = "deserialize_seconds_to_duration")] pub startup_delay: Duration, - /// Timeouts configuration for consensus. - pub timeouts: TimeoutsConfig, - /// The duration (seconds) between sync attempts. - #[serde(deserialize_with = "deserialize_float_seconds_to_duration")] - pub sync_retry_interval: Duration, /// How many heights in the future should we cache. pub future_height_limit: u32, /// How many rounds in the future (for current height) should we cache. @@ -54,30 +54,34 @@ pub struct ConsensusConfig { impl SerializeConfig for ConsensusDynamicConfig { fn dump(&self) -> BTreeMap { - BTreeMap::from_iter([ser_param( - "validator_id", - &self.validator_id, - "The validator id of the node.", - ParamPrivacyInput::Public, - )]) + let mut config = BTreeMap::from_iter([ + ser_param( + "validator_id", + &self.validator_id, + "The validator id of the node.", + ParamPrivacyInput::Public, + ), + ser_param( + "sync_retry_interval", + &self.sync_retry_interval.as_secs_f64(), + "The duration (seconds) between sync attempts.", + ParamPrivacyInput::Public, + ), + ]); + config.extend(prepend_sub_config_name(self.timeouts.dump(), "timeouts")); + config } } impl SerializeConfig for ConsensusStaticConfig { fn dump(&self) -> BTreeMap { - let mut config = BTreeMap::from_iter([ + BTreeMap::from_iter([ ser_param( "startup_delay", &self.startup_delay.as_secs(), "Delay (seconds) before starting consensus to give time for network peering.", ParamPrivacyInput::Public, ), - ser_param( - "sync_retry_interval", - &self.sync_retry_interval.as_secs_f64(), - "The duration (seconds) between sync attempts.", - ParamPrivacyInput::Public, - ), ser_param( "future_height_limit", &self.future_height_limit, @@ -96,9 +100,7 @@ impl SerializeConfig for ConsensusStaticConfig { "How many rounds should we cache for future heights.", ParamPrivacyInput::Public, ), - ]); - config.extend(prepend_sub_config_name(self.timeouts.dump(), "timeouts")); - config + ]) } } @@ -113,7 +115,11 @@ impl SerializeConfig for ConsensusConfig { impl Default for ConsensusDynamicConfig { fn default() -> Self { - Self { validator_id: ValidatorId::from(DEFAULT_VALIDATOR_ID) } + Self { + validator_id: ValidatorId::from(DEFAULT_VALIDATOR_ID), + timeouts: TimeoutsConfig::default(), + sync_retry_interval: Duration::from_secs_f64(1.0), + } } } @@ -121,8 +127,6 @@ impl Default for ConsensusStaticConfig { fn default() -> Self { Self { startup_delay: Duration::from_secs(5), - timeouts: TimeoutsConfig::default(), - sync_retry_interval: Duration::from_secs_f64(1.0), future_height_limit: 10, future_round_limit: 10, future_height_round_limit: 1, diff --git a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json index 2efa4e2fda6..88461e479b7 100644 --- a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json +++ b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json @@ -9,10 +9,10 @@ "consensus_manager_config.consensus_manager_config.static_config.future_height_round_limit": 5, "consensus_manager_config.consensus_manager_config.static_config.future_round_limit": 20, "consensus_manager_config.consensus_manager_config.static_config.startup_delay": 15, - "consensus_manager_config.consensus_manager_config.static_config.sync_retry_interval": 1.0, - "consensus_manager_config.consensus_manager_config.static_config.timeouts.precommit_timeout": 1.0, - "consensus_manager_config.consensus_manager_config.static_config.timeouts.prevote_timeout": 0.3, - "consensus_manager_config.consensus_manager_config.static_config.timeouts.proposal_timeout": 9.1, + "consensus_manager_config.consensus_manager_config.dynamic_config.sync_retry_interval": 1.0, + "consensus_manager_config.consensus_manager_config.dynamic_config.timeouts.precommit_timeout": 1.0, + "consensus_manager_config.consensus_manager_config.dynamic_config.timeouts.prevote_timeout": 0.3, + "consensus_manager_config.consensus_manager_config.dynamic_config.timeouts.proposal_timeout": 9.1, "consensus_manager_config.context_config.block_timestamp_window_seconds": 1, "consensus_manager_config.context_config.build_proposal_margin_millis": 1000, "consensus_manager_config.context_config.builder_address": "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", @@ -51,4 +51,4 @@ "consensus_manager_config.stream_handler_config.channel_buffer_capacity": 1000, "consensus_manager_config.stream_handler_config.max_streams": 100, "consensus_manager_config.votes_topic": "consensus_votes" -} +} \ No newline at end of file diff --git a/crates/apollo_integration_tests/src/utils.rs b/crates/apollo_integration_tests/src/utils.rs index 9992f9f820f..98f673f2714 100644 --- a/crates/apollo_integration_tests/src/utils.rs +++ b/crates/apollo_integration_tests/src/utils.rs @@ -12,7 +12,12 @@ use apollo_class_manager_config::config::{ }; use apollo_config::converters::UrlAndHeaders; use apollo_config_manager_config::config::ConfigManagerConfig; -use apollo_consensus_config::config::{ConsensusConfig, ConsensusStaticConfig, TimeoutsConfig}; +use apollo_consensus_config::config::{ + ConsensusConfig, + ConsensusDynamicConfig, + ConsensusStaticConfig, + TimeoutsConfig, +}; use apollo_consensus_config::ValidatorId; use apollo_consensus_manager_config::config::ConsensusManagerConfig; use apollo_consensus_orchestrator::cende::RECORDER_WRITE_BLOB_PATH; @@ -349,13 +354,15 @@ pub(crate) fn create_consensus_manager_configs_from_network_configs( network_config, immediate_active_height: BlockNumber(1), consensus_manager_config: ConsensusConfig { + dynamic_config: ConsensusDynamicConfig { + timeouts: timeouts.clone(), + ..Default::default() + }, static_config: ConsensusStaticConfig { // TODO(Matan, Dan): Set the right amount startup_delay: Duration::from_secs(15), - timeouts: timeouts.clone(), ..Default::default() }, - ..Default::default() }, context_config: ContextConfig { num_validators, diff --git a/crates/apollo_node/resources/config_schema.json b/crates/apollo_node/resources/config_schema.json index 1a80dd25646..b3aa2bae87f 100644 --- a/crates/apollo_node/resources/config_schema.json +++ b/crates/apollo_node/resources/config_schema.json @@ -1549,22 +1549,22 @@ "privacy": "Public", "value": 5 }, - "consensus_manager_config.consensus_manager_config.static_config.sync_retry_interval": { + "consensus_manager_config.consensus_manager_config.dynamic_config.sync_retry_interval": { "description": "The duration (seconds) between sync attempts.", "privacy": "Public", "value": 1.0 }, - "consensus_manager_config.consensus_manager_config.static_config.timeouts.precommit_timeout": { + "consensus_manager_config.consensus_manager_config.dynamic_config.timeouts.precommit_timeout": { "description": "The timeout (seconds) for a precommit.", "privacy": "Public", "value": 1.0 }, - "consensus_manager_config.consensus_manager_config.static_config.timeouts.prevote_timeout": { + "consensus_manager_config.consensus_manager_config.dynamic_config.timeouts.prevote_timeout": { "description": "The timeout (seconds) for a prevote.", "privacy": "Public", "value": 1.0 }, - "consensus_manager_config.consensus_manager_config.static_config.timeouts.proposal_timeout": { + "consensus_manager_config.consensus_manager_config.dynamic_config.timeouts.proposal_timeout": { "description": "The timeout (seconds) for a proposal.", "privacy": "Public", "value": 3.0 @@ -2774,4 +2774,4 @@ "privacy": "TemporaryValue", "value": 1000000 } -} +} \ No newline at end of file diff --git a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap index 2ee0538c9e9..82184c69be9 100644 --- a/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap +++ b/crates/papyrus_node/src/config/snapshots/papyrus_node__config__config_test__dump_default_config.snap @@ -101,6 +101,34 @@ expression: dumped_default_config "value": true, "privacy": "TemporaryValue" }, + "consensus.dynamic_config.sync_retry_interval": { + "description": "The duration (seconds) between sync attempts.", + "value": { + "$serde_json::private::Number": "1.0" + }, + "privacy": "Public" + }, + "consensus.dynamic_config.timeouts.precommit_timeout": { + "description": "The timeout (seconds) for a precommit.", + "value": { + "$serde_json::private::Number": "1.0" + }, + "privacy": "Public" + }, + "consensus.dynamic_config.timeouts.prevote_timeout": { + "description": "The timeout (seconds) for a prevote.", + "value": { + "$serde_json::private::Number": "1.0" + }, + "privacy": "Public" + }, + "consensus.dynamic_config.timeouts.proposal_timeout": { + "description": "The timeout (seconds) for a proposal.", + "value": { + "$serde_json::private::Number": "3.0" + }, + "privacy": "Public" + }, "consensus.dynamic_config.validator_id": { "description": "The validator id of the node.", "value": "0x64", @@ -134,34 +162,6 @@ expression: dumped_default_config }, "privacy": "Public" }, - "consensus.static_config.sync_retry_interval": { - "description": "The duration (seconds) between sync attempts.", - "value": { - "$serde_json::private::Number": "1.0" - }, - "privacy": "Public" - }, - "consensus.static_config.timeouts.precommit_timeout": { - "description": "The timeout (seconds) for a precommit.", - "value": { - "$serde_json::private::Number": "1.0" - }, - "privacy": "Public" - }, - "consensus.static_config.timeouts.prevote_timeout": { - "description": "The timeout (seconds) for a prevote.", - "value": { - "$serde_json::private::Number": "1.0" - }, - "privacy": "Public" - }, - "consensus.static_config.timeouts.proposal_timeout": { - "description": "The timeout (seconds) for a proposal.", - "value": { - "$serde_json::private::Number": "3.0" - }, - "privacy": "Public" - }, "context.#is_none": { "description": "Flag for an optional field.", "value": true, From 92cc34a67f694a907b3546b4a5aae78eca7b3466 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Sun, 2 Nov 2025 09:36:22 +0200 Subject: [PATCH 221/313] apollo_integration_tests: remove in_ci check from events_from_other_contract (#9841) * apollo_integration_tests: add mocked starknet contract (#8459) * apollo_integration_tests: ban `anvil` in unit tests * l1: add mocked starknet contract Mocked contract has mocked initialize and update state functions, but is otherwise identical, is intended for use in anvil-based integraiton tests. Scraper test needed a fix, it wasn't passing fee, and not that the contract is initialized it checks this. Also the cancellation request wasn't sent from the correct sender, which was also not previously checked. --------- Co-authored-by: Gilad Chase * apollo_integration_tests: remove in_ci check from events_from_other_contract --------- Co-authored-by: giladchase Co-authored-by: Gilad Chase --- .../tests/events_from_other_contracts.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/apollo_integration_tests/tests/events_from_other_contracts.rs b/crates/apollo_integration_tests/tests/events_from_other_contracts.rs index e6651f39227..da17b812b90 100644 --- a/crates/apollo_integration_tests/tests/events_from_other_contracts.rs +++ b/crates/apollo_integration_tests/tests/events_from_other_contracts.rs @@ -8,17 +8,10 @@ use starknet_api::core::EntryPointSelector; use starknet_api::transaction::L1HandlerTransaction; use starknet_api::{calldata, contract_address, felt}; -pub fn in_ci() -> bool { - std::env::var("CI").is_ok() -} - // Ensure that the base layer instance filters out events from other deployments of the core // contract. #[tokio::test] async fn events_from_other_contract() { - if !in_ci() { - return; - } const EVENT_IDENTIFIERS: &[EventIdentifier] = &[LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER]; let anvil_base_layer = AnvilBaseLayer::new().await; From 5e40bd6833da654721b73d758488c7a6e2da2bff Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 2 Nov 2025 11:34:56 +0200 Subject: [PATCH 222/313] scripts: fix a bug where the get pod names did not use the namespace and context from args (#9809) --- scripts/prod/update_config_and_restart_nodes_lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 43d563da4c7..a3f32655373 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -484,6 +484,7 @@ def restart_pod( "-o", "name", ] + kubectl_args.extend(get_namespace_args(namespace, cluster)) pods = run_kubectl_command(kubectl_args, capture_output=True).stdout.splitlines() # Filter the list of pods to only include the ones that match the service and extract the pod name. From 039f4ff67146d953ecc8fd378cb233bb4e339c49 Mon Sep 17 00:00:00 2001 From: Tzahi Date: Sun, 2 Nov 2025 11:58:35 +0200 Subject: [PATCH 223/313] apollo_mempool: fix accidentle line breakes in logs (#9858) --- crates/apollo_mempool/src/mempool.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/apollo_mempool/src/mempool.rs b/crates/apollo_mempool/src/mempool.rs index 514f1c1f787..c297edcefe5 100644 --- a/crates/apollo_mempool/src/mempool.rs +++ b/crates/apollo_mempool/src/mempool.rs @@ -563,7 +563,7 @@ impl Mempool { Ok(()) } - /// If this transaction is already in the pool but the fees have increased beyond the thereshold + /// If this transaction is already in the pool but the fees have increased beyond the threshold /// in the config, remove the existing transaction from the queue and the pool. /// Note: This method will **not** add the new incoming transaction. #[instrument(level = "debug", skip(self, incoming_tx), err)] @@ -588,9 +588,9 @@ impl Mempool { }; if !self.should_replace_tx(&existing_tx_reference, &incoming_tx_reference) { - debug!( - "{existing_tx_reference} was not replaced by {incoming_tx_reference} due to - insufficient fee escalation." + info!( + "{existing_tx_reference} was not replaced by {incoming_tx_reference} due to \ + insufficient fee escalation." ); // TODO(Elin): consider adding a more specific error type / message. return Err(MempoolError::DuplicateNonce { address, nonce }); @@ -864,8 +864,8 @@ impl std::fmt::Display for TransactionReference { let TransactionReference { address, nonce, tx_hash, tip, max_l2_gas_price } = self; write!( f, - "TransactionReference {{ address: {address}, nonce: {nonce}, tx_hash: {tx_hash}, - tip: {tip}, max_l2_gas_price: {max_l2_gas_price} }}" + "TransactionReference {{ address: {address}, nonce: {nonce}, tx_hash: {tx_hash}, tip: \ + {tip}, max_l2_gas_price: {max_l2_gas_price} }}" ) } } From 48a2feb78b1311cc73ac2821f3a9a2c425ace569 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 2 Nov 2025 12:54:22 +0200 Subject: [PATCH 224/313] apollo_dashboard: simpler new fn for Panel (#9856) --- crates/apollo_dashboard/src/dashboard.rs | 45 +++++++-- crates/apollo_dashboard/src/dashboard_test.rs | 10 +- crates/apollo_dashboard/src/panels/batcher.rs | 16 ++-- .../apollo_dashboard/src/panels/blockifier.rs | 8 +- .../apollo_dashboard/src/panels/consensus.rs | 96 +++++++++---------- crates/apollo_dashboard/src/panels/gateway.rs | 24 ++--- .../src/panels/http_server.rs | 8 +- .../src/panels/l1_gas_price.rs | 36 +++---- .../src/panels/l1_provider.rs | 15 +-- crates/apollo_dashboard/src/panels/mempool.rs | 20 ++-- .../src/panels/mempool_p2p.rs | 8 +- .../src/panels/pod_metrics.rs | 6 +- .../src/panels/sierra_compiler.rs | 6 +- .../apollo_dashboard/src/panels/state_sync.rs | 10 +- 14 files changed, 160 insertions(+), 148 deletions(-) diff --git a/crates/apollo_dashboard/src/dashboard.rs b/crates/apollo_dashboard/src/dashboard.rs index 8e841c1dce7..312d8579428 100644 --- a/crates/apollo_dashboard/src/dashboard.rs +++ b/crates/apollo_dashboard/src/dashboard.rs @@ -137,11 +137,40 @@ pub(crate) struct Panel { extra: ExtraParams, } +// helper: unify "String" and "Vec" +pub(crate) trait IntoExprs { + fn into_exprs(self) -> Vec; +} + +impl IntoExprs for String { + fn into_exprs(self) -> Vec { + vec![self] + } +} + +impl IntoExprs for &str { + fn into_exprs(self) -> Vec { + vec![self.to_string()] + } +} + +impl IntoExprs for Vec { + fn into_exprs(self) -> Vec { + self + } +} + +impl IntoExprs for Vec<&str> { + fn into_exprs(self) -> Vec { + self.into_iter().map(|s| s.to_string()).collect::>() + } +} + impl Panel { pub(crate) fn new( name: impl ToString, description: impl ToString, - exprs: Vec, + exprs: impl IntoExprs, panel_type: PanelType, ) -> Self { // A panel assigns a unique id to each of its expressions. Conventionally, we use letters @@ -149,6 +178,9 @@ impl Panel { const NUM_LETTERS: u8 = b'Z' - b'A' + 1; let name = name.to_string(); let description = description.to_string(); + + let exprs = exprs.into_exprs(); + assert!( exprs.len() <= NUM_LETTERS.into(), "Too many expressions ({} > {NUM_LETTERS}) in panel '{name}'.", @@ -156,6 +188,7 @@ impl Panel { ); Self { name, description, exprs, panel_type, extra: ExtraParams::default() } } + pub fn with_unit(mut self, unit: Unit) -> Self { self.extra.unit = Some(unit); self @@ -265,7 +298,7 @@ impl Panel { (rate({metric_name_with_filter_and_reason}[{HISTOGRAM_TIME_RANGE}])))", ) }) - .collect(), + .collect::>(), panel_type, ) } @@ -288,14 +321,14 @@ impl Panel { let expr = format!("({numerator_expr} / ({denominator_expr}))"); - Self::new(name, description, vec![expr], PanelType::TimeSeries).with_unit(Unit::PercentUnit) + Self::new(name, description, expr, PanelType::TimeSeries).with_unit(Unit::PercentUnit) } pub(crate) fn from_counter(metric: &MetricCounter, panel_type: PanelType) -> Self { Self::new( metric.get_name(), metric.get_description(), - vec![metric.get_name_with_filter().to_string()], + metric.get_name_with_filter().to_string(), panel_type, ) } @@ -304,7 +337,7 @@ impl Panel { Self::new( metric.get_name(), metric.get_description(), - vec![metric.get_name_with_filter().to_string()], + metric.get_name_with_filter().to_string(), panel_type, ) } @@ -328,7 +361,7 @@ impl Panel { metric_name_with_filter.as_ref(), ) }) - .collect(), + .collect::>(), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/dashboard_test.rs b/crates/apollo_dashboard/src/dashboard_test.rs index e2b3ddbc4ba..fcf49d8b2ad 100644 --- a/crates/apollo_dashboard/src/dashboard_test.rs +++ b/crates/apollo_dashboard/src/dashboard_test.rs @@ -91,7 +91,7 @@ fn test_ratio_time_series() { #[test] fn test_extra_params() { - let panel_with_extra_params = Panel::new("x", "x", vec!["y".to_string()], PanelType::Stat) + let panel_with_extra_params = Panel::new("x", "x", "y".to_string(), PanelType::Stat) .with_unit(Unit::Bytes) .show_percent_change() .with_log_query("Query") @@ -118,7 +118,7 @@ fn test_extra_params() { ); assert_eq!(panel_with_extra_params.extra.legends, Some(vec!["a".to_string()])); - let panel_without_extra_params = Panel::new("x", "x", vec!["y".to_string()], PanelType::Stat); + let panel_without_extra_params = Panel::new("x", "x", "y".to_string(), PanelType::Stat); assert!(panel_without_extra_params.extra.unit.is_none()); assert!(panel_without_extra_params.extra.show_percent_change.is_none()); assert!(panel_without_extra_params.extra.log_query.is_none()); @@ -129,7 +129,7 @@ fn test_extra_params() { #[test] #[should_panic] fn thresholds_first_step_must_be_none() { - let _ = Panel::new("x", "x", vec!["y".into()], PanelType::Stat).with_absolute_thresholds(vec![ + let _ = Panel::new("x", "x", "y", PanelType::Stat).with_absolute_thresholds(vec![ ("green", Some(0.0)), // illegal: first step must be None ("red", Some(80.0)), ]); @@ -138,7 +138,7 @@ fn thresholds_first_step_must_be_none() { #[test] #[should_panic] fn thresholds_must_be_strictly_increasing() { - let _ = Panel::new("x", "x", vec!["y".into()], PanelType::Stat).with_absolute_thresholds(vec![ + let _ = Panel::new("x", "x", "y", PanelType::Stat).with_absolute_thresholds(vec![ ("green", None), ("red", Some(90.0)), ("yellow", Some(80.0)), // illegal: not increasing @@ -148,5 +148,5 @@ fn thresholds_must_be_strictly_increasing() { #[test] #[should_panic] fn amount_of_legends_must_match_amount_of_exprs() { - let _ = Panel::new("x", "x", vec!["y".into()], PanelType::Stat).with_legends(vec!["a", "b"]); + let _ = Panel::new("x", "x", "y", PanelType::Stat).with_legends(vec!["a", "b"]); } diff --git a/crates/apollo_dashboard/src/panels/batcher.rs b/crates/apollo_dashboard/src/panels/batcher.rs index ba15bff3427..12ad6cc9d93 100644 --- a/crates/apollo_dashboard/src/panels/batcher.rs +++ b/crates/apollo_dashboard/src/panels/batcher.rs @@ -19,7 +19,7 @@ fn get_panel_validator_wasted_txs() -> Panel { Panel::new( "Proposal Validation: Wasted TXs", "Number of txs executed by the validator but excluded from the block (10m window)", - vec![format!("increase({}[10m])", VALIDATOR_WASTED_TXS.get_name_with_filter())], + format!("increase({}[10m])", VALIDATOR_WASTED_TXS.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("Finished building block as validator. Started executing") @@ -29,7 +29,7 @@ fn get_panel_proposer_deferred_txs() -> Panel { Panel::new( "Proposal Build: Deferred TXs", "Number of txs started execution by the proposer but excluded from the block (10m window)", - vec![format!("increase({}[10m])", PROPOSER_DEFERRED_TXS.get_name_with_filter())], + format!("increase({}[10m])", PROPOSER_DEFERRED_TXS.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("Finished building block as proposer. Started executing") @@ -39,7 +39,7 @@ fn get_panel_storage_height() -> Panel { Panel::new( "Storage Height", "The height of the batcher's storage", - vec![STORAGE_HEIGHT.get_name_with_filter().to_string()], + STORAGE_HEIGHT.get_name_with_filter().to_string(), PanelType::Stat, ) .with_log_query("Committing block at height") @@ -75,7 +75,7 @@ pub(crate) fn get_panel_batched_transactions_rate() -> Panel { Panel::new( "Batched Transactions Rate (TPS)", "The rate of transactions batched by the Batcher (1m window)", - vec![format!("rate({}[1m])", BATCHED_TRANSACTIONS.get_name_with_filter())], + format!("rate({}[1m])", BATCHED_TRANSACTIONS.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("BATCHER_FIN_VALIDATOR") @@ -85,11 +85,11 @@ fn get_panel_block_close_reasons() -> Panel { Panel::new( "Block Close Reasons", "Number of blocks closed by reason (10m window)", - vec![format!( + format!( "sum by ({}) (increase({}[10m]))", LABEL_NAME_BLOCK_CLOSE_REASON, BLOCK_CLOSE_REASON.get_name_with_filter() - )], + ), PanelType::Stat, ) .with_log_query("\"Block builder deadline reached.\" OR \"Block is full.\"") @@ -99,7 +99,7 @@ fn get_panel_num_batches_in_proposal() -> Panel { Panel::new( "Number of Chunks in Proposal", "The number of transaction batches received in a valid proposal", - vec![CONSENSUS_NUM_BATCHES_IN_PROPOSAL.get_name_with_filter().to_string()], + CONSENSUS_NUM_BATCHES_IN_PROPOSAL.get_name_with_filter().to_string(), PanelType::TimeSeries, ) } @@ -108,7 +108,7 @@ fn get_panel_num_txs_in_proposal() -> Panel { Panel::new( "Number of Transactions in Proposal", "The total number of individual transactions in a valid proposal received", - vec![CONSENSUS_NUM_TXS_IN_PROPOSAL.get_name_with_filter().to_string()], + CONSENSUS_NUM_TXS_IN_PROPOSAL.get_name_with_filter().to_string(), PanelType::TimeSeries, ) .with_log_query("BATCHER_FIN_PROPOSER") diff --git a/crates/apollo_dashboard/src/panels/blockifier.rs b/crates/apollo_dashboard/src/panels/blockifier.rs index d7ffb4241d8..54b3ca6657c 100644 --- a/crates/apollo_dashboard/src/panels/blockifier.rs +++ b/crates/apollo_dashboard/src/panels/blockifier.rs @@ -66,11 +66,11 @@ fn get_panel_sierra_gas_in_last_block() -> Panel { Panel::new( "Average Sierra Gas Usage in Block", "The average sierra gas usage in block (10m window)", - vec![format!( + format!( "avg_over_time({}[10m])/{}", SIERRA_GAS_IN_LAST_BLOCK.get_name_with_filter(), DENOMINATOR_DIVISOR_FOR_READABILITY - )], + ), PanelType::TimeSeries, ) } @@ -79,11 +79,11 @@ fn get_panel_proving_gas_in_last_block() -> Panel { Panel::new( "Average Proving Gas Usage in Block", "The average proving gas usage in block (10m window)", - vec![format!( + format!( "avg_over_time({}[10m])/{}", PROVING_GAS_IN_LAST_BLOCK.get_name_with_filter(), DENOMINATOR_DIVISOR_FOR_READABILITY - )], + ), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 283670c0955..233c80ac6bd 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -56,7 +56,7 @@ fn get_panel_consensus_block_number() -> Panel { Panel::new( "Consensus Height", "The block height the node is currently working on", - vec![CONSENSUS_BLOCK_NUMBER.get_name_with_filter().to_string()], + CONSENSUS_BLOCK_NUMBER.get_name_with_filter().to_string(), PanelType::Stat, ) .with_log_query( @@ -70,11 +70,11 @@ pub(crate) fn get_panel_consensus_block_number_diff_from_sync() -> Panel { Panel::new( "Consensus Height Diff From Sync", "The difference between the consensus height and the sync height", - vec![format!( + format!( "({} - {})", CONSENSUS_BLOCK_NUMBER.get_name_with_filter(), STATE_SYNC_CLASS_MANAGER_MARKER.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) } @@ -83,7 +83,7 @@ pub(crate) fn get_panel_consensus_round() -> Panel { Panel::new( "Consensus Round", "The round the node is currently working on", - vec![CONSENSUS_ROUND.get_name_with_filter().to_string()], + CONSENSUS_ROUND.get_name_with_filter().to_string(), PanelType::TimeSeries, ) .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") @@ -95,7 +95,7 @@ pub(crate) fn get_panel_consensus_round_advanced() -> Panel { "Consensus Round Advanced", "The number of times the consensus round advanced (counter is increased whenever round > \ 0) (10m window)", - vec![format!("increase({}[10m])", CONSENSUS_ROUND_ADVANCES.get_name_with_filter())], + format!("increase({}[10m])", CONSENSUS_ROUND_ADVANCES.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") @@ -106,10 +106,10 @@ fn get_panel_consensus_round_above_zero() -> Panel { Panel::new( "Consensus Round Above Zero", "Occurances where the consensus round was 1, relative to displayed range", - vec![format!( + format!( "{m} - ({m} @ start())", m = CONSENSUS_ROUND_ABOVE_ZERO.get_name_with_filter().to_string() - )], + ), PanelType::TimeSeries, ) .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") @@ -120,7 +120,7 @@ pub(crate) fn get_panel_consensus_block_time_avg() -> Panel { Panel::new( "Average Block Time", "Average block time (1m window)", - vec![format!("1 / rate({}[1m])", CONSENSUS_BLOCK_NUMBER.get_name_with_filter())], + format!("1 / rate({}[1m])", CONSENSUS_BLOCK_NUMBER.get_name_with_filter()), PanelType::TimeSeries, ) .with_unit(Unit::Seconds) @@ -130,10 +130,10 @@ fn get_panel_consensus_decisions_reached_by_consensus() -> Panel { Panel::new( "Decisions Reached By Consensus", "The number of decisions reached by way of consensus (10m window)", - vec![format!( + format!( "increase({}[10m])", CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) .with_log_query("DECISION_REACHED: Decision reached for round") @@ -144,10 +144,7 @@ fn get_panel_consensus_decisions_reached_by_sync() -> Panel { Panel::new( "Decisions Reached By Sync", "The number of decisions reached by way of sync (10m window)", - vec![format!( - "increase({}[10m])", - CONSENSUS_DECISIONS_REACHED_BY_SYNC.get_name_with_filter() - )], + format!("increase({}[10m])", CONSENSUS_DECISIONS_REACHED_BY_SYNC.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("Decision learned via sync protocol.") @@ -158,7 +155,7 @@ fn get_panel_consensus_proposals_received() -> Panel { Panel::new( "Proposal Validation: Number of Received Proposals", "The number of proposals received from the network (10m window)", - vec![format!("increase({}[10m])", CONSENSUS_PROPOSALS_RECEIVED.get_name_with_filter())], + format!("increase({}[10m])", CONSENSUS_PROPOSALS_RECEIVED.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -167,7 +164,7 @@ fn get_panel_consensus_proposals_validated() -> Panel { Panel::new( "Proposal Validation: Number of Validated Proposals", "The number of proposals received and validated successfully (10m window)", - vec![format!("increase({}[10m])", CONSENSUS_PROPOSALS_VALIDATED.get_name_with_filter())], + format!("increase({}[10m])", CONSENSUS_PROPOSALS_VALIDATED.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") @@ -178,7 +175,7 @@ fn get_panel_consensus_proposals_invalid() -> Panel { Panel::new( "Proposal Validation: Number of Invalid Proposals", "The number of proposals received and failed validation (10m window)", - vec![format!("increase({}[10m])", CONSENSUS_PROPOSALS_INVALID.get_name_with_filter())], + format!("increase({}[10m])", CONSENSUS_PROPOSALS_INVALID.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") @@ -189,11 +186,11 @@ fn get_panel_validate_proposal_failure() -> Panel { Panel::new( "Proposal Validation: Proposal Failure by Reason", "The number of validate proposal failures (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range])) > 0", LABEL_VALIDATE_PROPOSAL_FAILURE_REASON, CONSENSUS_VALIDATE_PROPOSAL_FAILURE.get_name_with_filter() - )], + ), PanelType::Stat, ) .with_log_query("PROPOSAL_FAILED: Proposal failed as validator") @@ -204,7 +201,7 @@ fn get_panel_consensus_build_proposal_total() -> Panel { Panel::new( "Proposal Build: Number of Proposals Started", "The number of proposals that started building (10m window)", - vec![format!("increase({}[10m])", CONSENSUS_BUILD_PROPOSAL_TOTAL.get_name_with_filter())], + format!("increase({}[10m])", CONSENSUS_BUILD_PROPOSAL_TOTAL.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -213,7 +210,7 @@ fn get_panel_consensus_build_proposal_failed() -> Panel { Panel::new( "Proposal Build: Number of Proposals Failed", "The number of proposals that failed to be built (10m window)", - vec![format!("increase({}[10m])", CONSENSUS_BUILD_PROPOSAL_FAILED.get_name_with_filter())], + format!("increase({}[10m])", CONSENSUS_BUILD_PROPOSAL_FAILED.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -222,11 +219,11 @@ fn get_panel_build_proposal_failure() -> Panel { Panel::new( "Proposal Build: Proposal Failure by Reason", "The number of build proposal failures (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range])) > 0", LABEL_BUILD_PROPOSAL_FAILURE_REASON, CONSENSUS_BUILD_PROPOSAL_FAILURE.get_name_with_filter() - )], + ), PanelType::Stat, ) .with_log_query("PROPOSAL_FAILED: Proposal failed as proposer") @@ -242,11 +239,11 @@ fn get_panel_consensus_timeouts_by_type() -> Panel { received a quorum of prevotes, but not on the same value.\n- TimeoutPrecommit: didn’t \ finish validation but quorum of precommits received, or it finished but no decision \ reached.", - vec![format!( + format!( "sum by ({}) (increase({}[10m]))", LABEL_NAME_TIMEOUT_TYPE, CONSENSUS_TIMEOUTS.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) .with_log_query("Applying Timeout") @@ -257,7 +254,7 @@ fn get_panel_consensus_l2_gas_price() -> Panel { Panel::new( "L2 Gas Price (GFri)", "L2 gas price in GFri calculated in an accepted proposal", - vec![format!("{} / 1e9", CONSENSUS_L2_GAS_PRICE.get_name_with_filter())], + format!("{} / 1e9", CONSENSUS_L2_GAS_PRICE.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -266,7 +263,7 @@ fn get_panel_cende_last_prepared_blob_block_number() -> Panel { Panel::new( "Last Prepared Blob Block Number", "The block number that is ready to be sent to Cende in the next height", - vec![CENDE_LAST_PREPARED_BLOB_BLOCK_NUMBER.get_name_with_filter().to_string()], + CENDE_LAST_PREPARED_BLOB_BLOCK_NUMBER.get_name_with_filter().to_string(), PanelType::Stat, ) .with_log_query("Blob for block number") @@ -292,7 +289,7 @@ fn get_panel_cende_write_blob_success() -> Panel { Panel::new( "Write Blob Success", "The number of successful blob writes to Cende (10m window)", - vec![format!("increase({}[10m])", CENDE_WRITE_BLOB_SUCCESS.get_name_with_filter())], + format!("increase({}[10m])", CENDE_WRITE_BLOB_SUCCESS.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query(query_expression) @@ -302,11 +299,11 @@ fn get_panel_cende_write_blob_failure() -> Panel { Panel::new( "Write Blob Failure by Reason", "The number of failed blob writes to Cende (10m window)", - vec![format!( + format!( "sum by ({}) (increase({}[10m]))", LABEL_CENDE_FAILURE_REASON, CENDE_WRITE_BLOB_FAILURE.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) .with_log_query("CENDE_FAILURE") @@ -317,7 +314,7 @@ fn get_panel_cende_write_preconfirmed_block() -> Panel { "Write Preconfirmed Block Success", "The number of successful writes to Cende for preconfirmed blocks (10m window). Each \ preconfirmed block may involve multiple writes.", - vec![format!("increase({}[10m])", PRECONFIRMED_BLOCK_WRITTEN.get_name_with_filter())], + format!("increase({}[10m])", PRECONFIRMED_BLOCK_WRITTEN.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("write_pre_confirmed_block request succeeded.") @@ -327,7 +324,7 @@ fn get_panel_consensus_num_connected_peers() -> Panel { Panel::new( "Number of Connected Peers", "The number of connected peers in Consensus P2P", - vec![CONSENSUS_NUM_CONNECTED_PEERS.get_name_with_filter().to_string()], + CONSENSUS_NUM_CONNECTED_PEERS.get_name_with_filter().to_string(), PanelType::Stat, ) } @@ -337,10 +334,7 @@ fn get_panel_consensus_votes_num_sent_messages() -> Panel { "Consensus Votes Number of Sent Messages", "The increase in the number of vote messages sent by consensus p2p (over the selected \ time range)", - vec![format!( - "increase({}[$__range])", - CONSENSUS_VOTES_NUM_SENT_MESSAGES.get_name_with_filter() - )], + format!("increase({}[$__range])", CONSENSUS_VOTES_NUM_SENT_MESSAGES.get_name_with_filter()), PanelType::Stat, ) } @@ -350,10 +344,10 @@ fn get_panel_consensus_votes_num_received_messages() -> Panel { "Consensus Votes Number of Received Messages", "The increase in the number of vote messages received by consensus p2p (over the selected \ time range)", - vec![format!( + format!( "increase({}[$__range])", CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES.get_name_with_filter() - )], + ), PanelType::Stat, ) } @@ -363,10 +357,10 @@ fn get_panel_consensus_proposals_num_sent_messages() -> Panel { "Consensus Proposals Number of Sent Messages", "The increase in the number of proposal messages sent by consensus p2p (over the selected \ time range)", - vec![format!( + format!( "increase({}[$__range])", CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES.get_name_with_filter() - )], + ), PanelType::Stat, ) } @@ -376,10 +370,10 @@ fn get_panel_consensus_proposals_num_received_messages() -> Panel { "Consensus Proposals Number of Received Messages", "The increase in the number of proposal messages received by consensus p2p (over the \ selected time range)", - vec![format!( + format!( "increase({}[$__range])", CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES.get_name_with_filter() - )], + ), PanelType::Stat, ) } @@ -388,7 +382,7 @@ fn get_panel_consensus_conflicting_votes() -> Panel { Panel::new( "Consensus Conflicting Votes", "The increase in the number of conflicting votes (over the selected time range)", - vec![format!("increase({}[$__range])", CONSENSUS_CONFLICTING_VOTES.get_name_with_filter())], + format!("increase({}[$__range])", CONSENSUS_CONFLICTING_VOTES.get_name_with_filter()), PanelType::Stat, ) } @@ -397,11 +391,11 @@ fn get_panel_consensus_network_events_by_type() -> Panel { Panel::new( "Consensus Network Events By Type", "Network events received by consensus p2p, by event type (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range])) > 0", LABEL_NAME_EVENT_TYPE, CONSENSUS_NETWORK_EVENTS.get_name_with_filter() - )], + ), PanelType::Stat, ) } @@ -410,11 +404,11 @@ fn get_panel_consensus_votes_dropped_messages_by_reason() -> Panel { Panel::new( "Consensus Votes Dropped Messages By Reason", "The number of dropped consensus votes messages, by reason (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range])) > 0", LABEL_NAME_BROADCAST_DROP_REASON, CONSENSUS_VOTES_NUM_DROPPED_MESSAGES.get_name_with_filter() - )], + ), PanelType::Stat, ) } @@ -424,11 +418,11 @@ fn get_panel_consensus_proposals_dropped_messages_by_reason() -> Panel { "Consensus Proposals Dropped Messages By Reason", "The number of dropped consensus proposals messages, by reason (over the selected time \ range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range])) > 0", LABEL_NAME_BROADCAST_DROP_REASON, CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES.get_name_with_filter() - )], + ), PanelType::Stat, ) } @@ -437,10 +431,10 @@ fn get_panel_consensus_decisions_reached_as_proposer() -> Panel { Panel::new( "Consensus Decisions Reached As Proposer", "The number of rounds with decision reached where this node is the proposer (10m window)", - vec![format!( + format!( "increase({}[10m])", CONSENSUS_DECISIONS_REACHED_AS_PROPOSER.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) .with_log_query("\"Building proposal\" OR \"BATCHER_FIN_PROPOSER\"") diff --git a/crates/apollo_dashboard/src/panels/gateway.rs b/crates/apollo_dashboard/src/panels/gateway.rs index d7ccdeb8164..dc1b7d9d4ef 100644 --- a/crates/apollo_dashboard/src/panels/gateway.rs +++ b/crates/apollo_dashboard/src/panels/gateway.rs @@ -18,11 +18,11 @@ fn get_panel_gateway_transactions_received_by_type() -> Panel { Panel::new( "Transactions Received by Type", "The number of transactions received by type (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range])) ", GATEWAY_LABEL_NAME_TX_TYPE, GATEWAY_TRANSACTIONS_RECEIVED.get_name_with_filter() - )], + ), PanelType::Stat, ) .with_log_query("\"Processing tx\"") @@ -32,11 +32,11 @@ fn get_panel_gateway_transactions_received_by_source() -> Panel { Panel::new( "Transactions Received by Source", "The number of transactions received by source (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range])) ", LABEL_NAME_SOURCE, GATEWAY_TRANSACTIONS_RECEIVED.get_name_with_filter() - )], + ), PanelType::Stat, ) .with_log_query("\"Processing tx\" AND \"is_p2p=\"") @@ -46,10 +46,10 @@ fn get_panel_gateway_transactions_received_rate() -> Panel { Panel::new( "Gateway Transactions Received Rate (TPS)", "The rate of transactions received by the gateway (1m window)", - vec![format!( + format!( "sum(rate({}[1m])) or vector(0)", GATEWAY_TRANSACTIONS_RECEIVED.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) } @@ -76,11 +76,11 @@ pub(crate) fn get_panel_gateway_add_tx_failure_by_reason() -> Panel { Panel::new( "Transactions Failed by Reason", "The number of transactions failed by reason (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range])) > 0", LABEL_NAME_ADD_TX_FAILURE_REASON, GATEWAY_ADD_TX_FAILURE.get_name_with_filter() - )], + ), PanelType::Stat, ) } @@ -90,13 +90,13 @@ fn get_panel_gateway_transactions_failure_rate() -> Panel { "Transaction Failure Rate by Type", "The rate of failed transactions vs received transactions by type (over the selected time \ range)", - vec![format!( + format!( "(sum by ({}) (increase({}[$__range])) / sum by ({}) (increase({}[$__range])))", GATEWAY_LABEL_NAME_TX_TYPE, GATEWAY_TRANSACTIONS_FAILED.get_name_with_filter(), GATEWAY_LABEL_NAME_TX_TYPE, GATEWAY_TRANSACTIONS_RECEIVED.get_name_with_filter() - )], + ), PanelType::Stat, ) .with_unit(Unit::PercentUnit) @@ -106,11 +106,11 @@ fn get_panel_gateway_transactions_sent_to_mempool() -> Panel { Panel::new( "Transactions Sent to Mempool by Type", "The number of transactions sent to mempool by type (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range]))", GATEWAY_LABEL_NAME_TX_TYPE, GATEWAY_TRANSACTIONS_SENT_TO_MEMPOOL.get_name_with_filter() - )], + ), PanelType::Stat, ) } diff --git a/crates/apollo_dashboard/src/panels/http_server.rs b/crates/apollo_dashboard/src/panels/http_server.rs index ccb35b1c4a7..73764874a02 100644 --- a/crates/apollo_dashboard/src/panels/http_server.rs +++ b/crates/apollo_dashboard/src/panels/http_server.rs @@ -13,7 +13,7 @@ fn get_panel_total_transactions_received() -> Panel { Panel::new( "Transactions Received", "Number of transactions received (10m window)", - vec![format!("increase({}[10m])", ADDED_TRANSACTIONS_TOTAL.get_name_with_filter())], + format!("increase({}[10m])", ADDED_TRANSACTIONS_TOTAL.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("\"ADD_TX_START\"") @@ -22,12 +22,12 @@ fn get_panel_transaction_success_rate() -> Panel { Panel::new( "Transaction Success Rate", "The ratio of transactions successfully added to the gateway (10m window)", - vec![format!( + format!( "increase({}[10m]) / (increase({}[10m]) + increase({}[10m]))", ADDED_TRANSACTIONS_SUCCESS.get_name_with_filter(), ADDED_TRANSACTIONS_SUCCESS.get_name_with_filter(), ADDED_TRANSACTIONS_FAILURE.get_name_with_filter(), - )], + ), PanelType::TimeSeries, ) .with_unit(Unit::PercentUnit) @@ -37,7 +37,7 @@ pub(crate) fn get_panel_http_server_transactions_received_rate() -> Panel { Panel::new( "HTTP Server Transactions Received Rate (TPS)", "The rate of transactions received by the HTTP Server (1m window)", - vec![format!("rate({}[1m])", ADDED_TRANSACTIONS_TOTAL.get_name_with_filter())], + format!("rate({}[1m])", ADDED_TRANSACTIONS_TOTAL.get_name_with_filter()), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/l1_gas_price.rs b/crates/apollo_dashboard/src/panels/l1_gas_price.rs index 1fc1b87ae03..cc210436d39 100644 --- a/crates/apollo_dashboard/src/panels/l1_gas_price.rs +++ b/crates/apollo_dashboard/src/panels/l1_gas_price.rs @@ -18,7 +18,7 @@ fn get_panel_eth_to_strk_error_count() -> Panel { Panel::new( "ETH→STRK Rate Query Error Count", "The number of times the ETH→STRK rate query failed (10m window)", - vec![format!("increase({}[10m])", ETH_TO_STRK_ERROR_COUNT.get_name_with_filter())], + format!("increase({}[10m])", ETH_TO_STRK_ERROR_COUNT.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -28,7 +28,7 @@ fn get_panel_eth_to_strk_seconds_since_last_successful_update() -> Panel { "Seconds since last successful ETH→STRK rate update", "The number of seconds since the last successful ETH→STRK rate update (assuming there was \ an update in the last 12 hours)", - vec![get_time_since_last_increase_expr(Ð_TO_STRK_SUCCESS_COUNT.get_name_with_filter())], + get_time_since_last_increase_expr(Ð_TO_STRK_SUCCESS_COUNT.get_name_with_filter()), PanelType::TimeSeries, ) .with_unit(Unit::Seconds) @@ -39,7 +39,7 @@ fn get_panel_eth_to_strk_success_count() -> Panel { "ETH→STRK Rate Query Success (binary)", "Indicates whether the ETH→STRK rate query succeeded (1m window) \nExpected to be 1 every \ 15 minutes.", - vec![format!("changes({}[1m])", ETH_TO_STRK_SUCCESS_COUNT.get_name_with_filter())], + format!("changes({}[1m])", ETH_TO_STRK_SUCCESS_COUNT.get_name_with_filter()), PanelType::TimeSeries, ) .with_log_query("Caching conversion rate for timestamp") @@ -49,7 +49,7 @@ fn get_panel_eth_to_strk_rate() -> Panel { Panel::new( "ETH→STRK rate", format!("ETH→STRK rate (divided by DEFAULT_ETH_TO_FRI_RATE={DEFAULT_ETH_TO_FRI_RATE})"), - vec![format!("{} / {}", ETH_TO_STRK_RATE.get_name_with_filter(), DEFAULT_ETH_TO_FRI_RATE)], + format!("{} / {}", ETH_TO_STRK_RATE.get_name_with_filter(), DEFAULT_ETH_TO_FRI_RATE), PanelType::TimeSeries, ) .with_log_query("Caching conversion rate for timestamp") @@ -60,10 +60,10 @@ fn get_panel_l1_gas_price_provider_insufficient_history() -> Panel { "L1 Gas Price Provider Insufficient History", "The number of times the L1 gas price provider calculated an average with too few blocks \ (10m window)", - vec![format!( + format!( "increase({}[10m])", L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) .with_log_query("Not enough history to calculate the mean gas price.") @@ -74,10 +74,7 @@ fn get_panel_l1_gas_price_scraper_success_count() -> Panel { "L1 Gas Price Scraper Success Count", "The number of times the L1 gas price scraper successfully scraped and updated gas prices \ (10m window)", - vec![format!( - "increase({}[10m])", - L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT.get_name_with_filter() - )], + format!("increase({}[10m])", L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -87,10 +84,10 @@ fn get_panel_l1_gas_price_scraper_baselayer_error_count() -> Panel { "L1 Gas Price Scraper Base Layer Error Count", "The number of times the L1 gas price scraper encountered an error while scraping the \ base layer (10m window)", - vec![format!( + format!( "increase({}[10m])", L1_GAS_PRICE_SCRAPER_BASELAYER_ERROR_COUNT.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) } @@ -100,10 +97,7 @@ fn get_panel_l1_gas_price_scraper_reorg_detected() -> Panel { "L1 Gas Price Scraper Reorg Detected", "The number of times the L1 gas price scraper detected a reorganization in the base layer \ (10m window)", - vec![format!( - "increase({}[10m])", - L1_GAS_PRICE_SCRAPER_REORG_DETECTED.get_name_with_filter() - )], + format!("increase({}[10m])", L1_GAS_PRICE_SCRAPER_REORG_DETECTED.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -113,9 +107,9 @@ fn get_panel_l1_gas_price_scraper_seconds_since_last_successful_scrape() -> Pane "Seconds since last successful L1 gas price scrape", "The number of seconds since the last successful scrape of the L1 gas price scraper \ (assuming there was a scrape in the last 12 hours)", - vec![get_time_since_last_increase_expr( + get_time_since_last_increase_expr( &L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT.get_name_with_filter(), - )], + ), PanelType::TimeSeries, ) .with_unit(Unit::Seconds) @@ -125,7 +119,7 @@ fn get_panel_l1_gas_price_scraper_latest_scraped_block() -> Panel { Panel::new( "L1 Gas Price Scraper Latest Scraped Block", "The latest block number that the L1 gas price scraper has scraped", - vec![format!("{}", L1_GAS_PRICE_SCRAPER_LATEST_SCRAPED_BLOCK.get_name_with_filter())], + L1_GAS_PRICE_SCRAPER_LATEST_SCRAPED_BLOCK.get_name_with_filter(), PanelType::Stat, ) } @@ -134,7 +128,7 @@ fn get_panel_l1_gas_price_latest_mean_value() -> Panel { Panel::new( "L1 Gas Price Latest Mean Value", "The latest L1 gas price, calculated as an average by the provider client", - vec![format!("{}", L1_GAS_PRICE_LATEST_MEAN_VALUE.get_name_with_filter())], + L1_GAS_PRICE_LATEST_MEAN_VALUE.get_name_with_filter(), PanelType::TimeSeries, ) } @@ -143,7 +137,7 @@ fn get_panel_l1_data_gas_price_latest_mean_value() -> Panel { Panel::new( "L1 Data Gas Price Latest Mean Value", "The latest L1 data gas price, calculated as an average by the provider client", - vec![format!("{}", L1_DATA_GAS_PRICE_LATEST_MEAN_VALUE.get_name_with_filter())], + L1_DATA_GAS_PRICE_LATEST_MEAN_VALUE.get_name_with_filter(), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/l1_provider.rs b/crates/apollo_dashboard/src/panels/l1_provider.rs index 2f202769e05..84fdf967c20 100644 --- a/crates/apollo_dashboard/src/panels/l1_provider.rs +++ b/crates/apollo_dashboard/src/panels/l1_provider.rs @@ -11,7 +11,7 @@ fn get_panel_l1_message_scraper_success_count() -> Panel { "L1 Message Scraper Success Count", "The increase in the number of times the L1 message scraper successfully scraped messages \ (10m window)", - vec![format!("increase({}[10m])", L1_MESSAGE_SCRAPER_SUCCESS_COUNT.get_name_with_filter())], + format!("increase({}[10m])", L1_MESSAGE_SCRAPER_SUCCESS_COUNT.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -20,10 +20,10 @@ fn get_panel_l1_message_scraper_baselayer_error_count() -> Panel { "L1 Message Scraper Base Layer Error Count", "The increase in the number of times the L1 message scraper encountered an error while \ scraping the base layer (10m window)", - vec![format!( + format!( "increase({}[10m])", L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) } @@ -31,10 +31,7 @@ fn get_panel_l1_message_scraper_reorg_detected() -> Panel { Panel::new( "L1 Message Scraper Reorg Detected", "The increase in the number of times the L1 message scraper detected a reorg (12h window)", - vec![format!( - "increase({}[12h])", - L1_MESSAGE_SCRAPER_REORG_DETECTED.get_name_with_filter() - )], + format!("increase({}[12h])", L1_MESSAGE_SCRAPER_REORG_DETECTED.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -43,9 +40,7 @@ fn get_panel_l1_message_scraper_seconds_since_last_successful_scrape() -> Panel "Seconds since last successful l1 event scrape", "The number of seconds since the last successful scrape of the L1 message scraper \ (assuming there was a scrape in the last 12 hours)", - vec![get_time_since_last_increase_expr( - &L1_MESSAGE_SCRAPER_SUCCESS_COUNT.get_name_with_filter(), - )], + get_time_since_last_increase_expr(&L1_MESSAGE_SCRAPER_SUCCESS_COUNT.get_name_with_filter()), PanelType::TimeSeries, ) .with_unit(Unit::Seconds) diff --git a/crates/apollo_dashboard/src/panels/mempool.rs b/crates/apollo_dashboard/src/panels/mempool.rs index 3ea6e6a9323..bb13e956a5a 100644 --- a/crates/apollo_dashboard/src/panels/mempool.rs +++ b/crates/apollo_dashboard/src/panels/mempool.rs @@ -18,10 +18,10 @@ fn get_panel_mempool_transactions_received_rate() -> Panel { Panel::new( "Mempool Transactions Received Rate (TPS)", "The rate of transactions received by the mempool (1m window)", - vec![format!( + format!( "sum(rate({}[1m])) or vector(0)", MEMPOOL_TRANSACTIONS_RECEIVED.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) .with_log_query("Adding transaction to mempool") @@ -30,7 +30,7 @@ fn get_panel_mempool_transactions_committed() -> Panel { Panel::new( "Transactions Committed", "Number of transactions committed to a block (10m window)", - vec![format!("increase({}[10m])", MEMPOOL_TRANSACTIONS_COMMITTED.get_name_with_filter())], + format!("increase({}[10m])", MEMPOOL_TRANSACTIONS_COMMITTED.get_name_with_filter()), PanelType::TimeSeries, ) } @@ -38,11 +38,11 @@ fn get_panel_mempool_transactions_dropped() -> Panel { Panel::new( "Dropped Transactions by Reason", "Number of transactions dropped from the mempool by reason (over the selected time range)", - vec![format!( + format!( "sum by ({}) (increase({}[$__range]))", LABEL_NAME_DROP_REASON, MEMPOOL_TRANSACTIONS_DROPPED.get_name_with_filter() - )], + ), PanelType::Stat, ) } @@ -50,7 +50,7 @@ fn get_panel_mempool_pool_size() -> Panel { Panel::new( "Pool Size (Num TXs)", "Number of all the transactions in the mempool", - vec![MEMPOOL_POOL_SIZE.get_name_with_filter().to_string()], + MEMPOOL_POOL_SIZE.get_name_with_filter().to_string(), PanelType::TimeSeries, ) } @@ -58,7 +58,7 @@ fn get_panel_mempool_priority_queue_size() -> Panel { Panel::new( "Prioritized Transactions", "Number of transactions prioritized for batching", - vec![MEMPOOL_PRIORITY_QUEUE_SIZE.get_name_with_filter().to_string()], + MEMPOOL_PRIORITY_QUEUE_SIZE.get_name_with_filter().to_string(), PanelType::TimeSeries, ) } @@ -66,7 +66,7 @@ fn get_panel_mempool_pending_queue_size() -> Panel { Panel::new( "Pending Transactions", "Number of transactions eligible for batching but below the gas price threshold", - vec![MEMPOOL_PENDING_QUEUE_SIZE.get_name_with_filter().to_string()], + MEMPOOL_PENDING_QUEUE_SIZE.get_name_with_filter().to_string(), PanelType::TimeSeries, ) } @@ -74,7 +74,7 @@ fn get_panel_mempool_total_size_in_bytes() -> Panel { Panel::new( "Mempool Size (Data)", "Size of the transactions in the mempool", - vec![MEMPOOL_TOTAL_SIZE_BYTES.get_name_with_filter().to_string()], + MEMPOOL_TOTAL_SIZE_BYTES.get_name_with_filter().to_string(), PanelType::TimeSeries, ) .with_unit(Unit::Bytes) @@ -83,7 +83,7 @@ fn get_panel_mempool_delayed_declares_size() -> Panel { Panel::new( "Delayed Declare Transactions", "Number of delayed declare transactions", - vec![MEMPOOL_DELAYED_DECLARES_SIZE.get_name_with_filter().to_string()], + MEMPOOL_DELAYED_DECLARES_SIZE.get_name_with_filter().to_string(), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/mempool_p2p.rs b/crates/apollo_dashboard/src/panels/mempool_p2p.rs index 6ae032e3f63..c12792d87a0 100644 --- a/crates/apollo_dashboard/src/panels/mempool_p2p.rs +++ b/crates/apollo_dashboard/src/panels/mempool_p2p.rs @@ -37,11 +37,11 @@ fn get_panel_mempool_p2p_network_events_by_type() -> Panel { Panel::new( MEMPOOL_P2P_NETWORK_EVENTS.get_name(), MEMPOOL_P2P_NETWORK_EVENTS.get_description(), - vec![format!( + format!( "sum by ({}) ({})", LABEL_NAME_EVENT_TYPE, MEMPOOL_P2P_NETWORK_EVENTS.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) } @@ -50,11 +50,11 @@ fn get_panel_mempool_p2p_dropped_messages_by_reason() -> Panel { Panel::new( MEMPOOL_P2P_NUM_DROPPED_MESSAGES.get_name(), MEMPOOL_P2P_NUM_DROPPED_MESSAGES.get_description(), - vec![format!( + format!( "sum by ({}) ({})", LABEL_NAME_BROADCAST_DROP_REASON, MEMPOOL_P2P_NUM_DROPPED_MESSAGES.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/pod_metrics.rs b/crates/apollo_dashboard/src/panels/pod_metrics.rs index 67f7b54858f..859ce3a3e59 100644 --- a/crates/apollo_dashboard/src/panels/pod_metrics.rs +++ b/crates/apollo_dashboard/src/panels/pod_metrics.rs @@ -6,7 +6,7 @@ fn get_pod_memory_utilization_panel() -> Panel { Panel::new( "pod_memory_utilization", "Pod Memory Utilization", - vec![format!("container_memory_working_set_bytes{0}", metric_label_filter!())], + format!("container_memory_working_set_bytes{0}", metric_label_filter!()), PanelType::TimeSeries, ) } @@ -15,7 +15,7 @@ fn get_pod_disk_utilization_panel() -> Panel { Panel::new( "pod_disk_utilization", "Pod Disk Utilization", - vec![format!("kubelet_volume_stats_used_bytes{0}", metric_label_filter!())], + format!("kubelet_volume_stats_used_bytes{0}", metric_label_filter!()), PanelType::TimeSeries, ) } @@ -24,7 +24,7 @@ fn get_pod_cpu_utilization_panel() -> Panel { Panel::new( "pod_cpu_utilization", "Pod CPU Utilization", - vec![format!("container_cpu_usage_seconds_total{0}", metric_label_filter!())], + format!("container_cpu_usage_seconds_total{0}", metric_label_filter!()), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/sierra_compiler.rs b/crates/apollo_dashboard/src/panels/sierra_compiler.rs index 10d28e82879..d15d8e0a1d4 100644 --- a/crates/apollo_dashboard/src/panels/sierra_compiler.rs +++ b/crates/apollo_dashboard/src/panels/sierra_compiler.rs @@ -15,11 +15,7 @@ fn get_panel_n_classes() -> Panel { Panel::new( "Number of Classes", "Number of classes, labeled by type (regular, deprecated)", - vec![format!( - "sum by ({}) (increase({}[10m]))", - "class_type", - N_CLASSES.get_name_with_filter() - )], + format!("sum by ({}) (increase({}[10m]))", "class_type", N_CLASSES.get_name_with_filter()), PanelType::Stat, ) } diff --git a/crates/apollo_dashboard/src/panels/state_sync.rs b/crates/apollo_dashboard/src/panels/state_sync.rs index ea643db5844..5cde00a0bad 100644 --- a/crates/apollo_dashboard/src/panels/state_sync.rs +++ b/crates/apollo_dashboard/src/panels/state_sync.rs @@ -28,7 +28,7 @@ fn get_panel_central_sync_central_block_marker() -> Panel { Panel::new( "Central Block Marker", "The first block that Central Starknet hasn't seen yet", - vec![CENTRAL_SYNC_CENTRAL_BLOCK_MARKER.get_name_with_filter().to_string()], + CENTRAL_SYNC_CENTRAL_BLOCK_MARKER.get_name_with_filter().to_string(), PanelType::Stat, ) } @@ -36,7 +36,7 @@ fn get_panel_state_sync_body_marker() -> Panel { Panel::new( "State Sync Body Marker", "The first block number for which the state sync component does not have a body", - vec![STATE_SYNC_BODY_MARKER.get_name_with_filter().to_string()], + STATE_SYNC_BODY_MARKER.get_name_with_filter().to_string(), PanelType::Stat, ) } @@ -44,11 +44,11 @@ fn get_panel_state_sync_diff_from_central() -> Panel { Panel::new( "Sync Diff From Central", "The number of blocks that were not fully synced yet", - vec![format!( + format!( "{} - {}", CENTRAL_SYNC_CENTRAL_BLOCK_MARKER.get_name_with_filter(), STATE_SYNC_CLASS_MANAGER_MARKER.get_name_with_filter() - )], + ), PanelType::TimeSeries, ) } @@ -56,7 +56,7 @@ fn get_panel_state_sync_new_header_maturity() -> Panel { Panel::new( "Sync Block Age", "The time from a block’s timestamp until its header is synced through the feeder-gateway.", - vec![STATE_SYNC_HEADER_LATENCY_SEC.get_name_with_filter().to_string()], + STATE_SYNC_HEADER_LATENCY_SEC.get_name_with_filter().to_string(), PanelType::TimeSeries, ) .with_unit(Unit::Seconds) From 8a7a0383789916050b7bafda909115a440a26921 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 2 Nov 2025 13:20:19 +0200 Subject: [PATCH 225/313] apollo_dashboard: create MetricCommon trait (#9857) --- Cargo.lock | 1 + .../apollo_dashboard/src/alert_definitions.rs | 1 + .../alert_scenarios/block_production_delay.rs | 1 + .../alert_scenarios/block_production_halt.rs | 1 + .../src/alert_scenarios/l1_gas_prices.rs | 1 + .../src/alert_scenarios/l1_handlers.rs | 1 + .../src/alert_scenarios/mempool_size.rs | 1 + .../src/alert_scenarios/preconfirmed.rs | 2 + .../src/alert_scenarios/sync_halt.rs | 1 + .../src/alert_scenarios/tps.rs | 1 + .../src/alert_scenarios/transaction_delays.rs | 1 + .../alert_scenarios/transaction_failures.rs | 1 + crates/apollo_dashboard/src/dashboard.rs | 1 + crates/apollo_dashboard/src/dashboard_test.rs | 2 +- crates/apollo_dashboard/src/panels/batcher.rs | 1 + .../apollo_dashboard/src/panels/blockifier.rs | 1 + .../apollo_dashboard/src/panels/consensus.rs | 1 + crates/apollo_dashboard/src/panels/gateway.rs | 1 + .../src/panels/http_server.rs | 1 + .../src/panels/l1_gas_price.rs | 1 + .../src/panels/l1_provider.rs | 1 + crates/apollo_dashboard/src/panels/mempool.rs | 1 + .../src/panels/mempool_p2p.rs | 1 + .../src/panels/sierra_compiler.rs | 1 + .../apollo_dashboard/src/panels/state_sync.rs | 1 + crates/apollo_integration_tests/Cargo.toml | 1 + .../src/monitoring_utils.rs | 1 + crates/apollo_metrics/src/lib.rs | 2 + crates/apollo_metrics/src/metrics.rs | 315 ++++++++++-------- .../tests/latency_histogram.rs | 7 +- .../apollo_state_sync_metrics/src/metrics.rs | 2 +- 31 files changed, 213 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a5d443645a..c8a8fd02070 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1589,6 +1589,7 @@ dependencies = [ "apollo_l1_scraper_config", "apollo_mempool_config", "apollo_mempool_p2p_config", + "apollo_metrics", "apollo_monitoring_endpoint", "apollo_monitoring_endpoint_config", "apollo_network", diff --git a/crates/apollo_dashboard/src/alert_definitions.rs b/crates/apollo_dashboard/src/alert_definitions.rs index 37d55a7029d..c73156678af 100644 --- a/crates/apollo_dashboard/src/alert_definitions.rs +++ b/crates/apollo_dashboard/src/alert_definitions.rs @@ -23,6 +23,7 @@ use apollo_l1_provider::metrics::{ L1_MESSAGE_SCRAPER_REORG_DETECTED, }; use apollo_mempool_p2p::metrics::MEMPOOL_P2P_NUM_CONNECTED_PEERS; +use apollo_metrics::MetricCommon; use apollo_storage::metrics::{ BATCHER_STORAGE_OPEN_READ_TRANSACTIONS, CLASS_MANAGER_STORAGE_OPEN_READ_TRANSACTIONS, diff --git a/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs b/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs index cfa7fe2568a..61a4571be20 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/block_production_delay.rs @@ -1,6 +1,7 @@ use apollo_consensus::metrics::{CONSENSUS_BLOCK_NUMBER, CONSENSUS_ROUND_ABOVE_ZERO}; use apollo_consensus_manager::metrics::CONSENSUS_NUM_CONNECTED_PEERS; use apollo_consensus_orchestrator::metrics::CENDE_WRITE_BLOB_FAILURE; +use apollo_metrics::MetricCommon; use crate::alert_definitions::BLOCK_TIME_SEC; use crate::alerts::{ 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 d5bc3b4c262..581a4a564ef 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/block_production_halt.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/block_production_halt.rs @@ -3,6 +3,7 @@ use std::time::Duration; use apollo_batcher::metrics::BATCHED_TRANSACTIONS; use apollo_consensus::metrics::{CONSENSUS_BLOCK_NUMBER, CONSENSUS_ROUND}; use apollo_consensus_manager::metrics::CONSENSUS_NUM_CONNECTED_PEERS; +use apollo_metrics::MetricCommon; use crate::alert_definitions::BLOCK_TIME_SEC; use crate::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 b3e9badc9dd..c45ec3c9745 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,7 @@ use apollo_l1_gas_price::metrics::{ L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, }; +use apollo_metrics::MetricCommon; use crate::alerts::{ Alert, diff --git a/crates/apollo_dashboard/src/alert_scenarios/l1_handlers.rs b/crates/apollo_dashboard/src/alert_scenarios/l1_handlers.rs index 7916d27700a..726c106d7cf 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/l1_handlers.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/l1_handlers.rs @@ -1,4 +1,5 @@ use apollo_l1_provider::metrics::L1_MESSAGE_SCRAPER_SUCCESS_COUNT; +use apollo_metrics::MetricCommon; use crate::alerts::{ Alert, diff --git a/crates/apollo_dashboard/src/alert_scenarios/mempool_size.rs b/crates/apollo_dashboard/src/alert_scenarios/mempool_size.rs index 107efbdad71..455ee5e0999 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/mempool_size.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/mempool_size.rs @@ -4,6 +4,7 @@ use apollo_mempool::metrics::{ MEMPOOL_POOL_SIZE, MEMPOOL_TRANSACTIONS_DROPPED, }; +use apollo_metrics::MetricCommon; use crate::alerts::{ Alert, diff --git a/crates/apollo_dashboard/src/alert_scenarios/preconfirmed.rs b/crates/apollo_dashboard/src/alert_scenarios/preconfirmed.rs index 4d35e37e030..e9b1960827a 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/preconfirmed.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/preconfirmed.rs @@ -36,6 +36,8 @@ fn get_preconfirmed_block_not_written( ) } +use apollo_metrics::MetricCommon; + pub(crate) fn get_preconfirmed_block_not_written_vec() -> Vec { vec![ get_preconfirmed_block_not_written( diff --git a/crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs b/crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs index 1171d5e0fdd..03bccd9a2e8 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs @@ -1,5 +1,6 @@ use std::time::Duration; +use apollo_metrics::MetricCommon; use apollo_state_sync_metrics::metrics::{ CENTRAL_SYNC_CENTRAL_BLOCK_MARKER, STATE_SYNC_CLASS_MANAGER_MARKER, diff --git a/crates/apollo_dashboard/src/alert_scenarios/tps.rs b/crates/apollo_dashboard/src/alert_scenarios/tps.rs index e5f37411c4b..c15a2c1d778 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/tps.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/tps.rs @@ -6,6 +6,7 @@ use apollo_gateway::metrics::{ }; use apollo_http_server::metrics::ADDED_TRANSACTIONS_SUCCESS; use apollo_mempool::metrics::MEMPOOL_TRANSACTIONS_RECEIVED; +use apollo_metrics::MetricCommon; use crate::alerts::{ Alert, diff --git a/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs b/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs index a03bca2923a..a457337df5f 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/transaction_delays.rs @@ -1,6 +1,7 @@ use apollo_batcher::metrics::NUM_TRANSACTION_IN_BLOCK; use apollo_http_server::metrics::HTTP_SERVER_ADD_TX_LATENCY; use apollo_mempool_p2p::metrics::MEMPOOL_P2P_NUM_CONNECTED_PEERS; +use apollo_metrics::MetricCommon; use crate::alerts::{ Alert, diff --git a/crates/apollo_dashboard/src/alert_scenarios/transaction_failures.rs b/crates/apollo_dashboard/src/alert_scenarios/transaction_failures.rs index 1cba3d44dfb..04197c62f19 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/transaction_failures.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/transaction_failures.rs @@ -5,6 +5,7 @@ use apollo_http_server::metrics::{ ADDED_TRANSACTIONS_TOTAL, }; use apollo_mempool::metrics::{MEMPOOL_TRANSACTIONS_DROPPED, MEMPOOL_TRANSACTIONS_RECEIVED}; +use apollo_metrics::MetricCommon; use crate::alerts::{ Alert, diff --git a/crates/apollo_dashboard/src/dashboard.rs b/crates/apollo_dashboard/src/dashboard.rs index 312d8579428..76979e1cb35 100644 --- a/crates/apollo_dashboard/src/dashboard.rs +++ b/crates/apollo_dashboard/src/dashboard.rs @@ -8,6 +8,7 @@ use apollo_infra::metrics::{ use apollo_infra::requests::LABEL_NAME_REQUEST_VARIANT; use apollo_metrics::metrics::{ LabeledMetricHistogram, + MetricCommon, MetricCounter, MetricGauge, MetricHistogram, diff --git a/crates/apollo_dashboard/src/dashboard_test.rs b/crates/apollo_dashboard/src/dashboard_test.rs index fcf49d8b2ad..adfb32307fd 100644 --- a/crates/apollo_dashboard/src/dashboard_test.rs +++ b/crates/apollo_dashboard/src/dashboard_test.rs @@ -1,5 +1,5 @@ use apollo_infra_utils::test_utils::assert_json_eq; -use apollo_metrics::metrics::{MetricCounter, MetricScope}; +use apollo_metrics::metrics::{MetricCommon, MetricCounter, MetricScope}; use crate::alerts::{ Alert, diff --git a/crates/apollo_dashboard/src/panels/batcher.rs b/crates/apollo_dashboard/src/panels/batcher.rs index 12ad6cc9d93..1f38e516211 100644 --- a/crates/apollo_dashboard/src/panels/batcher.rs +++ b/crates/apollo_dashboard/src/panels/batcher.rs @@ -12,6 +12,7 @@ use apollo_consensus_orchestrator::metrics::{ CONSENSUS_NUM_BATCHES_IN_PROPOSAL, CONSENSUS_NUM_TXS_IN_PROPOSAL, }; +use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; diff --git a/crates/apollo_dashboard/src/panels/blockifier.rs b/crates/apollo_dashboard/src/panels/blockifier.rs index 54b3ca6657c..37e0174c8cb 100644 --- a/crates/apollo_dashboard/src/panels/blockifier.rs +++ b/crates/apollo_dashboard/src/panels/blockifier.rs @@ -3,6 +3,7 @@ use apollo_batcher::metrics::{ PROVING_GAS_IN_LAST_BLOCK, SIERRA_GAS_IN_LAST_BLOCK, }; +use apollo_metrics::MetricCommon; use blockifier::metrics::{ BLOCKIFIER_METRIC_RATE_DURATION, CALLS_RUNNING_NATIVE, diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 233c80ac6bd..a4f56f05845 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -38,6 +38,7 @@ use apollo_consensus_orchestrator::metrics::{ LABEL_CENDE_FAILURE_REASON, LABEL_VALIDATE_PROPOSAL_FAILURE_REASON, }; +use apollo_metrics::MetricCommon; use apollo_network::network_manager::metrics::{ LABEL_NAME_BROADCAST_DROP_REASON, LABEL_NAME_EVENT_TYPE, diff --git a/crates/apollo_dashboard/src/panels/gateway.rs b/crates/apollo_dashboard/src/panels/gateway.rs index dc1b7d9d4ef..f435a40904d 100644 --- a/crates/apollo_dashboard/src/panels/gateway.rs +++ b/crates/apollo_dashboard/src/panels/gateway.rs @@ -11,6 +11,7 @@ use apollo_gateway::metrics::{ LABEL_NAME_SOURCE, LABEL_NAME_TX_TYPE as GATEWAY_LABEL_NAME_TX_TYPE, }; +use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; diff --git a/crates/apollo_dashboard/src/panels/http_server.rs b/crates/apollo_dashboard/src/panels/http_server.rs index 73764874a02..8b028c85da1 100644 --- a/crates/apollo_dashboard/src/panels/http_server.rs +++ b/crates/apollo_dashboard/src/panels/http_server.rs @@ -6,6 +6,7 @@ use apollo_http_server::metrics::{ ADDED_TRANSACTIONS_TOTAL, HTTP_SERVER_ADD_TX_LATENCY, }; +use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; diff --git a/crates/apollo_dashboard/src/panels/l1_gas_price.rs b/crates/apollo_dashboard/src/panels/l1_gas_price.rs index cc210436d39..aca4547efdf 100644 --- a/crates/apollo_dashboard/src/panels/l1_gas_price.rs +++ b/crates/apollo_dashboard/src/panels/l1_gas_price.rs @@ -11,6 +11,7 @@ use apollo_l1_gas_price::metrics::{ L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, }; use apollo_l1_gas_price_types::DEFAULT_ETH_TO_FRI_RATE; +use apollo_metrics::MetricCommon; use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; diff --git a/crates/apollo_dashboard/src/panels/l1_provider.rs b/crates/apollo_dashboard/src/panels/l1_provider.rs index 84fdf967c20..82a7eaa5f2c 100644 --- a/crates/apollo_dashboard/src/panels/l1_provider.rs +++ b/crates/apollo_dashboard/src/panels/l1_provider.rs @@ -3,6 +3,7 @@ use apollo_l1_provider::metrics::{ L1_MESSAGE_SCRAPER_REORG_DETECTED, L1_MESSAGE_SCRAPER_SUCCESS_COUNT, }; +use apollo_metrics::MetricCommon; use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; diff --git a/crates/apollo_dashboard/src/panels/mempool.rs b/crates/apollo_dashboard/src/panels/mempool.rs index bb13e956a5a..269dcd285a3 100644 --- a/crates/apollo_dashboard/src/panels/mempool.rs +++ b/crates/apollo_dashboard/src/panels/mempool.rs @@ -11,6 +11,7 @@ use apollo_mempool::metrics::{ TRANSACTION_TIME_SPENT_UNTIL_BATCHED, TRANSACTION_TIME_SPENT_UNTIL_COMMITTED, }; +use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; diff --git a/crates/apollo_dashboard/src/panels/mempool_p2p.rs b/crates/apollo_dashboard/src/panels/mempool_p2p.rs index c12792d87a0..c7215abf83f 100644 --- a/crates/apollo_dashboard/src/panels/mempool_p2p.rs +++ b/crates/apollo_dashboard/src/panels/mempool_p2p.rs @@ -6,6 +6,7 @@ use apollo_mempool_p2p::metrics::{ MEMPOOL_P2P_NUM_RECEIVED_MESSAGES, MEMPOOL_P2P_NUM_SENT_MESSAGES, }; +use apollo_metrics::MetricCommon; use apollo_network::network_manager::metrics::{ LABEL_NAME_BROADCAST_DROP_REASON, LABEL_NAME_EVENT_TYPE, diff --git a/crates/apollo_dashboard/src/panels/sierra_compiler.rs b/crates/apollo_dashboard/src/panels/sierra_compiler.rs index d15d8e0a1d4..0a6b6253b3c 100644 --- a/crates/apollo_dashboard/src/panels/sierra_compiler.rs +++ b/crates/apollo_dashboard/src/panels/sierra_compiler.rs @@ -1,5 +1,6 @@ use apollo_class_manager::metrics::{CLASS_SIZES, N_CLASSES}; use apollo_compile_to_casm::metrics::COMPILATION_DURATION; +use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; diff --git a/crates/apollo_dashboard/src/panels/state_sync.rs b/crates/apollo_dashboard/src/panels/state_sync.rs index 5cde00a0bad..b306ba42e5a 100644 --- a/crates/apollo_dashboard/src/panels/state_sync.rs +++ b/crates/apollo_dashboard/src/panels/state_sync.rs @@ -1,3 +1,4 @@ +use apollo_metrics::MetricCommon; use apollo_state_sync_metrics::metrics::{ CENTRAL_SYNC_CENTRAL_BLOCK_MARKER, P2P_SYNC_NUM_ACTIVE_INBOUND_SESSIONS, diff --git a/crates/apollo_integration_tests/Cargo.toml b/crates/apollo_integration_tests/Cargo.toml index d13572f889e..b63dd968b8e 100644 --- a/crates/apollo_integration_tests/Cargo.toml +++ b/crates/apollo_integration_tests/Cargo.toml @@ -40,6 +40,7 @@ apollo_l1_provider_config.workspace = true apollo_l1_scraper_config.workspace = true apollo_mempool_config.workspace = true apollo_mempool_p2p_config.workspace = true +apollo_metrics.workspace = true apollo_monitoring_endpoint = { workspace = true, features = ["testing"] } apollo_monitoring_endpoint_config.workspace = true apollo_network = { workspace = true, features = ["testing"] } diff --git a/crates/apollo_integration_tests/src/monitoring_utils.rs b/crates/apollo_integration_tests/src/monitoring_utils.rs index e0db4e77a07..a654d15fe48 100644 --- a/crates/apollo_integration_tests/src/monitoring_utils.rs +++ b/crates/apollo_integration_tests/src/monitoring_utils.rs @@ -2,6 +2,7 @@ use apollo_batcher::metrics::{REVERTED_TRANSACTIONS, STORAGE_HEIGHT}; use apollo_consensus::metrics::CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS; use apollo_infra_utils::run_until::run_until; use apollo_infra_utils::tracing::{CustomLogger, TraceLevel}; +use apollo_metrics::metrics::MetricCommon; use apollo_monitoring_endpoint::test_utils::MonitoringClient; use apollo_state_sync_metrics::metrics::{ STATE_SYNC_BODY_MARKER, diff --git a/crates/apollo_metrics/src/lib.rs b/crates/apollo_metrics/src/lib.rs index 84feec03d39..3782ee2392a 100644 --- a/crates/apollo_metrics/src/lib.rs +++ b/crates/apollo_metrics/src/lib.rs @@ -4,3 +4,5 @@ pub mod metrics; // Its being exported here to be used in define_metrics macro. pub use paste; + +pub use crate::metrics::MetricCommon; diff --git a/crates/apollo_metrics/src/metrics.rs b/crates/apollo_metrics/src/metrics.rs index b94653dabe0..376d8e82670 100644 --- a/crates/apollo_metrics/src/metrics.rs +++ b/crates/apollo_metrics/src/metrics.rs @@ -50,46 +50,66 @@ pub enum MetricScope { Tokio, } -pub struct MetricCounter { +#[derive(Clone, Debug)] +struct Metric { scope: MetricScope, name: &'static str, description: &'static str, - initial_value: u64, } -impl MetricCounter { - pub const fn new( - scope: MetricScope, - name: &'static str, - description: &'static str, - initial_value: u64, - ) -> Self { - Self { scope, name, description, initial_value } +impl Metric { + pub const fn new(scope: MetricScope, name: &'static str, description: &'static str) -> Self { + Self { scope, name, description } } +} - pub const fn get_name(&self) -> &'static str { +pub trait MetricCommon { + fn get_name(&self) -> &'static str; + fn get_name_with_filter(&self) -> String; + fn get_scope(&self) -> MetricScope; + fn get_description(&self) -> &'static str; +} + +impl MetricCommon for Metric { + fn get_name(&self) -> &'static str { self.name } - pub fn get_name_with_filter(&self) -> String { + fn get_name_with_filter(&self) -> String { format!("{}{}", self.name, metric_label_filter!()) } - pub const fn get_scope(&self) -> MetricScope { + fn get_scope(&self) -> MetricScope { self.scope } - pub const fn get_description(&self) -> &'static str { + fn get_description(&self) -> &'static str { self.description } +} + +pub struct MetricCounter { + metric: Metric, + initial_value: u64, +} + +impl MetricCounter { + pub const fn new( + scope: MetricScope, + name: &'static str, + description: &'static str, + initial_value: u64, + ) -> Self { + Self { metric: Metric::new(scope, name, description), initial_value } + } pub fn register(&self) { - counter!(self.name).absolute(self.initial_value); - describe_counter!(self.name, self.description); + counter!(self.get_name()).absolute(self.initial_value); + describe_counter!(self.get_name(), self.get_description()); } pub fn increment(&self, value: u64) { - counter!(self.name).increment(value); + counter!(self.get_name()).increment(value); } #[cfg(any(feature = "testing", test))] @@ -110,10 +130,26 @@ impl MetricCounter { } } +impl MetricCommon for MetricCounter { + fn get_name(&self) -> &'static str { + self.metric.get_name() + } + + fn get_name_with_filter(&self) -> String { + format!("{}{}", self.metric.get_name(), metric_label_filter!()) + } + + fn get_scope(&self) -> MetricScope { + self.metric.get_scope() + } + + fn get_description(&self) -> &'static str { + self.metric.get_description() + } +} + pub struct LabeledMetricCounter { - scope: MetricScope, - name: &'static str, - description: &'static str, + metric: Metric, initial_value: u64, label_permutations: &'static [&'static [(&'static str, &'static str)]], } @@ -126,34 +162,18 @@ impl LabeledMetricCounter { initial_value: u64, label_permutations: &'static [&'static [(&'static str, &'static str)]], ) -> Self { - Self { scope, name, description, initial_value, label_permutations } - } - - pub const fn get_name(&self) -> &'static str { - self.name - } - - pub fn get_name_with_filter(&self) -> String { - format!("{}{}", self.name, metric_label_filter!()) - } - - pub const fn get_scope(&self) -> MetricScope { - self.scope - } - - pub const fn get_description(&self) -> &'static str { - self.description + Self { metric: Metric::new(scope, name, description), initial_value, label_permutations } } pub fn register(&self) { self.label_permutations.iter().map(|&slice| slice.to_vec()).for_each(|labels| { - counter!(self.name, &labels).absolute(self.initial_value); + counter!(self.get_name(), &labels).absolute(self.initial_value); }); - describe_counter!(self.name, self.description); + describe_counter!(self.get_name(), self.get_description()); } pub fn increment(&self, value: u64, labels: &[(&'static str, &'static str)]) { - counter!(self.name, labels).increment(value); + counter!(self.get_name(), labels).increment(value); } #[cfg(any(feature = "testing", test))] @@ -178,44 +198,44 @@ impl LabeledMetricCounter { } } -pub struct MetricGauge { - scope: MetricScope, - name: &'static str, - description: &'static str, -} - -impl MetricGauge { - pub const fn new(scope: MetricScope, name: &'static str, description: &'static str) -> Self { - Self { scope, name, description } +impl MetricCommon for LabeledMetricCounter { + fn get_name(&self) -> &'static str { + self.metric.get_name() } - pub const fn get_name(&self) -> &'static str { - self.name + fn get_name_with_filter(&self) -> String { + format!("{}{}", self.metric.get_name(), metric_label_filter!()) } - pub fn get_name_with_filter(&self) -> String { - format!("{}{}", self.name, metric_label_filter!()) + fn get_scope(&self) -> MetricScope { + self.metric.get_scope() } - pub const fn get_scope(&self) -> MetricScope { - self.scope + fn get_description(&self) -> &'static str { + self.metric.get_description() } +} - pub const fn get_description(&self) -> &'static str { - self.description +pub struct MetricGauge { + metric: Metric, +} + +impl MetricGauge { + pub const fn new(scope: MetricScope, name: &'static str, description: &'static str) -> Self { + Self { metric: Metric::new(scope, name, description) } } pub fn register(&self) { - let _ = gauge!(self.name); - describe_gauge!(self.name, self.description); + let _ = gauge!(self.get_name()); + describe_gauge!(self.get_name(), self.get_description()); } pub fn increment(&self, value: T) { - gauge!(self.name).increment(value.into_f64()); + gauge!(self.get_name()).increment(value.into_f64()); } pub fn decrement(&self, value: T) { - gauge!(self.name).decrement(value.into_f64()); + gauge!(self.get_name()).decrement(value.into_f64()); } #[cfg(any(feature = "testing", test))] @@ -224,11 +244,11 @@ impl MetricGauge { } pub fn set(&self, value: T) { - gauge!(self.name).set(value.into_f64()); + gauge!(self.get_name()).set(value.into_f64()); } pub fn set_lossy(&self, value: T) { - gauge!(self.name).set(value.into_f64()); + gauge!(self.get_name()).set(value.into_f64()); } #[cfg(any(feature = "testing", test))] @@ -244,6 +264,23 @@ impl MetricGauge { } } +impl MetricCommon for MetricGauge { + fn get_name(&self) -> &'static str { + self.metric.get_name() + } + + fn get_name_with_filter(&self) -> String { + format!("{}{}", self.metric.get_name(), metric_label_filter!()) + } + + fn get_scope(&self) -> MetricScope { + self.metric.get_scope() + } + + fn get_description(&self) -> &'static str { + self.metric.get_description() + } +} /// An object which can be lossy converted into a `f64` representation. pub trait LossyIntoF64 { fn into_f64(self) -> f64; @@ -270,9 +307,7 @@ macro_rules! into_f64 { into_f64!(u64, usize, i64, u128); pub struct LabeledMetricGauge { - scope: MetricScope, - name: &'static str, - description: &'static str, + metric: Metric, label_permutations: &'static [&'static [(&'static str, &'static str)]], } @@ -283,38 +318,22 @@ impl LabeledMetricGauge { description: &'static str, label_permutations: &'static [&'static [(&'static str, &'static str)]], ) -> Self { - Self { scope, name, description, label_permutations } - } - - pub const fn get_name(&self) -> &'static str { - self.name - } - - pub fn get_name_with_filter(&self) -> String { - format!("{}{}", self.name, metric_label_filter!()) - } - - pub const fn get_scope(&self) -> MetricScope { - self.scope - } - - pub const fn get_description(&self) -> &'static str { - self.description + Self { metric: Metric::new(scope, name, description), label_permutations } } pub fn register(&self) { self.label_permutations.iter().map(|&slice| slice.to_vec()).for_each(|label| { - let _ = gauge!(self.name, &label); + let _ = gauge!(self.get_name(), &label); }); - describe_gauge!(self.name, self.description); + describe_gauge!(self.get_name(), self.get_description()); } pub fn increment(&self, value: T, label: &[(&'static str, &'static str)]) { - gauge!(self.name, label).increment(value); + gauge!(self.get_name(), label).increment(value); } pub fn decrement(&self, value: T, label: &[(&'static str, &'static str)]) { - gauge!(self.name, label).decrement(value.into_f64()); + gauge!(self.get_name(), label).decrement(value.into_f64()); } #[cfg(any(feature = "testing", test))] @@ -327,7 +346,7 @@ impl LabeledMetricGauge { } pub fn set(&self, value: T, label: &[(&'static str, &'static str)]) { - gauge!(self.name, label).set(value.into_f64()); + gauge!(self.get_name(), label).set(value.into_f64()); } #[cfg(any(feature = "testing", test))] @@ -343,11 +362,27 @@ impl LabeledMetricGauge { } } +impl MetricCommon for LabeledMetricGauge { + fn get_name(&self) -> &'static str { + self.metric.get_name() + } + + fn get_name_with_filter(&self) -> String { + format!("{}{}", self.metric.get_name(), metric_label_filter!()) + } + + fn get_scope(&self) -> MetricScope { + self.metric.get_scope() + } + + fn get_description(&self) -> &'static str { + self.metric.get_description() + } +} + #[derive(Clone)] pub struct MetricHistogram { - scope: MetricScope, - name: &'static str, - description: &'static str, + metric: Metric, } #[derive(Default, Debug)] @@ -365,48 +400,32 @@ impl PartialEq for HistogramValue { impl MetricHistogram { pub const fn new(scope: MetricScope, name: &'static str, description: &'static str) -> Self { - Self { scope, name, description } - } - - pub const fn get_name(&self) -> &'static str { - self.name - } - - pub fn get_name_with_filter(&self) -> String { - format!("{}_bucket{}", self.name, metric_label_filter!()) + Self { metric: Metric::new(scope, name, description) } } pub fn get_name_sum_with_filter(&self) -> String { - format!("{}_sum{}", self.name, metric_label_filter!()) + format!("{}_sum{}", self.get_name(), metric_label_filter!()) } pub fn get_name_count_with_filter(&self) -> String { - format!("{}_count{}", self.name, metric_label_filter!()) - } - - pub const fn get_scope(&self) -> MetricScope { - self.scope - } - - pub const fn get_description(&self) -> &'static str { - self.description + format!("{}_count{}", self.get_name(), metric_label_filter!()) } pub fn register(&self) { - let _ = histogram!(self.name); - describe_histogram!(self.name, self.description); + let _ = histogram!(self.get_name()); + describe_histogram!(self.get_name(), self.get_description()); } pub fn record(&self, value: T) { - histogram!(self.name).record(value.into_f64()); + histogram!(self.get_name()).record(value.into_f64()); } pub fn record_lossy(&self, value: T) { - histogram!(self.name).record(value.into_f64()); + histogram!(self.get_name()).record(value.into_f64()); } pub fn record_many(&self, value: T, count: usize) { - histogram!(self.name).record_many(value.into_f64(), count); + histogram!(self.get_name()).record_many(value.into_f64(), count); } #[cfg(any(feature = "testing", test))] @@ -422,10 +441,26 @@ impl MetricHistogram { } } +impl MetricCommon for MetricHistogram { + fn get_name(&self) -> &'static str { + self.metric.get_name() + } + + fn get_name_with_filter(&self) -> String { + format!("{}_bucket{}", self.metric.get_name(), metric_label_filter!()) + } + + fn get_scope(&self) -> MetricScope { + self.metric.get_scope() + } + + fn get_description(&self) -> &'static str { + self.metric.get_description() + } +} + pub struct LabeledMetricHistogram { - scope: MetricScope, - name: &'static str, - description: &'static str, + metric: Metric, label_permutations: &'static [&'static [(&'static str, &'static str)]], } @@ -436,23 +471,7 @@ impl LabeledMetricHistogram { description: &'static str, label_permutations: &'static [&'static [(&'static str, &'static str)]], ) -> Self { - Self { scope, name, description, label_permutations } - } - - pub const fn get_name(&self) -> &'static str { - self.name - } - - pub fn get_name_with_filter(&self) -> String { - format!("{}_bucket{}", self.name, metric_label_filter!()) - } - - pub const fn get_scope(&self) -> MetricScope { - self.scope - } - - pub const fn get_description(&self) -> &'static str { - self.description + Self { metric: Metric::new(scope, name, description), label_permutations } } // Returns a flattened and sorted list of the unique label values across all label permutations. @@ -470,9 +489,9 @@ impl LabeledMetricHistogram { pub fn register(&self) { self.label_permutations.iter().map(|&slice| slice.to_vec()).for_each(|labels| { - let _ = histogram!(self.name, &labels); + let _ = histogram!(self.get_name(), &labels); }); - describe_histogram!(self.name, self.description); + describe_histogram!(self.get_name(), self.get_description()); } /// Returns the label name used by this labeled histogram. @@ -481,7 +500,7 @@ impl LabeledMetricHistogram { } pub fn record(&self, value: T, labels: &[(&'static str, &'static str)]) { - histogram!(self.name, labels).record(value.into_f64()); + histogram!(self.get_name(), labels).record(value.into_f64()); } pub fn record_many( @@ -490,7 +509,7 @@ impl LabeledMetricHistogram { count: usize, labels: &[(&'static str, &'static str)], ) { - histogram!(self.name, labels).record_many(value.into_f64(), count); + histogram!(self.get_name(), labels).record_many(value.into_f64(), count); } #[cfg(any(feature = "testing", test))] @@ -515,6 +534,24 @@ impl LabeledMetricHistogram { } } +impl MetricCommon for LabeledMetricHistogram { + fn get_name(&self) -> &'static str { + self.metric.get_name() + } + + fn get_name_with_filter(&self) -> String { + format!("{}_bucket{}", self.metric.get_name(), metric_label_filter!()) + } + + fn get_scope(&self) -> MetricScope { + self.metric.get_scope() + } + + fn get_description(&self) -> &'static str { + self.metric.get_description() + } +} + /// Parses a specific numeric metric value from a metrics string. /// /// # Arguments diff --git a/crates/apollo_proc_macros_tests/tests/latency_histogram.rs b/crates/apollo_proc_macros_tests/tests/latency_histogram.rs index 9408d86821c..37889f68007 100644 --- a/crates/apollo_proc_macros_tests/tests/latency_histogram.rs +++ b/crates/apollo_proc_macros_tests/tests/latency_histogram.rs @@ -1,6 +1,11 @@ use std::sync::OnceLock; -use apollo_metrics::metrics::{MetricHistogram, MetricScope, COLLECT_SEQUENCER_PROFILING_METRICS}; +use apollo_metrics::metrics::{ + MetricCommon, + MetricHistogram, + MetricScope, + COLLECT_SEQUENCER_PROFILING_METRICS, +}; use apollo_proc_macros::{latency_histogram, sequencer_latency_histogram}; use apollo_test_utils::prometheus_is_contained; use metrics::set_default_local_recorder; diff --git a/crates/apollo_state_sync_metrics/src/metrics.rs b/crates/apollo_state_sync_metrics/src/metrics.rs index 6e128f534bf..f5e2c1daeac 100644 --- a/crates/apollo_state_sync_metrics/src/metrics.rs +++ b/crates/apollo_state_sync_metrics/src/metrics.rs @@ -5,7 +5,7 @@ use apollo_infra::metrics::{ RemoteClientMetrics, RemoteServerMetrics, }; -use apollo_metrics::{define_infra_metrics, define_metrics}; +use apollo_metrics::{define_infra_metrics, define_metrics, MetricCommon}; use apollo_state_sync_types::communication::STATE_SYNC_REQUEST_LABELS; use apollo_storage::body::BodyStorageReader; use apollo_storage::class_manager::ClassManagerStorageReader; From a4f1df4453afe69d1450d51d816e58a3b1628fc7 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 2 Nov 2025 13:40:05 +0200 Subject: [PATCH 226/313] scripts: add an abstraction for the args that depend on each other and validate them in one place (#9797) --- scripts/prod/restart_all_nodes_together.py | 19 +-- scripts/prod/set_node_revert_mode.py | 19 +-- .../prod/update_config_and_restart_nodes.py | 11 +- .../update_config_and_restart_nodes_lib.py | 141 +++++++++++------- 4 files changed, 112 insertions(+), 78 deletions(-) diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_nodes_together.py index d7381d8575b..d924c88cd93 100755 --- a/scripts/prod/restart_all_nodes_together.py +++ b/scripts/prod/restart_all_nodes_together.py @@ -7,13 +7,12 @@ import urllib.request from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, + NamespaceAndInstructionArgs, RestartStrategy, Service, get_configmap, - get_context_list_from_args, get_current_block_number, get_logs_explorer_url, - get_namespace_list_from_args, parse_config_from_yaml, print_colored, update_config_and_restart_nodes, @@ -107,12 +106,8 @@ def main(): "consensus_manager_config.immediate_active_height": next_block_number, } - namespace_list = get_namespace_list_from_args(args) - context_list = get_context_list_from_args(args) - if context_list is not None: - assert len(namespace_list) == len( - context_list - ), "namespace_list and context_list must have the same length" + namespace_list = NamespaceAndInstructionArgs.get_namespace_list_from_args(args) + context_list = NamespaceAndInstructionArgs.get_context_list_from_args(args) # Generate logs explorer URLs if needed post_restart_instructions = [] @@ -131,11 +126,13 @@ def main(): update_config_and_restart_nodes( config_overrides, - namespace_list, + NamespaceAndInstructionArgs( + namespace_list, + context_list, + post_restart_instructions, + ), Service.Core, - context_list, RestartStrategy.ALL_AT_ONCE, - post_restart_instructions, ) diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index 19ab8bdbefa..c984e68f9b8 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -6,12 +6,11 @@ import urllib.parse from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, + NamespaceAndInstructionArgs, RestartStrategy, Service, - get_context_list_from_args, get_current_block_number, get_logs_explorer_url, - get_namespace_list_from_args, print_colored, print_error, update_config_and_restart_nodes, @@ -46,20 +45,22 @@ def set_revert_mode( } post_restart_instructions = [] - for namespace, context in zip(namespace_list, context_list): + for namespace, context in zip(namespace_list, context_list or [None] * len(namespace_list)): url = get_logs_explorer_url_for_revert(namespace, revert_up_to_block, project_name) post_restart_instructions.append( f"Please check logs and verify that revert has completed (both in the batcher and for sync). Logs URL: {url}" ) - + namespace_and_instruction_args = NamespaceAndInstructionArgs( + namespace_list, + context_list, + post_restart_instructions, + ) update_config_and_restart_nodes( config_overrides, - namespace_list, + namespace_and_instruction_args, Service.Core, - context_list, restart_strategy, - post_restart_instructions, ) @@ -155,8 +156,8 @@ def main(): print_error("Error: --revert-up-to-block (-b) cannot be set when disabling revert.") sys.exit(1) - namespace_list = get_namespace_list_from_args(args) - context_list = get_context_list_from_args(args) + namespace_list = NamespaceAndInstructionArgs.get_namespace_list_from_args(args) + context_list = NamespaceAndInstructionArgs.get_context_list_from_args(args) should_disable_revert = not args.revert_only if should_revert: diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index 6ef96b2f981..cc2b2ef4142 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -8,9 +8,8 @@ from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, Colors, + NamespaceAndInstructionArgs, Service, - get_context_list_from_args, - get_namespace_list_from_args, print_colored, print_error, update_config_and_restart_nodes, @@ -151,11 +150,13 @@ def main(): update_config_and_restart_nodes( config_overrides, - get_namespace_list_from_args(args), + NamespaceAndInstructionArgs( + NamespaceAndInstructionArgs.get_namespace_list_from_args(args), + NamespaceAndInstructionArgs.get_context_list_from_args(args), + None, + ), args.service, - get_context_list_from_args(args), args.restart_strategy, - None, ) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index a3f32655373..279e99353da 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -211,35 +211,6 @@ def validate_arguments(args: argparse.Namespace) -> None: sys.exit(1) -def get_namespace_list_from_args( - args: argparse.Namespace, -) -> list[str]: - """Get a list of namespaces based on the arguments""" - if args.namespace_list: - return args.namespace_list - - return [ - f"{args.namespace_prefix}-{i}" - for i in range(args.start_index, args.start_index + args.num_nodes) - ] - - -def get_context_list_from_args( - args: argparse.Namespace, -) -> list[str]: - """Get a list of contexts based on the arguments""" - if args.cluster_list: - return args.cluster_list - - if args.cluster_prefix is None: - return None - - return [ - f"{args.cluster_prefix}-{i}" - for i in range(args.start_index, args.start_index + args.num_nodes) - ] - - def get_logs_explorer_url( query: str, project_name: Optional[str] = None, @@ -511,45 +482,103 @@ def restart_pod( sys.exit(1) +class NamespaceAndInstructionArgs: + def __init__( + self, + namespace_list: list[str], + cluster_list: Optional[list[str]], + instruction_list: Optional[list[str]] = None, + ): + assert ( + namespace_list is not None and len(namespace_list) > 0 + ), "Namespace list cannot be None or empty." + self.namespace_list = namespace_list + assert cluster_list is None or len(cluster_list) == len( + namespace_list + ), "cluster_list must have the same length as namespace_list" + self.cluster_list = cluster_list + assert instruction_list is None or len(namespace_list) == len( + instruction_list + ), "instruction_list must have the same length as namespace_list" + self.instruction_list = instruction_list + + def size(self) -> int: + return len(self.namespace_list) + + def get_namespace(self, index: int) -> str: + return self.namespace_list[index] + + def get_cluster(self, index: int) -> Optional[str]: + return self.cluster_list[index] if self.cluster_list is not None else None + + def get_instruction(self, index: int) -> Optional[str]: + return self.instruction_list[index] if self.instruction_list is not None else None + + @staticmethod + def get_namespace_list_from_args( + args: argparse.Namespace, + ) -> list[str]: + """Get a list of namespaces based on the arguments""" + if args.namespace_list: + return args.namespace_list + + return [ + f"{args.namespace_prefix}-{i}" + for i in range(args.start_index, args.start_index + args.num_nodes) + ] + + @staticmethod + def get_context_list_from_args( + args: argparse.Namespace, + ) -> list[str]: + """Get a list of contexts based on the arguments""" + if args.cluster_list: + return args.cluster_list + + if args.cluster_prefix is None: + return None + + return [ + f"{args.cluster_prefix}-{i}" + for i in range(args.start_index, args.start_index + args.num_nodes) + ] + + def update_config_and_restart_nodes( config_overrides: dict[str, Any], - namespace_list: list[str], + namespace_and_instruction_args: NamespaceAndInstructionArgs, service: Service, - cluster_list: Optional[list[str]], restart_strategy: RestartStrategy, - # TODO(guy.f): Add more abstraction to restart strategy so that the instructions are abstracted as part of it. - post_restart_instructions: Optional[list[str]] = None, ) -> None: assert config_overrides is not None, "config_overrides must be provided" - assert namespace_list is not None and len(namespace_list) > 0, "namespaces must be provided" - - if post_restart_instructions is not None: - assert len(post_restart_instructions) == len( - namespace_list - ), f"post_restart_instructions must have the same length as namespace_list. logs_explorer_urls: {len(post_restart_instructions)}, namespace_list: {len(namespace_list)}" + assert namespace_and_instruction_args.namespace_list is not None, "namespaces must be provided" - if not cluster_list: + if not namespace_and_instruction_args.cluster_list: print_colored( "cluster-prefix/cluster-list not provided. Assuming all nodes are on the current cluster", Colors.RED, ) - else: - assert len(cluster_list) == len( - namespace_list - ), f"cluster_list must have the same number of values as namespace_list. cluster_list: {cluster_list}, namespace_list: {namespace_list}" # Store original and updated configs for all nodes configs = [] # Process each node's configuration - for index, namespace in enumerate(namespace_list): - cluster = cluster_list[index] if cluster_list else None + for index in range(namespace_and_instruction_args.size()): + namespace = namespace_and_instruction_args.get_namespace(index) + cluster = namespace_and_instruction_args.get_cluster(index) + print_colored( - f"\nProcessing node for namespace {namespace} (cluster: {cluster if cluster else 'current cluster'})..." + f"\nProcessing node for namespace {namespace} (cluster: {cluster if cluster is not None else 'current cluster'})..." ) # Get current config and normalize it (e.g. " vs ') to ensure not showing bogus diffs. - original_config = normalize_config(get_configmap(namespace, cluster, service)) + original_config = normalize_config( + get_configmap( + namespace, + cluster, + service, + ) + ) # Update config updated_config = update_config_values(original_config, config_overrides) @@ -570,18 +599,24 @@ def update_config_and_restart_nodes( print(f"Applying config {index}...") apply_configmap( config["updated"], - namespace_list[index], + namespace_and_instruction_args.get_namespace(index), index, - cluster_list[index] if cluster_list else None, + namespace_and_instruction_args.get_cluster(index), ) if restart_strategy != RestartStrategy.NO_RESTART: for index, config in enumerate(configs): restart_pod( - namespace_list[index], service, index, cluster_list[index] if cluster_list else None + namespace_and_instruction_args.get_namespace(index), + service, + index, + namespace_and_instruction_args.get_cluster(index), + ) + instructions = namespace_and_instruction_args.get_instruction(index) + print_colored( + f"Restarted pod.\n{instructions if instructions is not None else ''} ", + Colors.YELLOW, ) - instructions = post_restart_instructions[index] if post_restart_instructions else None - print_colored(f"Restarted pod.\n{instructions if instructions else ''} ", Colors.YELLOW) if restart_strategy == RestartStrategy.ONE_BY_ONE: # Don't ask in the case of the last job. if index != len(configs) - 1 and not wait_until_y_or_n( From 79d408134b8b034ebde352bde9e722aa9be9ef32 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 2 Nov 2025 13:49:28 +0200 Subject: [PATCH 227/313] apollo_dashboard: add new module queries_builder (#9863) --- crates/apollo_dashboard/src/lib.rs | 4 ++++ crates/apollo_dashboard/src/query_builder.rs | 9 +++++++++ crates/apollo_dashboard/src/query_builder_test.rs | 14 ++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 crates/apollo_dashboard/src/query_builder.rs create mode 100644 crates/apollo_dashboard/src/query_builder_test.rs diff --git a/crates/apollo_dashboard/src/lib.rs b/crates/apollo_dashboard/src/lib.rs index 45ae7a90646..d6a12909c72 100644 --- a/crates/apollo_dashboard/src/lib.rs +++ b/crates/apollo_dashboard/src/lib.rs @@ -6,3 +6,7 @@ pub mod dashboard_definitions; #[cfg(test)] mod metric_definitions_test; mod panels; + +// TODO(MatanL): Remove cfg(test) when used +#[cfg(test)] +mod query_builder; diff --git a/crates/apollo_dashboard/src/query_builder.rs b/crates/apollo_dashboard/src/query_builder.rs new file mode 100644 index 00000000000..9b92ff8786e --- /dev/null +++ b/crates/apollo_dashboard/src/query_builder.rs @@ -0,0 +1,9 @@ +use apollo_metrics::metrics::MetricCommon; + +#[cfg(test)] +#[path = "query_builder_test.rs"] +pub mod query_builder_test; + +pub(crate) fn increase(metric: &dyn MetricCommon, duration: &str) -> String { + format!("increase({}[{}])", metric.get_name_with_filter(), duration) +} diff --git a/crates/apollo_dashboard/src/query_builder_test.rs b/crates/apollo_dashboard/src/query_builder_test.rs new file mode 100644 index 00000000000..60bbab71891 --- /dev/null +++ b/crates/apollo_dashboard/src/query_builder_test.rs @@ -0,0 +1,14 @@ +use apollo_infra_utils::template::Template; +use apollo_metrics::metric_label_filter; +use apollo_metrics::metrics::{MetricGauge, MetricScope}; + +use crate::query_builder; + +#[test] +fn increase_formats_correctly() { + let m = MetricGauge::new(MetricScope::Batcher, "testing", "Fake description"); + let q = query_builder::increase(&m, "5m"); + let expected = + Template::new("increase({}{}[{}])").format(&[&"testing", &metric_label_filter!(), &"5m"]); + assert_eq!(q, expected); +} From d11f2138fe34d6b6d5699549ca0eafca5b2b3b81 Mon Sep 17 00:00:00 2001 From: Nadin Jbara <93648739+nadin-Starkware@users.noreply.github.com> Date: Sun, 2 Nov 2025 13:57:38 +0200 Subject: [PATCH 228/313] apollo_config_manager: remove test from test name (#9901) --- crates/apollo_config_manager/src/config_manager_runner_tests.rs | 2 +- crates/apollo_config_manager/src/config_manager_tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/apollo_config_manager/src/config_manager_runner_tests.rs b/crates/apollo_config_manager/src/config_manager_runner_tests.rs index da1785f9551..0ca15b915c2 100644 --- a/crates/apollo_config_manager/src/config_manager_runner_tests.rs +++ b/crates/apollo_config_manager/src/config_manager_runner_tests.rs @@ -89,7 +89,7 @@ fn update_config_file(temp_file: &NamedTempFile) -> String { } #[tokio::test] -async fn test_config_manager_runner_update_config_with_changed_values() { +async fn config_manager_runner_update_config_with_changed_values() { // Set a mock config manager client to expect the update dynamic config request. let mut mock_client = MockConfigManagerClient::new(); mock_client.expect_set_node_dynamic_config().times(1..).return_const(Ok(())); diff --git a/crates/apollo_config_manager/src/config_manager_tests.rs b/crates/apollo_config_manager/src/config_manager_tests.rs index 1be2fbf52a2..201d6abe57d 100644 --- a/crates/apollo_config_manager/src/config_manager_tests.rs +++ b/crates/apollo_config_manager/src/config_manager_tests.rs @@ -6,7 +6,7 @@ use apollo_node_config::node_config::NodeDynamicConfig; use crate::config_manager::ConfigManager; #[tokio::test] -async fn test_config_manager_update_config() { +async fn config_manager_update_config() { // Set a config manager. let config = ConfigManagerConfig::default(); From 568d821e5bfeeb822baf88790df82a08b018ca00 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 2 Nov 2025 14:03:39 +0200 Subject: [PATCH 229/313] scripts: Add an abstraction for how to restart pods. (#9798) --- scripts/prod/restart_all_nodes_together.py | 20 +- scripts/prod/set_node_revert_mode.py | 10 +- .../prod/update_config_and_restart_nodes.py | 22 +- .../update_config_and_restart_nodes_lib.py | 320 +++++++++++------- 4 files changed, 232 insertions(+), 140 deletions(-) diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_nodes_together.py index d924c88cd93..c81db16800a 100755 --- a/scripts/prod/restart_all_nodes_together.py +++ b/scripts/prod/restart_all_nodes_together.py @@ -10,6 +10,7 @@ NamespaceAndInstructionArgs, RestartStrategy, Service, + ServiceRestarter, get_configmap, get_current_block_number, get_logs_explorer_url, @@ -124,15 +125,22 @@ def main(): f"Please check logs and verify that the node has proposed a block that was accepted. Logs URL: {url}" ) + namespace_and_instruction_args = NamespaceAndInstructionArgs( + namespace_list, + context_list, + post_restart_instructions, + ) + restarter = ServiceRestarter.from_restart_strategy( + RestartStrategy.ALL_AT_ONCE, + namespace_and_instruction_args, + Service.Core, + ) + update_config_and_restart_nodes( config_overrides, - NamespaceAndInstructionArgs( - namespace_list, - context_list, - post_restart_instructions, - ), + namespace_and_instruction_args, Service.Core, - RestartStrategy.ALL_AT_ONCE, + restarter, ) diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index c984e68f9b8..685a5bb3eb5 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -9,6 +9,7 @@ NamespaceAndInstructionArgs, RestartStrategy, Service, + ServiceRestarter, get_current_block_number, get_logs_explorer_url, print_colored, @@ -51,16 +52,23 @@ def set_revert_mode( post_restart_instructions.append( f"Please check logs and verify that revert has completed (both in the batcher and for sync). Logs URL: {url}" ) + namespace_and_instruction_args = NamespaceAndInstructionArgs( namespace_list, context_list, post_restart_instructions, ) + restarter = ServiceRestarter.from_restart_strategy( + restart_strategy, + namespace_and_instruction_args, + Service.Core, + ) + update_config_and_restart_nodes( config_overrides, namespace_and_instruction_args, Service.Core, - restart_strategy, + restarter, ) diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index cc2b2ef4142..c3f75c11943 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -10,6 +10,7 @@ Colors, NamespaceAndInstructionArgs, Service, + ServiceRestarter, print_colored, print_error, update_config_and_restart_nodes, @@ -148,15 +149,20 @@ def main(): print_error("No config overrides provided") sys.exit(1) - update_config_and_restart_nodes( - config_overrides, - NamespaceAndInstructionArgs( - NamespaceAndInstructionArgs.get_namespace_list_from_args(args), - NamespaceAndInstructionArgs.get_context_list_from_args(args), - None, - ), - args.service, + namespace_and_instruction_args = NamespaceAndInstructionArgs( + NamespaceAndInstructionArgs.get_namespace_list_from_args(args), + NamespaceAndInstructionArgs.get_context_list_from_args(args), + None, + ) + + restarter = ServiceRestarter.from_restart_strategy( args.restart_strategy, + namespace_and_instruction_args, + args.service, + ) + + update_config_and_restart_nodes( + config_overrides, namespace_and_instruction_args, args.service, restarter ) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 279e99353da..58205c002d4 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -4,8 +4,9 @@ import json import subprocess import sys +from abc import ABC, abstractmethod from enum import Enum -from typing import Any, Optional +from typing import Any, Callable, Optional import tempfile import urllib.error @@ -211,6 +212,192 @@ def validate_arguments(args: argparse.Namespace) -> None: sys.exit(1) +class NamespaceAndInstructionArgs: + def __init__( + self, + namespace_list: list[str], + cluster_list: Optional[list[str]], + instruction_list: Optional[list[str]] = None, + ): + assert ( + namespace_list is not None and len(namespace_list) > 0 + ), "Namespace list cannot be None or empty." + self.namespace_list = namespace_list + assert cluster_list is None or len(cluster_list) == len( + namespace_list + ), "cluster_list must have the same length as namespace_list" + self.cluster_list = cluster_list + assert instruction_list is None or len(namespace_list) == len( + instruction_list + ), "instruction_list must have the same length as namespace_list" + self.instruction_list = instruction_list + + def size(self) -> int: + return len(self.namespace_list) + + def get_namespace(self, index: int) -> str: + return self.namespace_list[index] + + def get_cluster(self, index: int) -> Optional[str]: + return self.cluster_list[index] if self.cluster_list is not None else None + + def get_instruction(self, index: int) -> Optional[str]: + return self.instruction_list[index] if self.instruction_list is not None else None + + @staticmethod + def get_namespace_list_from_args( + args: argparse.Namespace, + ) -> list[str]: + """Get a list of namespaces based on the arguments""" + if args.namespace_list: + return args.namespace_list + + return [ + f"{args.namespace_prefix}-{i}" + for i in range(args.start_index, args.start_index + args.num_nodes) + ] + + @staticmethod + def get_context_list_from_args( + args: argparse.Namespace, + ) -> list[str]: + """Get a list of contexts based on the arguments""" + if args.cluster_list: + return args.cluster_list + + if args.cluster_prefix is None: + return None + + return [ + f"{args.cluster_prefix}-{i}" + for i in range(args.start_index, args.start_index + args.num_nodes) + ] + + +class ServiceRestarter(ABC): + """Abstract class for restarting service instances.""" + + def __init__( + self, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + ): + self.namespace_and_instruction_args = namespace_and_instruction_args + self.service = service + + @staticmethod + def _restart_pod( + namespace: str, service: Service, index: int, cluster: Optional[str] = None + ) -> None: + """Restart pod by deleting it""" + # Get the list of pods (one string per line). + kubectl_args = [ + "get", + "pods", + "-o", + "name", + ] + kubectl_args.extend(get_namespace_args(namespace, cluster)) + pods = run_kubectl_command(kubectl_args, capture_output=True).stdout.splitlines() + + # Filter the list of pods to only include the ones that match the service and extract the pod name. + pods = [pod.split("/")[1] for pod in pods if pod.startswith(f"pod/{service.pod_name}")] + + if not pods: + print_error(f"Could not find pods for service {service.pod_name}.") + sys.exit(1) + + # Go over each pod and delete it. + for pod in pods: + kubectl_args = [ + "delete", + "pod", + pod, + ] + kubectl_args.extend(get_namespace_args(namespace, cluster)) + + try: + run_kubectl_command(kubectl_args, capture_output=False) + print_colored(f"Restarted {pod} for node {index}") + except Exception as e: + print_error(f"Failed restarting {pod} for node {index}: {e}") + sys.exit(1) + + @abstractmethod + def restart_service(self, instance_index: int) -> bool: + """Restart service for a specific instance. If returns False, the restart process should be aborted.""" + + # from_restart_strategy is a static method that returns the appropriate ServiceRestarter based on the restart strategy. + @staticmethod + def from_restart_strategy( + restart_strategy: RestartStrategy, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + ) -> "ServiceRestarter": + if restart_strategy == RestartStrategy.ONE_BY_ONE: + check_between_restarts = lambda instance_index: ( + True + if instance_index == namespace_and_instruction_args.size() - 1 + else wait_until_y_or_n(f"Do you want to restart the next pod?") + ) + + return ChecksBetweenRestarts( + namespace_and_instruction_args, + service, + check_between_restarts, + ) + elif restart_strategy == RestartStrategy.ALL_AT_ONCE: + return ChecksBetweenRestarts( + namespace_and_instruction_args, + service, + lambda instance_index: True, + ) + elif restart_strategy == RestartStrategy.NO_RESTART: + assert ( + namespace_and_instruction_args.get_instruction(0) is None + ), f"post_restart_instructions is not allowed with no_restart as the restart strategy" + return NoOpServiceRestarter(namespace_and_instruction_args, service) + else: + raise ValueError(f"Invalid restart strategy: {restart_strategy}") + + +class ChecksBetweenRestarts(ServiceRestarter): + """Checks between restarts.""" + + def __init__( + self, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + check_between_restarts: Callable[[int], bool], + ): + super().__init__(namespace_and_instruction_args, service) + self.check_between_restarts = check_between_restarts + + def restart_service(self, instance_index: int) -> bool: + """Restart the instance one by one, running the use code in between each restart.""" + self._restart_pod( + self.namespace_and_instruction_args.get_namespace(instance_index), + self.service, + instance_index, + self.namespace_and_instruction_args.get_cluster(instance_index), + ) + instructions = self.namespace_and_instruction_args.get_instruction(instance_index) + print_colored( + f"Restarted pod {instance_index}.\n{instructions if instructions is not None else ''} ", + Colors.YELLOW, + ) + return self.check_between_restarts(instance_index) + + +class NoOpServiceRestarter(ServiceRestarter): + """No-op service restarter.""" + + def restart_service(self, instance_index: int) -> bool: + """No-op.""" + print_colored("\nSkipping pod restart.") + return True + + def get_logs_explorer_url( query: str, project_name: Optional[str] = None, @@ -444,111 +631,11 @@ def apply_configmap( sys.exit(1) -def restart_pod( - namespace: str, service: Service, index: int, cluster: Optional[str] = None -) -> None: - """Restart pod by deleting it""" - # Get the list of pods (one string per line). - kubectl_args = [ - "get", - "pods", - "-o", - "name", - ] - kubectl_args.extend(get_namespace_args(namespace, cluster)) - pods = run_kubectl_command(kubectl_args, capture_output=True).stdout.splitlines() - - # Filter the list of pods to only include the ones that match the service and extract the pod name. - pods = [pod.split("/")[1] for pod in pods if pod.startswith(f"pod/{service.pod_name}")] - - if not pods: - print_error(f"Could not find pods for service {service.pod_name}.") - sys.exit(1) - - # Go over each pod and delete it. - for pod in pods: - kubectl_args = [ - "delete", - "pod", - pod, - ] - kubectl_args.extend(get_namespace_args(namespace, cluster)) - - try: - run_kubectl_command(kubectl_args, capture_output=False) - print_colored(f"Restarted {pod} for node {index}") - except Exception as e: - print_error(f"Failed restarting {pod} for node {index}: {e}") - sys.exit(1) - - -class NamespaceAndInstructionArgs: - def __init__( - self, - namespace_list: list[str], - cluster_list: Optional[list[str]], - instruction_list: Optional[list[str]] = None, - ): - assert ( - namespace_list is not None and len(namespace_list) > 0 - ), "Namespace list cannot be None or empty." - self.namespace_list = namespace_list - assert cluster_list is None or len(cluster_list) == len( - namespace_list - ), "cluster_list must have the same length as namespace_list" - self.cluster_list = cluster_list - assert instruction_list is None or len(namespace_list) == len( - instruction_list - ), "instruction_list must have the same length as namespace_list" - self.instruction_list = instruction_list - - def size(self) -> int: - return len(self.namespace_list) - - def get_namespace(self, index: int) -> str: - return self.namespace_list[index] - - def get_cluster(self, index: int) -> Optional[str]: - return self.cluster_list[index] if self.cluster_list is not None else None - - def get_instruction(self, index: int) -> Optional[str]: - return self.instruction_list[index] if self.instruction_list is not None else None - - @staticmethod - def get_namespace_list_from_args( - args: argparse.Namespace, - ) -> list[str]: - """Get a list of namespaces based on the arguments""" - if args.namespace_list: - return args.namespace_list - - return [ - f"{args.namespace_prefix}-{i}" - for i in range(args.start_index, args.start_index + args.num_nodes) - ] - - @staticmethod - def get_context_list_from_args( - args: argparse.Namespace, - ) -> list[str]: - """Get a list of contexts based on the arguments""" - if args.cluster_list: - return args.cluster_list - - if args.cluster_prefix is None: - return None - - return [ - f"{args.cluster_prefix}-{i}" - for i in range(args.start_index, args.start_index + args.num_nodes) - ] - - def update_config_and_restart_nodes( config_overrides: dict[str, Any], namespace_and_instruction_args: NamespaceAndInstructionArgs, service: Service, - restart_strategy: RestartStrategy, + restarter: ServiceRestarter, ) -> None: assert config_overrides is not None, "config_overrides must be provided" assert namespace_and_instruction_args.namespace_list is not None, "namespaces must be provided" @@ -604,28 +691,11 @@ def update_config_and_restart_nodes( namespace_and_instruction_args.get_cluster(index), ) - if restart_strategy != RestartStrategy.NO_RESTART: - for index, config in enumerate(configs): - restart_pod( - namespace_and_instruction_args.get_namespace(index), - service, - index, - namespace_and_instruction_args.get_cluster(index), - ) - instructions = namespace_and_instruction_args.get_instruction(index) - print_colored( - f"Restarted pod.\n{instructions if instructions is not None else ''} ", - Colors.YELLOW, - ) - if restart_strategy == RestartStrategy.ONE_BY_ONE: - # Don't ask in the case of the last job. - if index != len(configs) - 1 and not wait_until_y_or_n( - f"Do you want to restart the next pod?" - ): - print_colored("\nAborting restart process.") - return - print_colored("\nAll pods have been successfully restarted!", Colors.GREEN) - else: - print_colored("\nSkipping pod restart.") + for index, config in enumerate(configs): + if not restarter.restart_service(index): + print_colored("\nAborting restart process.") + sys.exit(1) + + print_colored("\nAll pods have been successfully restarted!", Colors.GREEN) print("\nOperation completed successfully!") From 8b2e64bd902416356a0bee9e3e931a1bfeedfb5c Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Sun, 2 Nov 2025 14:04:02 +0200 Subject: [PATCH 230/313] apollo_consensus: extract consensus_config fixture (#9892) --- Cargo.lock | 1 + crates/apollo_consensus/Cargo.toml | 1 + crates/apollo_consensus/src/manager_test.rs | 98 +++++++-------------- 3 files changed, 34 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8a8fd02070..1774be624d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1178,6 +1178,7 @@ dependencies = [ "lru 0.12.5", "mockall", "prost", + "rstest", "serde", "starknet-types-core", "starknet_api", diff --git a/crates/apollo_consensus/Cargo.toml b/crates/apollo_consensus/Cargo.toml index da1559471e2..1dd050bd263 100644 --- a/crates/apollo_consensus/Cargo.toml +++ b/crates/apollo_consensus/Cargo.toml @@ -40,6 +40,7 @@ apollo_storage = { workspace = true, features = ["testing"] } apollo_test_utils.workspace = true enum-as-inner.workspace = true mockall.workspace = true +rstest.workspace = true test-case.workspace = true [lints] diff --git a/crates/apollo_consensus/src/manager_test.rs b/crates/apollo_consensus/src/manager_test.rs index 27ea2f22943..3b646efbd5a 100644 --- a/crates/apollo_consensus/src/manager_test.rs +++ b/crates/apollo_consensus/src/manager_test.rs @@ -1,4 +1,3 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::time::Duration; use std::vec; @@ -21,6 +20,7 @@ use apollo_test_utils::{get_rng, GetTestInstance}; use futures::channel::{mpsc, oneshot}; use futures::{FutureExt, SinkExt}; use lazy_static::lazy_static; +use rstest::{fixture, rstest}; use starknet_api::block::BlockNumber; use starknet_types_core::felt::Felt; @@ -45,6 +45,18 @@ lazy_static! { const CHANNEL_SIZE: usize = 10; const SYNC_RETRY_INTERVAL: Duration = Duration::from_millis(100); +#[fixture] +fn consensus_config() -> ConsensusConfig { + ConsensusConfig::from_parts( + ConsensusDynamicConfig { + validator_id: *VALIDATOR_ID, + timeouts: TIMEOUTS.clone(), + sync_retry_interval: SYNC_RETRY_INTERVAL, + }, + ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, + ) +} + async fn send(sender: &mut MockBroadcastedMessagesSender, msg: Vote) { let broadcasted_message_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); @@ -80,8 +92,9 @@ fn assert_decision(res: RunHeightRes, id: Felt) { } } +#[rstest] #[tokio::test] -async fn manager_multiple_heights_unordered() { +async fn manager_multiple_heights_unordered(consensus_config: ConsensusConfig) { let TestSubscriberChannels { mock_network, subscriber_channels } = mock_register_broadcast_topic().unwrap(); let mut sender = mock_network.broadcasted_messages_sender; @@ -115,15 +128,6 @@ async fn manager_multiple_heights_unordered() { context.expect_set_height_and_round().returning(move |_, _| ()); context.expect_broadcast().returning(move |_| Ok(())); - // TODO(Asmaa): Extract to a #[fixture] - let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { - validator_id: *VALIDATOR_ID, - timeouts: TIMEOUTS.clone(), - sync_retry_interval: SYNC_RETRY_INTERVAL, - }, - ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, - ); let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let mut subscriber_channels = subscriber_channels.into(); let decision = manager @@ -153,8 +157,9 @@ async fn manager_multiple_heights_unordered() { assert_decision(decision, Felt::TWO); } +#[rstest] #[tokio::test] -async fn run_consensus_sync() { +async fn run_consensus_sync(consensus_config: ConsensusConfig) { // Set expectations. let mut context = MockTestContext::new(); let (decision_tx, decision_rx) = oneshot::channel(); @@ -191,14 +196,6 @@ async fn run_consensus_sync() { let mut network_sender = mock_network.broadcasted_messages_sender; send(&mut network_sender, prevote(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; send(&mut network_sender, precommit(Some(Felt::TWO), 2, 0, *PROPOSER_ID)).await; - let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { - validator_id: *VALIDATOR_ID, - timeouts: TIMEOUTS.clone(), - sync_retry_interval: SYNC_RETRY_INTERVAL, - }, - ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, - ); let run_consensus_args = RunConsensusArguments { consensus_config, start_active_height: BlockNumber(1), @@ -221,8 +218,9 @@ async fn run_consensus_sync() { decision_rx.await.unwrap(); } +#[rstest] #[tokio::test] -async fn test_timeouts() { +async fn test_timeouts(consensus_config: ConsensusConfig) { let TestSubscriberChannels { mock_network, subscriber_channels } = mock_register_broadcast_topic().unwrap(); let mut sender = mock_network.broadcasted_messages_sender; @@ -261,14 +259,7 @@ async fn test_timeouts() { }); context.expect_broadcast().returning(move |_| Ok(())); - let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { - validator_id: *VALIDATOR_ID, - timeouts: TIMEOUTS.clone(), - sync_retry_interval: SYNC_RETRY_INTERVAL, - }, - ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, - ); + // Ensure our validator id matches the expectation in the broadcast assertion. let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let manager_handle = tokio::spawn(async move { let decision = manager @@ -302,8 +293,9 @@ async fn test_timeouts() { manager_handle.await.unwrap(); } +#[rstest] #[tokio::test] -async fn timely_message_handling() { +async fn timely_message_handling(consensus_config: ConsensusConfig) { // TODO(matan): Make run_height more generic so don't need mock network? // Check that, even when sync is immediately ready, consensus still handles queued messages. let mut context = MockTestContext::new(); @@ -325,14 +317,6 @@ async fn timely_message_handling() { // Fill up the buffer. while vote_sender.send((vote.clone(), metadata.clone())).now_or_never().is_some() {} - let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { - validator_id: *VALIDATOR_ID, - timeouts: TIMEOUTS.clone(), - sync_retry_interval: SYNC_RETRY_INTERVAL, - }, - ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, - ); let mut manager = MultiHeightManager::new(consensus_config, QuorumType::Byzantine); let res = manager .run_height( @@ -351,8 +335,11 @@ async fn timely_message_handling() { assert!(vote_sender.send((vote.clone(), metadata.clone())).now_or_never().is_some()); } +#[rstest] #[tokio::test] -async fn run_consensus_dynamic_client_updates_validator_between_heights() { +async fn run_consensus_dynamic_client_updates_validator_between_heights( + consensus_config: ConsensusConfig, +) { let TestSubscriberChannels { mock_network, subscriber_channels } = mock_register_broadcast_topic().unwrap(); // Keep a handle to the vote sender so the paired receiver stays alive. @@ -395,35 +382,14 @@ async fn run_consensus_dynamic_client_updates_validator_between_heights() { }) .times(1); - // Dynamic client mock: H1 -> VALIDATOR_ID, H2 -> PROPOSER_ID + // Dynamic client mock: H1 -> VALIDATOR_ID, H2 -> PROPOSER_ID (order is important) let mut mock_client = MockConfigManagerClient::new(); - let call_count = Arc::new(AtomicUsize::new(0)); - let call_count_clone = Arc::clone(&call_count); - mock_client.expect_get_consensus_dynamic_config().times(2).returning(move || { - let n = call_count_clone.fetch_add(1, Ordering::SeqCst); - if n == 0 { - Ok(apollo_consensus_config::config::ConsensusDynamicConfig { - validator_id: *VALIDATOR_ID, - timeouts: TIMEOUTS.clone(), - sync_retry_interval: SYNC_RETRY_INTERVAL, - }) - } else { - Ok(apollo_consensus_config::config::ConsensusDynamicConfig { - validator_id: *PROPOSER_ID, - timeouts: TIMEOUTS.clone(), - sync_retry_interval: SYNC_RETRY_INTERVAL, - }) - } - }); + let validator_config = consensus_config.dynamic_config.clone(); + let proposer_config = + ConsensusDynamicConfig { validator_id: *PROPOSER_ID, ..validator_config.clone() }; + mock_client.expect_get_consensus_dynamic_config().times(1).return_const(Ok(validator_config)); + mock_client.expect_get_consensus_dynamic_config().times(1).return_const(Ok(proposer_config)); - let consensus_config = ConsensusConfig::from_parts( - ConsensusDynamicConfig { - validator_id: *VALIDATOR_ID, - timeouts: TIMEOUTS.clone(), - sync_retry_interval: SYNC_RETRY_INTERVAL, - }, - ConsensusStaticConfig { startup_delay: Duration::ZERO, ..Default::default() }, - ); let run_consensus_args = RunConsensusArguments { start_active_height: BlockNumber(1), start_observe_height: BlockNumber(1), From 1938d80c526a77c66ed740278dcccdefe05f8f9e Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Sun, 2 Nov 2025 14:10:17 +0200 Subject: [PATCH 231/313] apollo_dashboard: use query_builder increase fn in panels (#9866) --- crates/apollo_dashboard/src/dashboard.rs | 7 +-- crates/apollo_dashboard/src/lib.rs | 2 - crates/apollo_dashboard/src/panels/batcher.rs | 26 +++++----- .../apollo_dashboard/src/panels/consensus.rs | 48 +++++++------------ .../src/panels/http_server.rs | 11 +++-- .../src/panels/l1_gas_price.rs | 17 +++---- .../src/panels/l1_provider.rs | 10 ++-- crates/apollo_dashboard/src/panels/mempool.rs | 3 +- 8 files changed, 51 insertions(+), 73 deletions(-) diff --git a/crates/apollo_dashboard/src/dashboard.rs b/crates/apollo_dashboard/src/dashboard.rs index 76979e1cb35..5f2fa641d9a 100644 --- a/crates/apollo_dashboard/src/dashboard.rs +++ b/crates/apollo_dashboard/src/dashboard.rs @@ -18,6 +18,8 @@ use serde::ser::{SerializeMap, SerializeStruct}; use serde::{Serialize, Serializer}; use serde_with::skip_serializing_none; +use crate::query_builder; + #[cfg(test)] #[path = "dashboard_test.rs"] mod dashboard_test; @@ -311,12 +313,11 @@ impl Panel { denominator_parts: &[&MetricCounter], duration: &str, ) -> Self { - let numerator_expr = - format!("increase({}[{}])", numerator.get_name_with_filter(), duration); + let numerator_expr = query_builder::increase(numerator, duration); let denominator_expr = denominator_parts .iter() - .map(|m| format!("increase({}[{}])", m.get_name_with_filter(), duration)) + .map(|m| query_builder::increase(*m, duration)) .collect::>() .join(" + "); diff --git a/crates/apollo_dashboard/src/lib.rs b/crates/apollo_dashboard/src/lib.rs index d6a12909c72..ba53c0fb16a 100644 --- a/crates/apollo_dashboard/src/lib.rs +++ b/crates/apollo_dashboard/src/lib.rs @@ -7,6 +7,4 @@ pub mod dashboard_definitions; mod metric_definitions_test; mod panels; -// TODO(MatanL): Remove cfg(test) when used -#[cfg(test)] mod query_builder; diff --git a/crates/apollo_dashboard/src/panels/batcher.rs b/crates/apollo_dashboard/src/panels/batcher.rs index 1f38e516211..412917c8c2a 100644 --- a/crates/apollo_dashboard/src/panels/batcher.rs +++ b/crates/apollo_dashboard/src/panels/batcher.rs @@ -15,12 +15,13 @@ use apollo_consensus_orchestrator::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; +use crate::query_builder; fn get_panel_validator_wasted_txs() -> Panel { Panel::new( "Proposal Validation: Wasted TXs", "Number of txs executed by the validator but excluded from the block (10m window)", - format!("increase({}[10m])", VALIDATOR_WASTED_TXS.get_name_with_filter()), + query_builder::increase(&VALIDATOR_WASTED_TXS, "10m"), PanelType::TimeSeries, ) .with_log_query("Finished building block as validator. Started executing") @@ -30,7 +31,7 @@ fn get_panel_proposer_deferred_txs() -> Panel { Panel::new( "Proposal Build: Deferred TXs", "Number of txs started execution by the proposer but excluded from the block (10m window)", - format!("increase({}[10m])", PROPOSER_DEFERRED_TXS.get_name_with_filter()), + query_builder::increase(&PROPOSER_DEFERRED_TXS, "10m"), PanelType::TimeSeries, ) .with_log_query("Finished building block as proposer. Started executing") @@ -47,24 +48,21 @@ fn get_panel_storage_height() -> Panel { } fn get_panel_rejection_reverted_ratio() -> Panel { + let rejected_txs_expr = query_builder::increase(&REJECTED_TRANSACTIONS, "10m"); + let reverted_txs_expr = query_builder::increase(&REVERTED_TRANSACTIONS, "10m"); + let denominator_expr = format!( - "(increase({}[10m]) + increase({}[10m]) + increase({}[10m]))", - REJECTED_TRANSACTIONS.get_name_with_filter(), - REVERTED_TRANSACTIONS.get_name_with_filter(), - BATCHED_TRANSACTIONS.get_name_with_filter(), + "({} + {} + {})", + rejected_txs_expr, + reverted_txs_expr, + query_builder::increase(&BATCHED_TRANSACTIONS, "10m"), ); Panel::new( "Rejected / Reverted TXs Ratio", "Ratio of rejected / reverted transactions out of all processed txs (10m window)", vec![ - format!( - "increase({}[10m]) / {denominator_expr}", - REJECTED_TRANSACTIONS.get_name_with_filter(), - ), - format!( - "increase({}[10m]) / {denominator_expr}", - REVERTED_TRANSACTIONS.get_name_with_filter(), - ), + format!("{rejected_txs_expr} / {denominator_expr}"), + format!("{reverted_txs_expr} / {denominator_expr}"), ], PanelType::TimeSeries, ) diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index a4f56f05845..6bc7b1a8a25 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -46,6 +46,7 @@ use apollo_network::network_manager::metrics::{ use apollo_state_sync_metrics::metrics::STATE_SYNC_CLASS_MANAGER_MARKER; use crate::dashboard::{Panel, PanelType, Row, Unit}; +use crate::query_builder; // The key events that are relevant to the consensus panel. const CONSENSUS_KEY_EVENTS_LOG_QUERY: &str = @@ -96,7 +97,7 @@ pub(crate) fn get_panel_consensus_round_advanced() -> Panel { "Consensus Round Advanced", "The number of times the consensus round advanced (counter is increased whenever round > \ 0) (10m window)", - format!("increase({}[10m])", CONSENSUS_ROUND_ADVANCES.get_name_with_filter()), + query_builder::increase(&CONSENSUS_ROUND_ADVANCES, "10m"), PanelType::TimeSeries, ) .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") @@ -131,10 +132,7 @@ fn get_panel_consensus_decisions_reached_by_consensus() -> Panel { Panel::new( "Decisions Reached By Consensus", "The number of decisions reached by way of consensus (10m window)", - format!( - "increase({}[10m])", - CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS.get_name_with_filter() - ), + query_builder::increase(&CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, "10m"), PanelType::TimeSeries, ) .with_log_query("DECISION_REACHED: Decision reached for round") @@ -145,7 +143,7 @@ fn get_panel_consensus_decisions_reached_by_sync() -> Panel { Panel::new( "Decisions Reached By Sync", "The number of decisions reached by way of sync (10m window)", - format!("increase({}[10m])", CONSENSUS_DECISIONS_REACHED_BY_SYNC.get_name_with_filter()), + query_builder::increase(&CONSENSUS_DECISIONS_REACHED_BY_SYNC, "10m"), PanelType::TimeSeries, ) .with_log_query("Decision learned via sync protocol.") @@ -156,7 +154,7 @@ fn get_panel_consensus_proposals_received() -> Panel { Panel::new( "Proposal Validation: Number of Received Proposals", "The number of proposals received from the network (10m window)", - format!("increase({}[10m])", CONSENSUS_PROPOSALS_RECEIVED.get_name_with_filter()), + query_builder::increase(&CONSENSUS_PROPOSALS_RECEIVED, "10m"), PanelType::TimeSeries, ) } @@ -165,7 +163,7 @@ fn get_panel_consensus_proposals_validated() -> Panel { Panel::new( "Proposal Validation: Number of Validated Proposals", "The number of proposals received and validated successfully (10m window)", - format!("increase({}[10m])", CONSENSUS_PROPOSALS_VALIDATED.get_name_with_filter()), + query_builder::increase(&CONSENSUS_PROPOSALS_VALIDATED, "10m"), PanelType::TimeSeries, ) .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") @@ -176,7 +174,7 @@ fn get_panel_consensus_proposals_invalid() -> Panel { Panel::new( "Proposal Validation: Number of Invalid Proposals", "The number of proposals received and failed validation (10m window)", - format!("increase({}[10m])", CONSENSUS_PROPOSALS_INVALID.get_name_with_filter()), + query_builder::increase(&CONSENSUS_PROPOSALS_INVALID, "10m"), PanelType::TimeSeries, ) .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") @@ -202,7 +200,7 @@ fn get_panel_consensus_build_proposal_total() -> Panel { Panel::new( "Proposal Build: Number of Proposals Started", "The number of proposals that started building (10m window)", - format!("increase({}[10m])", CONSENSUS_BUILD_PROPOSAL_TOTAL.get_name_with_filter()), + query_builder::increase(&CONSENSUS_BUILD_PROPOSAL_TOTAL, "10m"), PanelType::TimeSeries, ) } @@ -211,7 +209,7 @@ fn get_panel_consensus_build_proposal_failed() -> Panel { Panel::new( "Proposal Build: Number of Proposals Failed", "The number of proposals that failed to be built (10m window)", - format!("increase({}[10m])", CONSENSUS_BUILD_PROPOSAL_FAILED.get_name_with_filter()), + query_builder::increase(&CONSENSUS_BUILD_PROPOSAL_FAILED, "10m"), PanelType::TimeSeries, ) } @@ -290,7 +288,7 @@ fn get_panel_cende_write_blob_success() -> Panel { Panel::new( "Write Blob Success", "The number of successful blob writes to Cende (10m window)", - format!("increase({}[10m])", CENDE_WRITE_BLOB_SUCCESS.get_name_with_filter()), + query_builder::increase(&CENDE_WRITE_BLOB_SUCCESS, "10m"), PanelType::TimeSeries, ) .with_log_query(query_expression) @@ -315,7 +313,7 @@ fn get_panel_cende_write_preconfirmed_block() -> Panel { "Write Preconfirmed Block Success", "The number of successful writes to Cende for preconfirmed blocks (10m window). Each \ preconfirmed block may involve multiple writes.", - format!("increase({}[10m])", PRECONFIRMED_BLOCK_WRITTEN.get_name_with_filter()), + query_builder::increase(&PRECONFIRMED_BLOCK_WRITTEN, "10m"), PanelType::TimeSeries, ) .with_log_query("write_pre_confirmed_block request succeeded.") @@ -335,7 +333,7 @@ fn get_panel_consensus_votes_num_sent_messages() -> Panel { "Consensus Votes Number of Sent Messages", "The increase in the number of vote messages sent by consensus p2p (over the selected \ time range)", - format!("increase({}[$__range])", CONSENSUS_VOTES_NUM_SENT_MESSAGES.get_name_with_filter()), + query_builder::increase(&CONSENSUS_VOTES_NUM_SENT_MESSAGES, "$__range"), PanelType::Stat, ) } @@ -345,10 +343,7 @@ fn get_panel_consensus_votes_num_received_messages() -> Panel { "Consensus Votes Number of Received Messages", "The increase in the number of vote messages received by consensus p2p (over the selected \ time range)", - format!( - "increase({}[$__range])", - CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES.get_name_with_filter() - ), + query_builder::increase(&CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, "$__range"), PanelType::Stat, ) } @@ -358,10 +353,7 @@ fn get_panel_consensus_proposals_num_sent_messages() -> Panel { "Consensus Proposals Number of Sent Messages", "The increase in the number of proposal messages sent by consensus p2p (over the selected \ time range)", - format!( - "increase({}[$__range])", - CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES.get_name_with_filter() - ), + query_builder::increase(&CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, "$__range"), PanelType::Stat, ) } @@ -371,10 +363,7 @@ fn get_panel_consensus_proposals_num_received_messages() -> Panel { "Consensus Proposals Number of Received Messages", "The increase in the number of proposal messages received by consensus p2p (over the \ selected time range)", - format!( - "increase({}[$__range])", - CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES.get_name_with_filter() - ), + query_builder::increase(&CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, "$__range"), PanelType::Stat, ) } @@ -383,7 +372,7 @@ fn get_panel_consensus_conflicting_votes() -> Panel { Panel::new( "Consensus Conflicting Votes", "The increase in the number of conflicting votes (over the selected time range)", - format!("increase({}[$__range])", CONSENSUS_CONFLICTING_VOTES.get_name_with_filter()), + query_builder::increase(&CONSENSUS_CONFLICTING_VOTES, "$__range"), PanelType::Stat, ) } @@ -432,10 +421,7 @@ fn get_panel_consensus_decisions_reached_as_proposer() -> Panel { Panel::new( "Consensus Decisions Reached As Proposer", "The number of rounds with decision reached where this node is the proposer (10m window)", - format!( - "increase({}[10m])", - CONSENSUS_DECISIONS_REACHED_AS_PROPOSER.get_name_with_filter() - ), + query_builder::increase(&CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, "10m"), PanelType::TimeSeries, ) .with_log_query("\"Building proposal\" OR \"BATCHER_FIN_PROPOSER\"") diff --git a/crates/apollo_dashboard/src/panels/http_server.rs b/crates/apollo_dashboard/src/panels/http_server.rs index 8b028c85da1..e2060765629 100644 --- a/crates/apollo_dashboard/src/panels/http_server.rs +++ b/crates/apollo_dashboard/src/panels/http_server.rs @@ -9,25 +9,26 @@ use apollo_http_server::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; +use crate::query_builder; fn get_panel_total_transactions_received() -> Panel { Panel::new( "Transactions Received", "Number of transactions received (10m window)", - format!("increase({}[10m])", ADDED_TRANSACTIONS_TOTAL.get_name_with_filter()), + query_builder::increase(&ADDED_TRANSACTIONS_TOTAL, "10m"), PanelType::TimeSeries, ) .with_log_query("\"ADD_TX_START\"") } fn get_panel_transaction_success_rate() -> Panel { + // TODO(MatanL): use Panel::ratio_time_series Panel::new( "Transaction Success Rate", "The ratio of transactions successfully added to the gateway (10m window)", format!( - "increase({}[10m]) / (increase({}[10m]) + increase({}[10m]))", - ADDED_TRANSACTIONS_SUCCESS.get_name_with_filter(), - ADDED_TRANSACTIONS_SUCCESS.get_name_with_filter(), - ADDED_TRANSACTIONS_FAILURE.get_name_with_filter(), + "{s} / ({s} + {f})", + s = query_builder::increase(&ADDED_TRANSACTIONS_SUCCESS, "10m"), + f = query_builder::increase(&ADDED_TRANSACTIONS_FAILURE, "10m"), ), PanelType::TimeSeries, ) diff --git a/crates/apollo_dashboard/src/panels/l1_gas_price.rs b/crates/apollo_dashboard/src/panels/l1_gas_price.rs index aca4547efdf..1b232bc0fad 100644 --- a/crates/apollo_dashboard/src/panels/l1_gas_price.rs +++ b/crates/apollo_dashboard/src/panels/l1_gas_price.rs @@ -14,12 +14,13 @@ use apollo_l1_gas_price_types::DEFAULT_ETH_TO_FRI_RATE; use apollo_metrics::MetricCommon; use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; +use crate::query_builder; fn get_panel_eth_to_strk_error_count() -> Panel { Panel::new( "ETH→STRK Rate Query Error Count", "The number of times the ETH→STRK rate query failed (10m window)", - format!("increase({}[10m])", ETH_TO_STRK_ERROR_COUNT.get_name_with_filter()), + query_builder::increase(Ð_TO_STRK_ERROR_COUNT, "10m"), PanelType::TimeSeries, ) } @@ -61,10 +62,7 @@ fn get_panel_l1_gas_price_provider_insufficient_history() -> Panel { "L1 Gas Price Provider Insufficient History", "The number of times the L1 gas price provider calculated an average with too few blocks \ (10m window)", - format!( - "increase({}[10m])", - L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY.get_name_with_filter() - ), + query_builder::increase(&L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, "10m"), PanelType::TimeSeries, ) .with_log_query("Not enough history to calculate the mean gas price.") @@ -75,7 +73,7 @@ fn get_panel_l1_gas_price_scraper_success_count() -> Panel { "L1 Gas Price Scraper Success Count", "The number of times the L1 gas price scraper successfully scraped and updated gas prices \ (10m window)", - format!("increase({}[10m])", L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT.get_name_with_filter()), + query_builder::increase(&L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, "10m"), PanelType::TimeSeries, ) } @@ -85,10 +83,7 @@ fn get_panel_l1_gas_price_scraper_baselayer_error_count() -> Panel { "L1 Gas Price Scraper Base Layer Error Count", "The number of times the L1 gas price scraper encountered an error while scraping the \ base layer (10m window)", - format!( - "increase({}[10m])", - L1_GAS_PRICE_SCRAPER_BASELAYER_ERROR_COUNT.get_name_with_filter() - ), + query_builder::increase(&L1_GAS_PRICE_SCRAPER_BASELAYER_ERROR_COUNT, "10m"), PanelType::TimeSeries, ) } @@ -98,7 +93,7 @@ fn get_panel_l1_gas_price_scraper_reorg_detected() -> Panel { "L1 Gas Price Scraper Reorg Detected", "The number of times the L1 gas price scraper detected a reorganization in the base layer \ (10m window)", - format!("increase({}[10m])", L1_GAS_PRICE_SCRAPER_REORG_DETECTED.get_name_with_filter()), + query_builder::increase(&L1_GAS_PRICE_SCRAPER_REORG_DETECTED, "10m"), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/l1_provider.rs b/crates/apollo_dashboard/src/panels/l1_provider.rs index 82a7eaa5f2c..399f2464bf6 100644 --- a/crates/apollo_dashboard/src/panels/l1_provider.rs +++ b/crates/apollo_dashboard/src/panels/l1_provider.rs @@ -6,13 +6,14 @@ use apollo_l1_provider::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; +use crate::query_builder; fn get_panel_l1_message_scraper_success_count() -> Panel { Panel::new( "L1 Message Scraper Success Count", "The increase in the number of times the L1 message scraper successfully scraped messages \ (10m window)", - format!("increase({}[10m])", L1_MESSAGE_SCRAPER_SUCCESS_COUNT.get_name_with_filter()), + query_builder::increase(&L1_MESSAGE_SCRAPER_SUCCESS_COUNT, "10m"), PanelType::TimeSeries, ) } @@ -21,10 +22,7 @@ fn get_panel_l1_message_scraper_baselayer_error_count() -> Panel { "L1 Message Scraper Base Layer Error Count", "The increase in the number of times the L1 message scraper encountered an error while \ scraping the base layer (10m window)", - format!( - "increase({}[10m])", - L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT.get_name_with_filter() - ), + query_builder::increase(&L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT, "10m"), PanelType::TimeSeries, ) } @@ -32,7 +30,7 @@ fn get_panel_l1_message_scraper_reorg_detected() -> Panel { Panel::new( "L1 Message Scraper Reorg Detected", "The increase in the number of times the L1 message scraper detected a reorg (12h window)", - format!("increase({}[12h])", L1_MESSAGE_SCRAPER_REORG_DETECTED.get_name_with_filter()), + query_builder::increase(&L1_MESSAGE_SCRAPER_REORG_DETECTED, "12h"), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/mempool.rs b/crates/apollo_dashboard/src/panels/mempool.rs index 269dcd285a3..3c314f187ec 100644 --- a/crates/apollo_dashboard/src/panels/mempool.rs +++ b/crates/apollo_dashboard/src/panels/mempool.rs @@ -14,6 +14,7 @@ use apollo_mempool::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; +use crate::query_builder; fn get_panel_mempool_transactions_received_rate() -> Panel { Panel::new( @@ -31,7 +32,7 @@ fn get_panel_mempool_transactions_committed() -> Panel { Panel::new( "Transactions Committed", "Number of transactions committed to a block (10m window)", - format!("increase({}[10m])", MEMPOOL_TRANSACTIONS_COMMITTED.get_name_with_filter()), + query_builder::increase(&MEMPOOL_TRANSACTIONS_COMMITTED, "10m"), PanelType::TimeSeries, ) } From dd55b92f5908438bf7c843c7b53bc771f69e9ad1 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Sun, 2 Nov 2025 14:10:24 +0200 Subject: [PATCH 232/313] apollo_deployments: move http port to be part of deployment config (#9900) --- .../resources/app_configs/http_server_config.json | 3 +-- .../resources/deployment_inputs/mainnet.json | 3 ++- .../resources/deployment_inputs/potc_mock.json | 3 ++- .../resources/deployment_inputs/sepolia_integration.json | 3 ++- .../resources/deployment_inputs/sepolia_testnet.json | 3 ++- .../resources/deployment_inputs/stress_test.json | 3 ++- .../resources/deployment_inputs/upgrade_test.json | 3 ++- .../deployments/mainnet/deployment_config_override.json | 1 + .../deployments/potc_mock/deployment_config_override.json | 1 + .../resources/deployments/replacer_deployment.json | 1 + .../sepolia_integration/deployment_config_override.json | 1 + .../sepolia_testnet/deployment_config_override.json | 1 + .../deployments/stress_test/deployment_config_override.json | 1 + .../deployments/testing/deployment_config_override.json | 1 + .../deployments/upgrade_test/deployment_config_override.json | 1 + crates/apollo_deployments/src/config_override.rs | 4 ++++ crates/apollo_deployments/src/deployment_definitions.rs | 1 + .../apollo_deployments/src/deployment_definitions/testing.rs | 2 ++ crates/apollo_deployments/src/deployments/hybrid.rs | 1 + 19 files changed, 29 insertions(+), 8 deletions(-) diff --git a/crates/apollo_deployments/resources/app_configs/http_server_config.json b/crates/apollo_deployments/resources/app_configs/http_server_config.json index b413553c006..c2a18ec0a34 100644 --- a/crates/apollo_deployments/resources/app_configs/http_server_config.json +++ b/crates/apollo_deployments/resources/app_configs/http_server_config.json @@ -1,4 +1,3 @@ { - "http_server_config.ip": "0.0.0.0", - "http_server_config.port": 8080 + "http_server_config.ip": "0.0.0.0" } diff --git a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json index 65ecae98bb3..5b83ad646bb 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json @@ -15,5 +15,6 @@ "p2p_communication_type": "External", "deployment_environment": "Mainnet", "audited_libfuncs_only": true, - "requires_k8s_service_config_params": true + "requires_k8s_service_config_params": true, + "http_server_port": 8080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json index 339c50e498b..1f1d2cd074f 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json +++ b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json @@ -40,5 +40,6 @@ "p2p_communication_type": "Internal", "deployment_environment": "PotcMock", "audited_libfuncs_only": true, - "requires_k8s_service_config_params": false + "requires_k8s_service_config_params": false, + "http_server_port": 8080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json index 5c2f6e9fcce..8de07283542 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json @@ -15,5 +15,6 @@ "p2p_communication_type": "Internal", "deployment_environment": "SepoliaIntegration", "audited_libfuncs_only": false, - "requires_k8s_service_config_params": false + "requires_k8s_service_config_params": false, + "http_server_port": 8080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json index 01f9861050d..3099b35149b 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json @@ -15,5 +15,6 @@ "p2p_communication_type": "External", "deployment_environment": "SepoliaTestnet", "audited_libfuncs_only": true, - "requires_k8s_service_config_params": true + "requires_k8s_service_config_params": true, + "http_server_port": 8080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json index 92627daa0d4..b72e9f266e7 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json @@ -15,5 +15,6 @@ "p2p_communication_type": "Internal", "deployment_environment": "StressTest", "audited_libfuncs_only": false, - "requires_k8s_service_config_params": false + "requires_k8s_service_config_params": false, + "http_server_port": 8080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json index d64ee6e6e58..bdad3f92161 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json @@ -15,5 +15,6 @@ "p2p_communication_type": "External", "deployment_environment": "UpgradeTest", "audited_libfuncs_only": false, - "requires_k8s_service_config_params": true + "requires_k8s_service_config_params": true, + "http_server_port": 8080 } diff --git a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json index 0e649748b25..272b37728b3 100644 --- a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json @@ -5,6 +5,7 @@ "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-mainnet-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-mainnet-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-mainnet-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-mainnet-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-mainnet-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-mainnet-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-mainnet-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-mainnet-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-core-service.apollo-mainnet-14.starknet.io/tcp/53080/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-core-service.apollo-mainnet-15.starknet.io/tcp/53080/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-mainnet-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-mainnet-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-mempool-service.apollo-mainnet-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-mempool-service.apollo-mainnet-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json index 3b07315977b..c89fded052d 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json @@ -5,6 +5,7 @@ "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-potc-mock-10.svc.cluster.local/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-potc-mock-11.svc.cluster.local/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-potc-mock-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-potc-mock-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-potc-mock-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-potc-mock-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", diff --git a/crates/apollo_deployments/resources/deployments/replacer_deployment.json b/crates/apollo_deployments/resources/deployments/replacer_deployment.json index 372b106ea07..e74f12abd96 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_deployment.json +++ b/crates/apollo_deployments/resources/deployments/replacer_deployment.json @@ -5,6 +5,7 @@ "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", "eth_fee_token_address": "$$$_ETH_FEE_TOKEN_ADDRESS_$$$", + "http_server_config.port": "$$$_HTTP_SERVER_CONFIG-PORT_$$$", "l1_provider_config.provider_startup_height_override": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE_$$$", "l1_provider_config.provider_startup_height_override.#is_none": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE-IS_NONE_$$$", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json index 6c94bf74b7c..d557080c9b4 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json @@ -5,6 +5,7 @@ "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json index 188ef217d3b..67b6c727ce4 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json @@ -5,6 +5,7 @@ "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-alpha-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-alpha-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-alpha-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-sepolia-alpha-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-alpha-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-alpha-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-sepolia-alpha-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-core-service.apollo-sepolia-alpha-14.starknet.io/tcp/53080/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-core-service.apollo-sepolia-alpha-15.starknet.io/tcp/53080/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-alpha-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-alpha-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-sepolia-alpha-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-alpha-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-sepolia-alpha-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-mempool-service.apollo-sepolia-alpha-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", diff --git a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json index 01e37d39e4c..8c8682849e2 100644 --- a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json @@ -5,6 +5,7 @@ "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-stresstest-dev-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-stresstest-dev-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-stresstest-dev-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x07e813ecf3e7b3e14f07bd2f68cb4a3d12110e3c75ec5a63de3d2dacf1852904", + "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-stresstest-dev-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-stresstest-dev-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-stresstest-dev-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", diff --git a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json index c978d861773..32cc705fd6f 100644 --- a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json @@ -5,6 +5,7 @@ "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, "eth_fee_token_address": "0x1001", + "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 1, "l1_provider_config.provider_startup_height_override.#is_none": false, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", diff --git a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json index 2acd0efb7c5..97fc103ebd4 100644 --- a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json @@ -5,6 +5,7 @@ "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-mainnet-test-0.sw-dev.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-mainnet-test-1.sw-dev.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-mainnet-test-2.sw-dev.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-mainnet-test-10.sw-dev.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-mainnet-test-11.sw-dev.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-mainnet-test-12.sw-dev.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x04475715fa6768670bb310eab072171856c94c1a04fa78be2370513aa2a87dc4", + "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-test-0.sw-dev.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-test-1.sw-dev.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-test-2.sw-dev.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-test-10.sw-dev.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-test-11.sw-dev.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-test-12.sw-dev.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index 88d8db2acca..6b56e3c2494 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -156,6 +156,8 @@ pub struct DeploymentConfigOverride { consensus_p2p_bootstrap_config: PeerToPeerBootstrapConfig, #[serde(flatten, with = "mempool_prefix")] mempool_p2p_bootstrap_config: PeerToPeerBootstrapConfig, + #[serde(rename = "http_server_config.port")] + http_server_config_port: u16, } impl DeploymentConfigOverride { @@ -172,6 +174,7 @@ impl DeploymentConfigOverride { consensus_p2p_bootstrap_config: PeerToPeerBootstrapConfig, mempool_p2p_bootstrap_config: PeerToPeerBootstrapConfig, sierra_compiler_config_audited_libfuncs_only: bool, + http_server_config_port: u16, ) -> Self { let ( l1_provider_config_provider_startup_height_override, @@ -194,6 +197,7 @@ impl DeploymentConfigOverride { state_sync_config: state_sync_type.get_state_sync_config(), consensus_p2p_bootstrap_config, mempool_p2p_bootstrap_config, + http_server_config_port, } } } diff --git a/crates/apollo_deployments/src/deployment_definitions.rs b/crates/apollo_deployments/src/deployment_definitions.rs index 4fc6380d8c0..8a0d9f96324 100644 --- a/crates/apollo_deployments/src/deployment_definitions.rs +++ b/crates/apollo_deployments/src/deployment_definitions.rs @@ -88,6 +88,7 @@ pub struct DeploymentInputs { pub deployment_environment: Environment, pub requires_k8s_service_config_params: bool, pub audited_libfuncs_only: bool, + pub http_server_port: u16, } impl DeploymentInputs { diff --git a/crates/apollo_deployments/src/deployment_definitions/testing.rs b/crates/apollo_deployments/src/deployment_definitions/testing.rs index 9c31be2d4dc..db925678861 100644 --- a/crates/apollo_deployments/src/deployment_definitions/testing.rs +++ b/crates/apollo_deployments/src/deployment_definitions/testing.rs @@ -1,3 +1,4 @@ +use apollo_http_server_config::config::HTTP_SERVER_PORT; use starknet_api::block::BlockNumber; use url::Url; @@ -37,6 +38,7 @@ fn testing_deployment_config_override() -> DeploymentConfigOverride { PeerToPeerBootstrapConfig::new(None), PeerToPeerBootstrapConfig::new(None), false, + HTTP_SERVER_PORT, ) } diff --git a/crates/apollo_deployments/src/deployments/hybrid.rs b/crates/apollo_deployments/src/deployments/hybrid.rs index d015e80855b..9c049e80c02 100644 --- a/crates/apollo_deployments/src/deployments/hybrid.rs +++ b/crates/apollo_deployments/src/deployments/hybrid.rs @@ -884,6 +884,7 @@ fn hybrid_deployments(inputs: &DeploymentInputs) -> Vec { consensus_p2p_bootstrap_config.clone(), mempool_p2p_bootstrap_config.clone(), inputs.audited_libfuncs_only, + inputs.http_server_port, ), &inputs.node_namespace_format, &inputs.ingress_domain, From 84102cc9987ce9b314e5ea5c9b6396ef1488b523 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Sun, 2 Nov 2025 14:41:05 +0200 Subject: [PATCH 233/313] apollo_integration_tests: remove the deprecated method on_anvil_with_wallet_and_config (#9845) --- crates/apollo_integration_tests/src/anvil_base_layer.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/apollo_integration_tests/src/anvil_base_layer.rs b/crates/apollo_integration_tests/src/anvil_base_layer.rs index c00c74a44aa..3b341e0429b 100644 --- a/crates/apollo_integration_tests/src/anvil_base_layer.rs +++ b/crates/apollo_integration_tests/src/anvil_base_layer.rs @@ -59,10 +59,8 @@ impl AnvilBaseLayer { ); } - // TODO(Arni): Remove the allow(deprecated) once we remove the deprecated function. - #[allow(deprecated)] let anvil_client = ProviderBuilder::new() - .on_anvil_with_wallet_and_config(|anvil| anvil.port(Self::DEFAULT_ANVIL_PORT)) + .connect_anvil_with_wallet_and_config(|anvil| anvil.port(Self::DEFAULT_ANVIL_PORT)) .unwrap_or_else(|error| match error { AnvilError::SpawnError(e) if e.to_string().contains("No such file or directory") => From f506dfa9e7e87645d1c7a28bf60c5dd6ad3471e9 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 2 Nov 2025 16:09:26 +0200 Subject: [PATCH 234/313] scripts: add an abstraction for updating the configs. Will be used to update configs dynamically. (#9872) --- scripts/prod/restart_all_nodes_together.py | 3 +- scripts/prod/set_node_revert_mode.py | 3 +- .../prod/update_config_and_restart_nodes.py | 6 +- .../update_config_and_restart_nodes_lib.py | 78 ++++++++++++++----- 4 files changed, 68 insertions(+), 22 deletions(-) diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_nodes_together.py index c81db16800a..b79d11249ea 100755 --- a/scripts/prod/restart_all_nodes_together.py +++ b/scripts/prod/restart_all_nodes_together.py @@ -7,6 +7,7 @@ import urllib.request from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, + ConstConfigValuesUpdater, NamespaceAndInstructionArgs, RestartStrategy, Service, @@ -137,7 +138,7 @@ def main(): ) update_config_and_restart_nodes( - config_overrides, + ConstConfigValuesUpdater(config_overrides), namespace_and_instruction_args, Service.Core, restarter, diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index 685a5bb3eb5..07c2380fcc1 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -6,6 +6,7 @@ import urllib.parse from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, + ConstConfigValuesUpdater, NamespaceAndInstructionArgs, RestartStrategy, Service, @@ -65,7 +66,7 @@ def set_revert_mode( ) update_config_and_restart_nodes( - config_overrides, + ConstConfigValuesUpdater(config_overrides), namespace_and_instruction_args, Service.Core, restarter, diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index c3f75c11943..c6e40582b7d 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -8,6 +8,7 @@ from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, Colors, + ConstConfigValuesUpdater, NamespaceAndInstructionArgs, Service, ServiceRestarter, @@ -162,7 +163,10 @@ def main(): ) update_config_and_restart_nodes( - config_overrides, namespace_and_instruction_args, args.service, restarter + ConstConfigValuesUpdater(config_overrides), + namespace_and_instruction_args, + args.service, + restarter, ) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 58205c002d4..3dbbc7d65e1 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -274,6 +274,62 @@ def get_context_list_from_args( ] +class ConfigValuesUpdater(ABC): + """Abstract class for updating configuration values for different service instances.""" + + def get_updated_config(self, orig_config_yaml: str, instance_index: int) -> str: + """Get updated configuration YAML for a specific instance. + + Args: + orig_config_yaml: Original configuration as YAML string + instance_index: Index of the instance to update configuration for + + Returns: + Updated configuration as YAML string + """ + config, config_data = parse_config_from_yaml(orig_config_yaml) + updated_config_data = self.get_updated_config_for_instance(config_data, instance_index) + return serialize_config_to_yaml(config, updated_config_data) + + @abstractmethod + def get_updated_config_for_instance( + self, config_data: dict[str, Any], instance_index: int + ) -> dict[str, Any]: + """Get updated configuration data for a specific instance. + + Args: + config_data: Current configuration data dictionary + instance_index: Index of the instance to update configuration for + + Returns: + Updated configuration data dictionary + """ + + +class ConstConfigValuesUpdater(ConfigValuesUpdater): + """Concrete implementation that applies constant configuration overrides.""" + + def __init__(self, config_overrides: dict[str, Any]): + """Initialize with configuration overrides. + + Args: + config_overrides: Dictionary of configuration keys and values to override + """ + self.config_overrides = config_overrides + + def get_updated_config_for_instance( + self, config_data: dict[str, Any], instance_index: int + ) -> dict[str, Any]: + """Apply the same configuration overrides to the config data for each instance.""" + updated_config = config_data.copy() + + for key, value in self.config_overrides.items(): + print_colored(f" Overriding config: {key} = {value}") + updated_config[key] = value + + return updated_config + + class ServiceRestarter(ABC): """Abstract class for restarting service instances.""" @@ -540,22 +596,6 @@ def represent_literal_str(dumper, data): return result -def update_config_values( - config_content: str, - config_overrides: dict[str, Any] = None, -) -> str: - """Update configuration values in the YAML content and return the updated YAML""" - # Parse the configuration - config, config_data = parse_config_from_yaml(config_content) - - for key, value in config_overrides.items(): - print_colored(f" Overriding config: {key} = {value}") - config_data[key] = value - - # Serialize back to YAML - return serialize_config_to_yaml(config, config_data) - - def normalize_config(config_content: str) -> str: """Normalize configuration by parsing and re-serializing without changes. @@ -632,12 +672,12 @@ def apply_configmap( def update_config_and_restart_nodes( - config_overrides: dict[str, Any], + config_values_updater: ConfigValuesUpdater, namespace_and_instruction_args: NamespaceAndInstructionArgs, service: Service, restarter: ServiceRestarter, ) -> None: - assert config_overrides is not None, "config_overrides must be provided" + assert config_values_updater is not None, "config_values_updater must be provided" assert namespace_and_instruction_args.namespace_list is not None, "namespaces must be provided" if not namespace_and_instruction_args.cluster_list: @@ -668,7 +708,7 @@ def update_config_and_restart_nodes( ) # Update config - updated_config = update_config_values(original_config, config_overrides) + updated_config = config_values_updater.get_updated_config(original_config, index) # Store configs configs.append({"original": original_config, "updated": updated_config}) From 89d1ee1ac6f186bb1f6484ade3686ee1b2dab340 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 2 Nov 2025 16:10:08 +0200 Subject: [PATCH 235/313] scripts: A class which gates progress on metrics satisifying a condition (#9799) --- .../update_config_and_restart_nodes_lib.py | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 3dbbc7d65e1..307b680ae18 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -6,14 +6,18 @@ import sys from abc import ABC, abstractmethod from enum import Enum +from time import sleep from typing import Any, Callable, Optional +import signal +import socket import tempfile import urllib.error import urllib.parse import urllib.request import yaml from difflib import unified_diff +from prometheus_client.parser import text_string_to_metric_families class Colors(Enum): @@ -212,6 +216,161 @@ def validate_arguments(args: argparse.Namespace) -> None: sys.exit(1) +class MetricConditionGater: + """Gates progress on a metric satisfying a condition. + + This class was meant to be used with counter/gauge metrics. It may not work properly with histogram metrics. + """ + + class MetricCondition: + def __init__( + self, + value_condition: Callable[[Any], bool], + condition_description: Optional[str] = None, + ): + self.value_condition = value_condition + self.condition_description = condition_description + + def __init__( + self, + metric_name: str, + namespace: str, + cluster: Optional[str], + pod: str, + metrics_port: int, + metric_value_condition: "MetricConditionGater.MetricCondition", + refresh_interval_seconds: int = 3, + ): + self.metric_name = metric_name + self.local_port = self._get_free_port() + self.namespace = namespace + self.cluster = cluster + self.pod = pod + self.metrics_port = metrics_port + self.metric_value_condition = metric_value_condition + self.refresh_interval_seconds = refresh_interval_seconds + + @staticmethod + def _get_free_port(): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(("", 0)) + return s.getsockname()[1] + + def _get_metrics_raw_string(self) -> str: + while True: + try: + with urllib.request.urlopen( + f"http://localhost:{self.local_port}/monitoring/metrics" + ) as response: + if response.status == 200: + return response.read().decode("utf-8") + else: + print_colored( + f"Failed to get metrics for pod {self.pod}: {response.status}" + ) + except urllib.error.URLError as e: + print_colored(f"Failed to get metrics for pod {self.pod}: {e}") + print_colored( + f"Waiting {self.refresh_interval_seconds} seconds to retry getting metrics...", + Colors.YELLOW, + ) + sleep(self.refresh_interval_seconds) + + def _poll_until_condition_met(self): + """Poll metrics until the condition is met for the metric.""" + condition_description = ( + f"({self.metric_value_condition.condition_description}) " + if self.metric_value_condition.condition_description is not None + else "" + ) + + while True: + metrics = self._get_metrics_raw_string() + assert metrics is not None, f"Failed to get metrics from for pod {self.pod}" + + metric_families = text_string_to_metric_families(metrics) + val = None + for metric_family in metric_families: + if metric_family.name == self.metric_name: + if len(metric_family.samples) > 1: + print_error( + f"Multiple samples found for metric {self.metric_name}. Using the first one.", + ) + val = metric_family.samples[0].value + break + + if val is None: + print_colored( + f"Metric '{self.metric_name}' not found in pod {self.pod}. Assuming the node is not ready." + ) + elif self.metric_value_condition.value_condition(val): + print_colored( + f"Metric {self.metric_name} condition {condition_description}met (value={val})." + ) + return + else: + print_colored( + f"Metric {self.metric_name} condition {condition_description}not met (value={val}). Continuing to wait." + ) + + sleep(self.refresh_interval_seconds) + + @staticmethod + def _terminate_port_forward_process(pf_process: subprocess.Popen): + if pf_process and pf_process.poll() is None: + print_colored(f"Terminating kubectl port-forward process (PID: {pf_process.pid})") + pf_process.terminate() + try: + pf_process.wait(timeout=5) + except subprocess.TimeoutExpired: + print_colored("Force killing kubectl port-forward process") + pf_process.kill() + pf_process.wait() + + def gate(self): + """Wait until the nodes metrics satisfy the condition.""" + # This method: + # 1. Starts kubectl port forwarding to the node and keep it running in the background so we can access the metrics. + # 2. Calls _poll_until_condition_met. + # 3. Terminates the port forwarding process when done or when interrupted. + cmd = [ + "kubectl", + "port-forward", + f"pod/{self.pod}", + f"{self.local_port}:{self.metrics_port}", + ] + cmd.extend(get_namespace_args(self.namespace, self.cluster)) + + pf_process = None + + try: + pf_process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + print("Waiting for forwarding to start") + # Give the forwarding time to start. + # TODO(guy.f): Consider poll until the forwarding is ready if we see any issues. + sleep(3) + assert ( + pf_process.poll() is None + ), f"Port forwarding process exited with code {pf_process.returncode}" + + print( + f"Forwarding started (from local port {self.local_port} to {self.pod}:{self.metrics_port})" + ) + + # Set up signal handler to ensure forwarding subprocess is terminated on interruption + def signal_handler(signum, frame): + self._terminate_port_forward_process(pf_process) + sys.exit(0) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + self._poll_until_condition_met() + + finally: + self._terminate_port_forward_process(pf_process) + + class NamespaceAndInstructionArgs: def __init__( self, From 86e9c5a6a2224f5079a98da5f1f4ca96b90a7734 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 2 Nov 2025 17:11:58 +0200 Subject: [PATCH 236/313] scripts: On restart, update the node ids (flag protected) (#9873) --- scripts/prod/restart_all_nodes_together.py | 28 +++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_nodes_together.py index b79d11249ea..075182f7f29 100755 --- a/scripts/prod/restart_all_nodes_together.py +++ b/scripts/prod/restart_all_nodes_together.py @@ -48,6 +48,20 @@ def get_validator_id(namespace: str, context: Optional[str]) -> str: return config_data["validator_id"] +class NodeValidatorIdCompositeUpdater(ConstConfigValuesUpdater): + def __init__(self, config_overrides: dict[str, any], validator_id_start_from: int): + super().__init__(config_overrides) + self.validator_id_start_from = validator_id_start_from + + def get_updated_config_for_instance( + self, config_data: dict[str, any], instance_index: int + ) -> dict[str, any]: + updated_config = super().get_updated_config_for_instance(config_data, instance_index) + validator_id_as_hex = hex(self.validator_id_start_from + instance_index) + updated_config["validator_id"] = validator_id_as_hex + return updated_config + + def main(): usage_example = """ Examples: @@ -94,6 +108,12 @@ def main(): help="The name of the project to get logs from.", ) + args_builder.add_argument( + "--validator-id-start-from", + type=int, + help="If set, also update the validator ID config to this value + index of the instance being restarted. Value is in decimal format.", + ) + args = args_builder.build() # Get current block number from feeder URL @@ -137,8 +157,14 @@ def main(): Service.Core, ) + updater = ( + NodeValidatorIdCompositeUpdater(config_overrides, args.validator_id_start_from) + if args.validator_id_start_from + else ConstConfigValuesUpdater(config_overrides) + ) + update_config_and_restart_nodes( - ConstConfigValuesUpdater(config_overrides), + updater, namespace_and_instruction_args, Service.Core, restarter, From 10988ed7fae3f5d467b55ae2e2541dac6105b9fc Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 2 Nov 2025 17:13:11 +0200 Subject: [PATCH 237/313] scripts: only use all at once restart for set revert mode. (#9878) --- scripts/prod/set_node_revert_mode.py | 43 ++++++++++------------------ 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index 07c2380fcc1..933ed381a78 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -39,7 +39,6 @@ def set_revert_mode( project_name: str, should_revert: bool, revert_up_to_block: int, - restart_strategy: RestartStrategy, ): config_overrides = { "revert_config.should_revert": should_revert, @@ -60,7 +59,7 @@ def set_revert_mode( post_restart_instructions, ) restarter = ServiceRestarter.from_restart_strategy( - restart_strategy, + RestartStrategy.ALL_AT_ONCE, namespace_and_instruction_args, Service.Core, ) @@ -77,41 +76,34 @@ def main(): usage_example = """ Examples: # Set revert mode up to a specific block - %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --revert-only --revert_up_to_block 12345 - %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -b 12345 + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --revert-only --revert_up_to_block 12345 + %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -b 12345 # Set revert mode using feeder URL to get current block - %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --revert-only --feeder-url feeder.integration-sepolia.starknet.io - %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --revert-only --feeder-url feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -N 3 --revert-only -f feeder.integration-sepolia.starknet.io # Disable revert mode - %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 -t all_at_once --disable-revert-only - %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --disable-revert-only + %(prog)s --namespace apollo-sepolia-integration --num-nodes 3 --disable-revert-only + %(prog)s -n apollo-sepolia-integration -N 3 --disable-revert-only # Set revert mode with cluster prefix - %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster -t all_at_once --revert-only -b 12345 + %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster --revert-only -b 12345 # Set revert mode with feeder URL and cluster prefix - %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io - - # Disable revert mode without restarting nodes - %(prog)s -n apollo-sepolia-integration -N 3 -t no_restart --disable-revert-only - - # Set revert mode with explicit restart - %(prog)s -n apollo-sepolia-integration -N 3 -t all_at_once --revert-only -b 12345 - - # Set revert mode with feeder URL and explicit restart - %(prog)s -n apollo-sepolia-integration -N 3 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -N 3 -c my-cluster --revert-only -f feeder.integration-sepolia.starknet.io # Set revert mode starting from specific node index - %(prog)s -n apollo-sepolia-integration -N 3 -i 5 -t all_at_once --revert-only -b 12345 + %(prog)s -n apollo-sepolia-integration -N 3 -i 5 --revert-only -b 12345 # Set revert mode with feeder URL starting from specific node index - %(prog)s -n apollo-sepolia-integration -N 3 -i 5 -t one_by_one --revert-only -f feeder.integration-sepolia.starknet.io + %(prog)s -n apollo-sepolia-integration -N 3 -i 5 --revert-only -f feeder.integration-sepolia.starknet.io """ args_builder = ApolloArgsParserBuilder( - "Sets or unsets the revert mode for the sequencer nodes", usage_example + "Sets or unsets the revert mode for the sequencer nodes", + usage_example, + include_restart_strategy=False, ) revert_group = args_builder.parser.add_mutually_exclusive_group() @@ -137,15 +129,12 @@ def main(): # TODO(guy.f): Remove this when we rely on metrics for restarting. args_builder.add_argument( "--project-name", + required=True, help="The name of the project to get logs from. If One_By_One strategy is used, this is required.", ) args = args_builder.build() - if args.restart_strategy == RestartStrategy.ONE_BY_ONE and args.project_name is None: - print_error("Error: --project-name is required when using One_By_One strategy") - sys.exit(1) - should_revert = not args.disable_revert_only if should_revert: if args.feeder_url is None and args.revert_up_to_block is None: @@ -182,7 +171,6 @@ def main(): args.project_name, True, revert_up_to_block, - args.restart_strategy, ) if should_disable_revert: print_colored(f"\nDisabling revert mode") @@ -193,7 +181,6 @@ def main(): args.project_name, False, 18446744073709551615, - args.restart_strategy, ) From 132da8e66635b5c99e198b772291a1eabdaa8ee6 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Sun, 2 Nov 2025 19:20:58 +0200 Subject: [PATCH 238/313] apollo_integration_tests: add l1 handler to revert flow (#9912) --- .../integration_test_revert_flow.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs index 84b80f0aa91..363817dfe0a 100644 --- a/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs +++ b/crates/apollo_integration_tests/src/bin/sequencer_node_end_to_end_integration_tests/integration_test_revert_flow.rs @@ -21,8 +21,7 @@ async fn main() { assert!(BLOCK_TO_REVERT_FROM < BLOCK_TO_WAIT_FOR_AFTER_REVERT); const N_INVOKE_TXS: usize = 50; - // TODO(Arni): handle L1 handlers in this scenario. - const N_L1_HANDLER_TXS: usize = 0; + const N_L1_HANDLER_TXS: usize = 5; /// The number of consolidated local sequencers that participate in the test. const N_CONSOLIDATED_SEQUENCERS: usize = 5; /// The number of hybrid sequencers that participate in the test. From d103b8ccb5ac1a0af2aeceea0508419be67fb64f Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Sun, 2 Nov 2025 19:21:23 +0200 Subject: [PATCH 239/313] apollo_integration_tests: remove in ci check from scraper test (#9914) --- .../tests/l1_events_scraper_end_to_end.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs index 22cdbcdc50f..c1ae3904df3 100644 --- a/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs +++ b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs @@ -19,16 +19,8 @@ use starknet_api::hash::StarkHash; use starknet_api::transaction::fields::{Calldata, Fee}; use starknet_api::transaction::{L1HandlerTransaction, TransactionHasher, TransactionVersion}; -pub fn in_ci() -> bool { - std::env::var("CI").is_ok() -} - #[tokio::test] async fn scraper_end_to_end() { - if !in_ci() { - return; - } - // Setup. let base_layer = AnvilBaseLayer::new().await; let contract = &base_layer.ethereum_base_layer.contract; From 85aa8af30dc0442ca18cb0c30fbe94e35e61b915 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Mon, 3 Nov 2025 09:35:39 +0200 Subject: [PATCH 240/313] apollo_dashboard: change sync lag to be nonapplicable for observer nodes (#9916) --- .../apollo_dashboard/resources/dev_grafana_alerts_mainnet.json | 2 +- .../apollo_dashboard/resources/dev_grafana_alerts_testnet.json | 2 +- crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json index 762e4018acb..a5fe4267f54 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_mainnet.json @@ -1594,7 +1594,7 @@ "for": "30s", "intervalSec": 30, "severity": "p2", - "observer_applicable": "true" + "observer_applicable": "false" }, { "name": "state_sync_stuck", diff --git a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json index 3d48df7ca95..a46529b6d2d 100644 --- a/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json +++ b/crates/apollo_dashboard/resources/dev_grafana_alerts_testnet.json @@ -1678,7 +1678,7 @@ "for": "30s", "intervalSec": 30, "severity": "p3", - "observer_applicable": "true" + "observer_applicable": "false" }, { "name": "state_sync_stuck", diff --git a/crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs b/crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs index 03bccd9a2e8..3436d796e9f 100644 --- a/crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs +++ b/crates/apollo_dashboard/src/alert_scenarios/sync_halt.rs @@ -41,7 +41,7 @@ fn get_state_sync_lag( PENDING_DURATION_DEFAULT, EVALUATION_INTERVAL_SEC_DEFAULT, alert_severity, - ObserverApplicability::Applicable, + ObserverApplicability::NotApplicable, alert_env_filtering, ) } From 0b98c4a1bb6019b3842470ef1f53fdbf3784afa7 Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Mon, 3 Nov 2025 09:55:23 +0200 Subject: [PATCH 241/313] apollo_time: add ClockExt extension trait with sleep_until (#9903) --- crates/apollo_consensus/src/manager.rs | 4 +-- .../src/validate_proposal.rs | 6 ++-- crates/apollo_time/src/time.rs | 29 ++++++++++++------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/crates/apollo_consensus/src/manager.rs b/crates/apollo_consensus/src/manager.rs index 47498b26bcc..71b37f81a38 100644 --- a/crates/apollo_consensus/src/manager.rs +++ b/crates/apollo_consensus/src/manager.rs @@ -17,7 +17,7 @@ use apollo_network::network_manager::BroadcastTopicClientTrait; use apollo_network_types::network_types::BroadcastedMessageMetadata; use apollo_protobuf::consensus::{ProposalInit, Vote}; use apollo_protobuf::converters::ProtobufConversionError; -use apollo_time::time::{sleep_until, Clock, DefaultClock}; +use apollo_time::time::{Clock, ClockExt, DefaultClock}; use futures::channel::mpsc; use futures::stream::FuturesUnordered; use futures::{FutureExt, StreamExt}; @@ -318,7 +318,7 @@ impl MultiHeightManager { }, // Using sleep_until to make sure that we won't restart the sleep due to other // events occuring. - _ = sleep_until(sync_poll_deadline, &clock) => { + _ = clock.sleep_until(sync_poll_deadline) => { sync_poll_deadline += sync_retry_interval; if context.try_sync(height).await { return Ok(RunHeightRes::Sync); diff --git a/crates/apollo_consensus_orchestrator/src/validate_proposal.rs b/crates/apollo_consensus_orchestrator/src/validate_proposal.rs index f7ec2e5d7ff..07b6defa4fd 100644 --- a/crates/apollo_consensus_orchestrator/src/validate_proposal.rs +++ b/crates/apollo_consensus_orchestrator/src/validate_proposal.rs @@ -20,7 +20,7 @@ use apollo_l1_gas_price_types::errors::{EthToStrkOracleClientError, L1GasPriceCl use apollo_l1_gas_price_types::L1GasPriceProviderClient; use apollo_protobuf::consensus::{ConsensusBlockInfo, ProposalFin, ProposalPart, TransactionBatch}; use apollo_state_sync_types::communication::StateSyncClient; -use apollo_time::time::{sleep_until, Clock, DateTime}; +use apollo_time::time::{Clock, ClockExt, DateTime}; use futures::channel::mpsc; use futures::StreamExt; use starknet_api::block::{BlockNumber, GasPrice}; @@ -182,7 +182,7 @@ pub(crate) async fn validate_proposal( "validating proposal parts".to_string(), )); } - _ = sleep_until(deadline, args.deps.clock.as_ref()) => { + _ = args.deps.clock.sleep_until(deadline) => { batcher_abort_proposal(args.deps.batcher.as_ref(), args.proposal_id).await; return Err(ValidateProposalError::ValidationTimeout( "validating proposal parts".to_string(), @@ -361,7 +361,7 @@ async fn await_second_proposal_part( "waiting for second proposal part".to_string(), )) } - _ = sleep_until(deadline, clock) => { + _ = clock.sleep_until(deadline) => { Err(ValidateProposalError::ValidationTimeout( "waiting for second proposal part".to_string(), )) diff --git a/crates/apollo_time/src/time.rs b/crates/apollo_time/src/time.rs index ae4575ab8a5..40f41583c90 100644 --- a/crates/apollo_time/src/time.rs +++ b/crates/apollo_time/src/time.rs @@ -18,19 +18,26 @@ pub trait Clock: Send + Sync + Debug { } } -/// Free function to sleep until a given deadline using a provided clock. -#[cfg(feature = "tokio")] -pub async fn sleep_until(deadline: DateTime, clock: &dyn Clock) { - // Calculate how much time is left until the deadline. - // If the deadline has already passed, this will be a negative duration. - let time_delta = deadline - clock.now(); - // Convert to `std::time::Duration`, clamping any negative value to zero. - // A zero-duration sleep is effectively a no-op. - let duration_to_sleep = time_delta.to_std().unwrap_or_default(); - // Sleep for the computed duration (or return immediately if zero). - tokio::time::sleep(duration_to_sleep).await; +pub trait ClockExt: Clock { + fn sleep_until<'a>( + &'a self, + deadline: DateTime, + ) -> impl core::future::Future + Send + 'a { + async move { + // Calculate how much time is left until the deadline. + // If the deadline has already passed, this will be a negative duration. + let time_delta = deadline - self.now(); + // Convert to `std::time::Duration`, clamping any negative value to zero. + // A zero-duration sleep is effectively a no-op. + let duration_to_sleep = time_delta.to_std().unwrap_or_default(); + // Sleep for the computed duration (or return immediately if zero). + tokio::time::sleep(duration_to_sleep).await; + } + } } +impl ClockExt for T {} + #[derive(Clone, Copy, Debug, Default)] pub struct DefaultClock; From fee02038a11635e7745c7eb348865ffbc143f2b7 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Mon, 3 Nov 2025 12:59:13 +0200 Subject: [PATCH 242/313] scripts: add an option for exclude patterns to specifically exclude paths (#9923) --- scripts/check_test_trigger.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/scripts/check_test_trigger.py b/scripts/check_test_trigger.py index 4239c07ed2a..7a83b6910b6 100644 --- a/scripts/check_test_trigger.py +++ b/scripts/check_test_trigger.py @@ -9,16 +9,20 @@ from tests_utils import get_local_changes, get_tested_packages -def is_file_triggered(commit_id: str, trigger_patterns: List[str]) -> bool: +def is_file_triggered( + commit_id: str, trigger_patterns: List[str], exclude_patterns: List[str] +) -> bool: """ Returns True if any file changed since `commit_id` matches any of the given - wildcard patterns in `trigger_patterns`. + wildcard patterns in `trigger_patterns` and does not match any in `exclude_patterns`. """ changed_files = get_local_changes(".", commit_id) for changed in changed_files: normalized = changed.replace(os.sep, "/") for pattern in trigger_patterns: - if fnmatch.fnmatch(normalized, pattern): + if fnmatch.fnmatch(normalized, pattern) and not any( + fnmatch.fnmatch(normalized, exclude_pattern) for exclude_pattern in exclude_patterns + ): return True return False @@ -48,6 +52,12 @@ def parse_args() -> argparse.Namespace: default="", help="Comma-separated list of file/path patterns that should trigger the test.", ) + parser.add_argument( + "--path_triggers-exclude", + type=str, + default="", + help="Comma-separated list of file/path patterns that should not trigger the test. Takes precedence over path_triggers.", + ) return parser.parse_args() @@ -56,6 +66,7 @@ def main(): crate_triggers: Set[str] = set(filter(None, args.crate_triggers.split(","))) path_triggers: List[str] = list(filter(None, args.path_triggers.split(","))) + path_triggers_exclude: List[str] = list(filter(None, args.path_triggers_exclude.split(","))) tested = get_tested_packages( changes_only=True, commit_id=args.commit_id, include_dependencies=True @@ -67,7 +78,7 @@ def main(): crate_trigger = any(crate in crate_triggers for crate in tested) print(f"crate_trigger: {crate_trigger}", file=sys.stderr) - file_trigger = is_file_triggered(args.commit_id, path_triggers) + file_trigger = is_file_triggered(args.commit_id, path_triggers, path_triggers_exclude) print(f"file_trigger: {file_trigger}", file=sys.stderr) should_run = crate_trigger or file_trigger From 0b8755c95d0450d1f85492708213daa8355f1961 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Mon, 3 Nov 2025 13:00:04 +0200 Subject: [PATCH 243/313] scripts: refactor the lib file into multiple libs (#9924) --- scripts/prod/common_lib.py | 172 ++++++ scripts/prod/metrics_lib.py | 169 ++++++ scripts/prod/restart_all_nodes_together.py | 9 +- scripts/prod/restarter_lib.py | 144 +++++ scripts/prod/set_node_revert_mode.py | 14 +- .../prod/update_config_and_restart_nodes.py | 8 +- .../update_config_and_restart_nodes_lib.py | 492 +----------------- 7 files changed, 524 insertions(+), 484 deletions(-) create mode 100644 scripts/prod/common_lib.py create mode 100644 scripts/prod/metrics_lib.py create mode 100644 scripts/prod/restarter_lib.py diff --git a/scripts/prod/common_lib.py b/scripts/prod/common_lib.py new file mode 100644 index 00000000000..9a6ae613ccb --- /dev/null +++ b/scripts/prod/common_lib.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 + +import argparse +import subprocess +import sys +from enum import Enum +from typing import Optional + + +class Colors(Enum): + """ANSI color codes for terminal output""" + + RED = "\033[1;31m" + GREEN = "\033[1;32m" + YELLOW = "\033[1;33m" + BLUE = "\033[1;34m" + RESET = "\033[0m" + + +def print_colored(message: str, color: Colors = Colors.RESET, file=sys.stdout) -> None: + """Print message with color""" + print(f"{color.value}{message}{Colors.RESET.value}", file=file) + + +def print_error(message: str) -> None: + print_colored(message, color=Colors.RED, file=sys.stderr) + + +class RestartStrategy(Enum): + """Strategy for restarting nodes.""" + + ALL_AT_ONCE = "all_at_once" + ONE_BY_ONE = "one_by_one" + NO_RESTART = "no_restart" + + +def restart_strategy_converter(strategy_name: str) -> RestartStrategy: + """Convert string to RestartStrategy enum with informative error message""" + RESTART_STRATEGY_PREFIX = f"{RestartStrategy.__name__}." + if strategy_name.startswith(RESTART_STRATEGY_PREFIX): + strategy_name = strategy_name[len(RESTART_STRATEGY_PREFIX) :] + + strategy_name = strategy_name.lower() + + try: + return RestartStrategy(strategy_name) + except KeyError: + valid_strategies = ", ".join([strategy.value for strategy in RestartStrategy]) + raise argparse.ArgumentTypeError( + f"Invalid restart strategy '{strategy_name}'. Valid options are: {valid_strategies}" + ) + + +class Service(Enum): + """Service types mapping to their configmap and pod names.""" + + Core = ("sequencer-core-config", "sequencer-core-statefulset-0") + Gateway = ("sequencer-gateway-config", "sequencer-gateway-deployment") + HttpServer = ( + "sequencer-httpserver-config", + "sequencer-httpserver-deployment", + ) + L1 = ("sequencer-l1-config", "sequencer-l1-deployment") + Mempool = ("sequencer-mempool-config", "sequencer-mempool-deployment") + SierraCompiler = ( + "sequencer-sierracompiler-config", + "sequencer-sierracompiler-deployment", + ) + + def __init__(self, config_map_name: str, pod_name: str) -> None: + self.config_map_name = config_map_name + self.pod_name = pod_name + + +class NamespaceAndInstructionArgs: + def __init__( + self, + namespace_list: list[str], + cluster_list: Optional[list[str]], + instruction_list: Optional[list[str]] = None, + ): + assert ( + namespace_list is not None and len(namespace_list) > 0 + ), "Namespace list cannot be None or empty." + self.namespace_list = namespace_list + assert cluster_list is None or len(cluster_list) == len( + namespace_list + ), "cluster_list must have the same length as namespace_list" + self.cluster_list = cluster_list + assert instruction_list is None or len(namespace_list) == len( + instruction_list + ), "instruction_list must have the same length as namespace_list" + self.instruction_list = instruction_list + + def size(self) -> int: + return len(self.namespace_list) + + def get_namespace(self, index: int) -> str: + return self.namespace_list[index] + + def get_cluster(self, index: int) -> Optional[str]: + return self.cluster_list[index] if self.cluster_list is not None else None + + def get_instruction(self, index: int) -> Optional[str]: + return self.instruction_list[index] if self.instruction_list is not None else None + + @staticmethod + def get_namespace_list_from_args( + args: argparse.Namespace, + ) -> list[str]: + """Get a list of namespaces based on the arguments""" + if args.namespace_list: + return args.namespace_list + + return [ + f"{args.namespace_prefix}-{i}" + for i in range(args.start_index, args.start_index + args.num_nodes) + ] + + @staticmethod + def get_context_list_from_args( + args: argparse.Namespace, + ) -> list[str]: + """Get a list of contexts based on the arguments""" + if args.cluster_list: + return args.cluster_list + + if args.cluster_prefix is None: + return None + + return [ + f"{args.cluster_prefix}-{i}" + for i in range(args.start_index, args.start_index + args.num_nodes) + ] + + +def get_namespace_args(namespace: str, cluster: Optional[str] = None) -> list[str]: + ret = ["-n", f"{namespace}"] + if cluster: + ret.extend(["--context", f"{cluster}"]) + return ret + + +def run_kubectl_command(args: list, capture_output: bool = True) -> subprocess.CompletedProcess: + full_command = ["kubectl"] + args + try: + result = subprocess.run(full_command, capture_output=capture_output, text=True, check=True) + return result + except subprocess.CalledProcessError as e: + print_error(f"kubectl command failed: {' '.join(full_command)}") + print_error(f"Error: {e.stderr}") + sys.exit(1) + + +def ask_for_confirmation() -> bool: + """Ask user for confirmation to proceed""" + response = ( + input(f"{Colors.BLUE.value}Do you approve these changes? (y/n){Colors.RESET.value}") + .strip() + .lower() + ) + return response == "y" + + +def wait_until_y_or_n(question: str) -> bool: + """Wait until user enters y or n. Cotinues asking until user enters y or n.""" + while True: + response = input(f"{Colors.BLUE.value}{question} (y/n){Colors.RESET.value}").strip().lower() + if response == "y" or response == "n": + break + print_error(f"Invalid response: {response}") + return response == "y" diff --git a/scripts/prod/metrics_lib.py b/scripts/prod/metrics_lib.py new file mode 100644 index 00000000000..e4403855f07 --- /dev/null +++ b/scripts/prod/metrics_lib.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 + +import subprocess +import sys +from time import sleep +from typing import Any, Callable, Optional + +import signal +import socket +import urllib.error +import urllib.request +from prometheus_client.parser import text_string_to_metric_families + +from scripts.prod.common_lib import Colors, get_namespace_args, print_colored, print_error + + +class MetricConditionGater: + """Gates progress on a metric satisfying a condition. + + This class was meant to be used with counter/gauge metrics. It may not work properly with histogram metrics. + """ + + class MetricCondition: + def __init__( + self, + value_condition: Callable[[Any], bool], + condition_description: Optional[str] = None, + ): + self.value_condition = value_condition + self.condition_description = condition_description + + def __init__( + self, + metric_name: str, + namespace: str, + cluster: Optional[str], + pod: str, + metrics_port: int, + metric_value_condition: "MetricConditionGater.MetricCondition", + refresh_interval_seconds: int = 3, + ): + self.metric_name = metric_name + self.local_port = self._get_free_port() + self.namespace = namespace + self.cluster = cluster + self.pod = pod + self.metrics_port = metrics_port + self.metric_value_condition = metric_value_condition + self.refresh_interval_seconds = refresh_interval_seconds + + @staticmethod + def _get_free_port(): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(("", 0)) + return s.getsockname()[1] + + def _get_metrics_raw_string(self) -> str: + while True: + try: + with urllib.request.urlopen( + f"http://localhost:{self.local_port}/monitoring/metrics" + ) as response: + if response.status == 200: + return response.read().decode("utf-8") + else: + print_colored( + f"Failed to get metrics for pod {self.pod}: {response.status}" + ) + except urllib.error.URLError as e: + print_colored(f"Failed to get metrics for pod {self.pod}: {e}") + print_colored( + f"Waiting {self.refresh_interval_seconds} seconds to retry getting metrics...", + Colors.YELLOW, + ) + sleep(self.refresh_interval_seconds) + + def _poll_until_condition_met(self): + """Poll metrics until the condition is met for the metric.""" + condition_description = ( + f"({self.metric_value_condition.condition_description}) " + if self.metric_value_condition.condition_description is not None + else "" + ) + + while True: + metrics = self._get_metrics_raw_string() + assert metrics is not None, f"Failed to get metrics from for pod {self.pod}" + + metric_families = text_string_to_metric_families(metrics) + val = None + for metric_family in metric_families: + if metric_family.name == self.metric_name: + if len(metric_family.samples) > 1: + print_error( + f"Multiple samples found for metric {self.metric_name}. Using the first one.", + ) + val = metric_family.samples[0].value + break + + if val is None: + print_colored( + f"Metric '{self.metric_name}' not found in pod {self.pod}. Assuming the node is not ready." + ) + elif self.metric_value_condition.value_condition(val): + print_colored( + f"Metric {self.metric_name} condition {condition_description}met (value={val})." + ) + return + else: + print_colored( + f"Metric {self.metric_name} condition {condition_description}not met (value={val}). Continuing to wait." + ) + + sleep(self.refresh_interval_seconds) + + @staticmethod + def _terminate_port_forward_process(pf_process: subprocess.Popen): + if pf_process and pf_process.poll() is None: + print_colored(f"Terminating kubectl port-forward process (PID: {pf_process.pid})") + pf_process.terminate() + try: + pf_process.wait(timeout=5) + except subprocess.TimeoutExpired: + print_colored("Force killing kubectl port-forward process") + pf_process.kill() + pf_process.wait() + + def gate(self): + """Wait until the nodes metrics satisfy the condition.""" + # This method: + # 1. Starts kubectl port forwarding to the node and keep it running in the background so we can access the metrics. + # 2. Calls _poll_until_condition_met. + # 3. Terminates the port forwarding process when done or when interrupted. + cmd = [ + "kubectl", + "port-forward", + f"pod/{self.pod}", + f"{self.local_port}:{self.metrics_port}", + ] + cmd.extend(get_namespace_args(self.namespace, self.cluster)) + + pf_process = None + + try: + pf_process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + print("Waiting for forwarding to start") + # Give the forwarding time to start. + # TODO(guy.f): Consider poll until the forwarding is ready if we see any issues. + sleep(3) + assert ( + pf_process.poll() is None + ), f"Port forwarding process exited with code {pf_process.returncode}" + + print( + f"Forwarding started (from local port {self.local_port} to {self.pod}:{self.metrics_port})" + ) + + # Set up signal handler to ensure forwarding subprocess is terminated on interruption + def signal_handler(signum, frame): + self._terminate_port_forward_process(pf_process) + sys.exit(0) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + self._poll_until_condition_met() + + finally: + self._terminate_port_forward_process(pf_process) diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_nodes_together.py index 075182f7f29..b143fe53381 100755 --- a/scripts/prod/restart_all_nodes_together.py +++ b/scripts/prod/restart_all_nodes_together.py @@ -2,21 +2,16 @@ from typing import Optional -import urllib.error import urllib.parse -import urllib.request +from common_lib import NamespaceAndInstructionArgs, RestartStrategy, Service, print_colored +from restarter_lib import ServiceRestarter from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, ConstConfigValuesUpdater, - NamespaceAndInstructionArgs, - RestartStrategy, - Service, - ServiceRestarter, get_configmap, get_current_block_number, get_logs_explorer_url, parse_config_from_yaml, - print_colored, update_config_and_restart_nodes, ) diff --git a/scripts/prod/restarter_lib.py b/scripts/prod/restarter_lib.py new file mode 100644 index 00000000000..9a98ac99778 --- /dev/null +++ b/scripts/prod/restarter_lib.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 + +import sys +from abc import ABC, abstractmethod +from typing import Callable, Optional + +from common_lib import ( + Colors, + NamespaceAndInstructionArgs, + RestartStrategy, + Service, + get_namespace_args, + print_colored, + print_error, + run_kubectl_command, + wait_until_y_or_n, +) + + +def _get_pod_names( + namespace: str, service: Service, index: int, cluster: Optional[str] = None +) -> list[str]: + kubectl_args = [ + "get", + "pods", + "-o", + "name", + ] + kubectl_args.extend(get_namespace_args(namespace, cluster)) + pods = run_kubectl_command(kubectl_args, capture_output=True).stdout.splitlines() + return [pod.split("/")[1] for pod in pods if pod.startswith(f"pod/{service.pod_name}")] + + +class ServiceRestarter(ABC): + """Abstract class for restarting service instances.""" + + def __init__( + self, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + ): + self.namespace_and_instruction_args = namespace_and_instruction_args + self.service = service + + @staticmethod + def _restart_pod( + namespace: str, service: Service, index: int, cluster: Optional[str] = None + ) -> None: + """Restart pod by deleting it""" + pods = _get_pod_names(namespace, service, index, cluster) + + if not pods: + print_error(f"Could not find pods for service {service.pod_name}.") + sys.exit(1) + + # Go over each pod and delete it. + for pod in pods: + kubectl_args = [ + "delete", + "pod", + pod, + ] + kubectl_args.extend(get_namespace_args(namespace, cluster)) + + try: + run_kubectl_command(kubectl_args, capture_output=False) + print_colored(f"Restarted {pod} for node {index}") + except Exception as e: + print_error(f"Failed restarting {pod} for node {index}: {e}") + sys.exit(1) + + @abstractmethod + def restart_service(self, instance_index: int) -> bool: + """Restart service for a specific instance. If returns False, the restart process should be aborted.""" + + # from_restart_strategy is a static method that returns the appropriate ServiceRestarter based on the restart strategy. + @staticmethod + def from_restart_strategy( + restart_strategy: RestartStrategy, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + ) -> "ServiceRestarter": + if restart_strategy == RestartStrategy.ONE_BY_ONE: + check_between_restarts = lambda instance_index: ( + True + if instance_index == namespace_and_instruction_args.size() - 1 + else wait_until_y_or_n(f"Do you want to restart the next pod?") + ) + + return ChecksBetweenRestarts( + namespace_and_instruction_args, + service, + check_between_restarts, + ) + elif restart_strategy == RestartStrategy.ALL_AT_ONCE: + return ChecksBetweenRestarts( + namespace_and_instruction_args, + service, + lambda instance_index: True, + ) + elif restart_strategy == RestartStrategy.NO_RESTART: + assert ( + namespace_and_instruction_args.get_instruction(0) is None + ), f"post_restart_instructions is not allowed with no_restart as the restart strategy" + return NoOpServiceRestarter(namespace_and_instruction_args, service) + else: + raise ValueError(f"Invalid restart strategy: {restart_strategy}") + + +class ChecksBetweenRestarts(ServiceRestarter): + """Checks between restarts.""" + + def __init__( + self, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + check_between_restarts: Callable[[int], bool], + ): + super().__init__(namespace_and_instruction_args, service) + self.check_between_restarts = check_between_restarts + + def restart_service(self, instance_index: int) -> bool: + """Restart the instance one by one, running the use code in between each restart.""" + self._restart_pod( + self.namespace_and_instruction_args.get_namespace(instance_index), + self.service, + instance_index, + self.namespace_and_instruction_args.get_cluster(instance_index), + ) + instructions = self.namespace_and_instruction_args.get_instruction(instance_index) + print_colored( + f"Restarted pod {instance_index}.\n{instructions if instructions is not None else ''} ", + Colors.YELLOW, + ) + return self.check_between_restarts(instance_index) + + +class NoOpServiceRestarter(ServiceRestarter): + """No-op service restarter.""" + + def restart_service(self, instance_index: int) -> bool: + """No-op.""" + print_colored("\nSkipping pod restart.") + return True diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index 933ed381a78..f77f5b40eb0 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -4,17 +4,19 @@ from typing import Optional import urllib.parse -from update_config_and_restart_nodes_lib import ( - ApolloArgsParserBuilder, - ConstConfigValuesUpdater, +from common_lib import ( NamespaceAndInstructionArgs, RestartStrategy, Service, - ServiceRestarter, - get_current_block_number, - get_logs_explorer_url, print_colored, print_error, +) +from restarter_lib import ServiceRestarter +from update_config_and_restart_nodes_lib import ( + ApolloArgsParserBuilder, + ConstConfigValuesUpdater, + get_current_block_number, + get_logs_explorer_url, update_config_and_restart_nodes, ) diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index c6e40582b7d..9dc86a28012 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -5,15 +5,11 @@ import sys from typing import Any +from common_lib import Colors, NamespaceAndInstructionArgs, Service, print_colored, print_error +from restarter_lib import ServiceRestarter from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, - Colors, ConstConfigValuesUpdater, - NamespaceAndInstructionArgs, - Service, - ServiceRestarter, - print_colored, - print_error, update_config_and_restart_nodes, ) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 307b680ae18..39885d6a9bb 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -2,41 +2,28 @@ import argparse import json -import subprocess import sys from abc import ABC, abstractmethod -from enum import Enum -from time import sleep -from typing import Any, Callable, Optional +from typing import Any, Optional -import signal -import socket import tempfile import urllib.error -import urllib.parse import urllib.request import yaml +from common_lib import ( + Colors, + NamespaceAndInstructionArgs, + RestartStrategy, + Service, + ask_for_confirmation, + get_namespace_args, + print_colored, + print_error, + restart_strategy_converter, + run_kubectl_command, +) from difflib import unified_diff -from prometheus_client.parser import text_string_to_metric_families - - -class Colors(Enum): - """ANSI color codes for terminal output""" - - RED = "\033[1;31m" - GREEN = "\033[1;32m" - YELLOW = "\033[1;33m" - BLUE = "\033[1;34m" - RESET = "\033[0m" - - -def print_colored(message: str, color: Colors = Colors.RESET, file=sys.stdout) -> None: - """Print message with color""" - print(f"{color.value}{message}{Colors.RESET.value}", file=file) - - -def print_error(message: str) -> None: - print_colored(message, color=Colors.RED, file=sys.stderr) +from restarter_lib import ServiceRestarter class ApolloArgsParserBuilder: @@ -134,52 +121,6 @@ def build(self) -> argparse.Namespace: return args -class Service(Enum): - """Service types mapping to their configmap and pod names.""" - - Core = ("sequencer-core-config", "sequencer-core-statefulset-0") - Gateway = ("sequencer-gateway-config", "sequencer-gateway-deployment") - HttpServer = ( - "sequencer-httpserver-config", - "sequencer-httpserver-deployment", - ) - L1 = ("sequencer-l1-config", "sequencer-l1-deployment") - Mempool = ("sequencer-mempool-config", "sequencer-mempool-deployment") - SierraCompiler = ( - "sequencer-sierracompiler-config", - "sequencer-sierracompiler-deployment", - ) - - def __init__(self, config_map_name: str, pod_name: str) -> None: - self.config_map_name = config_map_name - self.pod_name = pod_name - - -class RestartStrategy(Enum): - """Strategy for restarting nodes.""" - - ALL_AT_ONCE = "all_at_once" - ONE_BY_ONE = "one_by_one" - NO_RESTART = "no_restart" - - -def restart_strategy_converter(strategy_name: str) -> RestartStrategy: - """Convert string to RestartStrategy enum with informative error message""" - RESTART_STRATEGY_PREFIX = f"{RestartStrategy.__name__}." - if strategy_name.startswith(RESTART_STRATEGY_PREFIX): - strategy_name = strategy_name[len(RESTART_STRATEGY_PREFIX) :] - - strategy_name = strategy_name.lower() - - try: - return RestartStrategy(strategy_name) - except KeyError: - valid_strategies = ", ".join([strategy.value for strategy in RestartStrategy]) - raise argparse.ArgumentTypeError( - f"Invalid restart strategy '{strategy_name}'. Valid options are: {valid_strategies}" - ) - - def validate_arguments(args: argparse.Namespace) -> None: if (args.namespace_list and args.cluster_prefix) or ( args.namespace_prefix and args.cluster_list @@ -216,221 +157,21 @@ def validate_arguments(args: argparse.Namespace) -> None: sys.exit(1) -class MetricConditionGater: - """Gates progress on a metric satisfying a condition. - - This class was meant to be used with counter/gauge metrics. It may not work properly with histogram metrics. - """ - - class MetricCondition: - def __init__( - self, - value_condition: Callable[[Any], bool], - condition_description: Optional[str] = None, - ): - self.value_condition = value_condition - self.condition_description = condition_description - - def __init__( - self, - metric_name: str, - namespace: str, - cluster: Optional[str], - pod: str, - metrics_port: int, - metric_value_condition: "MetricConditionGater.MetricCondition", - refresh_interval_seconds: int = 3, - ): - self.metric_name = metric_name - self.local_port = self._get_free_port() - self.namespace = namespace - self.cluster = cluster - self.pod = pod - self.metrics_port = metrics_port - self.metric_value_condition = metric_value_condition - self.refresh_interval_seconds = refresh_interval_seconds - - @staticmethod - def _get_free_port(): - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.bind(("", 0)) - return s.getsockname()[1] - - def _get_metrics_raw_string(self) -> str: - while True: - try: - with urllib.request.urlopen( - f"http://localhost:{self.local_port}/monitoring/metrics" - ) as response: - if response.status == 200: - return response.read().decode("utf-8") - else: - print_colored( - f"Failed to get metrics for pod {self.pod}: {response.status}" - ) - except urllib.error.URLError as e: - print_colored(f"Failed to get metrics for pod {self.pod}: {e}") - print_colored( - f"Waiting {self.refresh_interval_seconds} seconds to retry getting metrics...", - Colors.YELLOW, - ) - sleep(self.refresh_interval_seconds) - - def _poll_until_condition_met(self): - """Poll metrics until the condition is met for the metric.""" - condition_description = ( - f"({self.metric_value_condition.condition_description}) " - if self.metric_value_condition.condition_description is not None - else "" - ) - - while True: - metrics = self._get_metrics_raw_string() - assert metrics is not None, f"Failed to get metrics from for pod {self.pod}" - - metric_families = text_string_to_metric_families(metrics) - val = None - for metric_family in metric_families: - if metric_family.name == self.metric_name: - if len(metric_family.samples) > 1: - print_error( - f"Multiple samples found for metric {self.metric_name}. Using the first one.", - ) - val = metric_family.samples[0].value - break - - if val is None: - print_colored( - f"Metric '{self.metric_name}' not found in pod {self.pod}. Assuming the node is not ready." - ) - elif self.metric_value_condition.value_condition(val): - print_colored( - f"Metric {self.metric_name} condition {condition_description}met (value={val})." - ) - return - else: - print_colored( - f"Metric {self.metric_name} condition {condition_description}not met (value={val}). Continuing to wait." - ) - - sleep(self.refresh_interval_seconds) - - @staticmethod - def _terminate_port_forward_process(pf_process: subprocess.Popen): - if pf_process and pf_process.poll() is None: - print_colored(f"Terminating kubectl port-forward process (PID: {pf_process.pid})") - pf_process.terminate() - try: - pf_process.wait(timeout=5) - except subprocess.TimeoutExpired: - print_colored("Force killing kubectl port-forward process") - pf_process.kill() - pf_process.wait() - - def gate(self): - """Wait until the nodes metrics satisfy the condition.""" - # This method: - # 1. Starts kubectl port forwarding to the node and keep it running in the background so we can access the metrics. - # 2. Calls _poll_until_condition_met. - # 3. Terminates the port forwarding process when done or when interrupted. - cmd = [ - "kubectl", - "port-forward", - f"pod/{self.pod}", - f"{self.local_port}:{self.metrics_port}", - ] - cmd.extend(get_namespace_args(self.namespace, self.cluster)) - - pf_process = None - - try: - pf_process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - print("Waiting for forwarding to start") - # Give the forwarding time to start. - # TODO(guy.f): Consider poll until the forwarding is ready if we see any issues. - sleep(3) - assert ( - pf_process.poll() is None - ), f"Port forwarding process exited with code {pf_process.returncode}" - - print( - f"Forwarding started (from local port {self.local_port} to {self.pod}:{self.metrics_port})" - ) - - # Set up signal handler to ensure forwarding subprocess is terminated on interruption - def signal_handler(signum, frame): - self._terminate_port_forward_process(pf_process) - sys.exit(0) - - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) - - self._poll_until_condition_met() - - finally: - self._terminate_port_forward_process(pf_process) - - -class NamespaceAndInstructionArgs: - def __init__( - self, - namespace_list: list[str], - cluster_list: Optional[list[str]], - instruction_list: Optional[list[str]] = None, - ): - assert ( - namespace_list is not None and len(namespace_list) > 0 - ), "Namespace list cannot be None or empty." - self.namespace_list = namespace_list - assert cluster_list is None or len(cluster_list) == len( - namespace_list - ), "cluster_list must have the same length as namespace_list" - self.cluster_list = cluster_list - assert instruction_list is None or len(namespace_list) == len( - instruction_list - ), "instruction_list must have the same length as namespace_list" - self.instruction_list = instruction_list - - def size(self) -> int: - return len(self.namespace_list) - - def get_namespace(self, index: int) -> str: - return self.namespace_list[index] - - def get_cluster(self, index: int) -> Optional[str]: - return self.cluster_list[index] if self.cluster_list is not None else None - - def get_instruction(self, index: int) -> Optional[str]: - return self.instruction_list[index] if self.instruction_list is not None else None - - @staticmethod - def get_namespace_list_from_args( - args: argparse.Namespace, - ) -> list[str]: - """Get a list of namespaces based on the arguments""" - if args.namespace_list: - return args.namespace_list - - return [ - f"{args.namespace_prefix}-{i}" - for i in range(args.start_index, args.start_index + args.num_nodes) - ] - - @staticmethod - def get_context_list_from_args( - args: argparse.Namespace, - ) -> list[str]: - """Get a list of contexts based on the arguments""" - if args.cluster_list: - return args.cluster_list +def get_logs_explorer_url( + query: str, + project_name: Optional[str] = None, +) -> str: + # We need to double escape '(' and ')', so first we replace only them with their escaped versions. + query = query.replace("(", urllib.parse.quote("(")).replace(")", urllib.parse.quote(")")) - if args.cluster_prefix is None: - return None + # Now "normal" escape everything else + query = urllib.parse.quote(query) - return [ - f"{args.cluster_prefix}-{i}" - for i in range(args.start_index, args.start_index + args.num_nodes) - ] + escaped_project_name = urllib.parse.quote(project_name) + return ( + f"https://console.cloud.google.com/logs/query;query={query}" + f"?project={escaped_project_name}" + ) class ConfigValuesUpdater(ABC): @@ -489,147 +230,6 @@ def get_updated_config_for_instance( return updated_config -class ServiceRestarter(ABC): - """Abstract class for restarting service instances.""" - - def __init__( - self, - namespace_and_instruction_args: NamespaceAndInstructionArgs, - service: Service, - ): - self.namespace_and_instruction_args = namespace_and_instruction_args - self.service = service - - @staticmethod - def _restart_pod( - namespace: str, service: Service, index: int, cluster: Optional[str] = None - ) -> None: - """Restart pod by deleting it""" - # Get the list of pods (one string per line). - kubectl_args = [ - "get", - "pods", - "-o", - "name", - ] - kubectl_args.extend(get_namespace_args(namespace, cluster)) - pods = run_kubectl_command(kubectl_args, capture_output=True).stdout.splitlines() - - # Filter the list of pods to only include the ones that match the service and extract the pod name. - pods = [pod.split("/")[1] for pod in pods if pod.startswith(f"pod/{service.pod_name}")] - - if not pods: - print_error(f"Could not find pods for service {service.pod_name}.") - sys.exit(1) - - # Go over each pod and delete it. - for pod in pods: - kubectl_args = [ - "delete", - "pod", - pod, - ] - kubectl_args.extend(get_namespace_args(namespace, cluster)) - - try: - run_kubectl_command(kubectl_args, capture_output=False) - print_colored(f"Restarted {pod} for node {index}") - except Exception as e: - print_error(f"Failed restarting {pod} for node {index}: {e}") - sys.exit(1) - - @abstractmethod - def restart_service(self, instance_index: int) -> bool: - """Restart service for a specific instance. If returns False, the restart process should be aborted.""" - - # from_restart_strategy is a static method that returns the appropriate ServiceRestarter based on the restart strategy. - @staticmethod - def from_restart_strategy( - restart_strategy: RestartStrategy, - namespace_and_instruction_args: NamespaceAndInstructionArgs, - service: Service, - ) -> "ServiceRestarter": - if restart_strategy == RestartStrategy.ONE_BY_ONE: - check_between_restarts = lambda instance_index: ( - True - if instance_index == namespace_and_instruction_args.size() - 1 - else wait_until_y_or_n(f"Do you want to restart the next pod?") - ) - - return ChecksBetweenRestarts( - namespace_and_instruction_args, - service, - check_between_restarts, - ) - elif restart_strategy == RestartStrategy.ALL_AT_ONCE: - return ChecksBetweenRestarts( - namespace_and_instruction_args, - service, - lambda instance_index: True, - ) - elif restart_strategy == RestartStrategy.NO_RESTART: - assert ( - namespace_and_instruction_args.get_instruction(0) is None - ), f"post_restart_instructions is not allowed with no_restart as the restart strategy" - return NoOpServiceRestarter(namespace_and_instruction_args, service) - else: - raise ValueError(f"Invalid restart strategy: {restart_strategy}") - - -class ChecksBetweenRestarts(ServiceRestarter): - """Checks between restarts.""" - - def __init__( - self, - namespace_and_instruction_args: NamespaceAndInstructionArgs, - service: Service, - check_between_restarts: Callable[[int], bool], - ): - super().__init__(namespace_and_instruction_args, service) - self.check_between_restarts = check_between_restarts - - def restart_service(self, instance_index: int) -> bool: - """Restart the instance one by one, running the use code in between each restart.""" - self._restart_pod( - self.namespace_and_instruction_args.get_namespace(instance_index), - self.service, - instance_index, - self.namespace_and_instruction_args.get_cluster(instance_index), - ) - instructions = self.namespace_and_instruction_args.get_instruction(instance_index) - print_colored( - f"Restarted pod {instance_index}.\n{instructions if instructions is not None else ''} ", - Colors.YELLOW, - ) - return self.check_between_restarts(instance_index) - - -class NoOpServiceRestarter(ServiceRestarter): - """No-op service restarter.""" - - def restart_service(self, instance_index: int) -> bool: - """No-op.""" - print_colored("\nSkipping pod restart.") - return True - - -def get_logs_explorer_url( - query: str, - project_name: Optional[str] = None, -) -> str: - # We need to double escape '(' and ')', so first we replace only them with their escaped versions. - query = query.replace("(", urllib.parse.quote("(")).replace(")", urllib.parse.quote(")")) - - # Now "normal" escape everything else - query = urllib.parse.quote(query) - - escaped_project_name = urllib.parse.quote(project_name) - return ( - f"https://console.cloud.google.com/logs/query;query={query}" - f"?project={escaped_project_name}" - ) - - def get_current_block_number(feeder_url: str) -> int: """Get the current block number from the feeder URL.""" try: @@ -654,24 +254,6 @@ def get_current_block_number(feeder_url: str) -> int: sys.exit(1) -def run_kubectl_command(args: list, capture_output: bool = True) -> subprocess.CompletedProcess: - full_command = ["kubectl"] + args - try: - result = subprocess.run(full_command, capture_output=capture_output, text=True, check=True) - return result - except subprocess.CalledProcessError as e: - print_error(f"kubectl command failed: {' '.join(full_command)}") - print_error(f"Error: {e.stderr}") - sys.exit(1) - - -def get_namespace_args(namespace: str, cluster: Optional[str] = None) -> list[str]: - ret = ["-n", f"{namespace}"] - if cluster: - ret.extend(["--context", f"{cluster}"]) - return ret - - def get_configmap( namespace: str, cluster: Optional[str] = None, @@ -788,26 +370,6 @@ def show_config_diff(old_content: str, new_content: str, index: int) -> None: print_colored("No changes detected", Colors.BLUE) -def ask_for_confirmation() -> bool: - """Ask user for confirmation to proceed""" - response = ( - input(f"{Colors.BLUE.value}Do you approve these changes? (y/n){Colors.RESET.value}") - .strip() - .lower() - ) - return response == "y" - - -def wait_until_y_or_n(question: str) -> bool: - """Wait until user enters y or n. Cotinues asking until user enters y or n.""" - while True: - response = input(f"{Colors.BLUE.value}{question} (y/n){Colors.RESET.value}").strip().lower() - if response == "y" or response == "n": - break - print_error(f"Invalid response: {response}") - return response == "y" - - def apply_configmap( config_content: str, namespace: str, From f440aabb868796eeeecf368fcfbda310d3df11aa Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Mon, 3 Nov 2025 14:44:32 +0200 Subject: [PATCH 244/313] scripts: fix a wrong - to _ (#9929) --- scripts/check_test_trigger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_test_trigger.py b/scripts/check_test_trigger.py index 7a83b6910b6..0f3fe287e24 100644 --- a/scripts/check_test_trigger.py +++ b/scripts/check_test_trigger.py @@ -53,7 +53,7 @@ def parse_args() -> argparse.Namespace: help="Comma-separated list of file/path patterns that should trigger the test.", ) parser.add_argument( - "--path_triggers-exclude", + "--path_triggers_exclude", type=str, default="", help="Comma-separated list of file/path patterns that should not trigger the test. Takes precedence over path_triggers.", From c0d4986bce63cb2f1d27789ecaf4947d362016eb Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Mon, 3 Nov 2025 15:32:50 +0200 Subject: [PATCH 245/313] apollo_integration_tests: rename var to l1_handlers in end_to_end_flow (#9921) --- crates/apollo_integration_tests/tests/common/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/apollo_integration_tests/tests/common/mod.rs b/crates/apollo_integration_tests/tests/common/mod.rs index eac0bf3fa4b..952238e536f 100644 --- a/crates/apollo_integration_tests/tests/common/mod.rs +++ b/crates/apollo_integration_tests/tests/common/mod.rs @@ -81,14 +81,14 @@ pub async fn end_to_end_flow( info!("Starting scenario {i}."); // Create and send transactions. // TODO(Arni): move send messages to l2 into [run_test_scenario]. - let l1_to_l2_messages_args = create_l1_to_l2_messages_args_fn(&mut tx_generator); - mock_running_system.send_messages_to_l2(&l1_to_l2_messages_args).await; + let l1_handlers = create_l1_to_l2_messages_args_fn(&mut tx_generator); + mock_running_system.send_messages_to_l2(&l1_handlers).await; // Run the test scenario and get the expected batched tx hashes of the current scenario. let expected_batched_tx_hashes = run_test_scenario( &mut tx_generator, create_rpc_txs_fn, - l1_to_l2_messages_args, + l1_handlers, &mut send_rpc_tx_fn, test_tx_hashes_fn, &chain_id, From 9d361e259a2db97a4190c3ffbc107fac26bf0457 Mon Sep 17 00:00:00 2001 From: Tzahi Date: Mon, 3 Nov 2025 15:33:58 +0200 Subject: [PATCH 246/313] apollo_gateway: remove tx clone in add_tx_inner (#9894) --- crates/apollo_gateway/src/gateway.rs | 42 +++++++++++++--------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/crates/apollo_gateway/src/gateway.rs b/crates/apollo_gateway/src/gateway.rs index 870b0fc6b39..9ddfe720085 100644 --- a/crates/apollo_gateway/src/gateway.rs +++ b/crates/apollo_gateway/src/gateway.rs @@ -93,18 +93,18 @@ impl Gateway { tx: RpcTransaction, p2p_message_metadata: Option, ) -> GatewayResult { - debug!("Processing tx with signature: {:?}", tx.signature()); + debug!("Processing tx: {:?}", &tx); + let tx_signature = tx.signature().clone(); let is_p2p = p2p_message_metadata.is_some(); let start_time = std::time::Instant::now(); - let ret = self.add_tx_inner(&tx, p2p_message_metadata).await; + let ret = self.add_tx_inner(tx, p2p_message_metadata).await; let elapsed = start_time.elapsed().as_secs_f64(); debug!( "Processed tx with signature: {:?}. duration: {elapsed} sec, ret: {ret:?}, is_p2p: \ - {is_p2p}, tx: {:?}", - tx.signature(), - tx + {is_p2p}", + &tx_signature, ); ret @@ -112,10 +112,10 @@ impl Gateway { async fn add_tx_inner( &self, - tx: &RpcTransaction, + tx: RpcTransaction, p2p_message_metadata: Option, ) -> GatewayResult { - let mut metric_counters = GatewayMetricHandle::new(tx, &p2p_message_metadata); + let mut metric_counters = GatewayMetricHandle::new(&tx, &p2p_message_metadata); metric_counters.count_transaction_received(); if let RpcTransaction::Declare(ref declare_tx) = tx { @@ -126,17 +126,16 @@ impl Gateway { } // Perform stateless validations. - self.stateless_tx_validator.validate(tx)?; + self.stateless_tx_validator.validate(&tx)?; let tx_signature = tx.signature().clone(); - let internal_tx = self - .transaction_converter - .convert_rpc_tx_to_internal_rpc_tx(tx.clone()) - .await - .map_err(|e| { - warn!("Failed to convert RPC transaction to internal RPC transaction: {}", e); - transaction_converter_err_to_deprecated_gw_err(&tx_signature, e) - })?; + let internal_tx = + self.transaction_converter.convert_rpc_tx_to_internal_rpc_tx(tx).await.map_err( + |e| { + warn!("Failed to convert RPC transaction to internal RPC transaction: {}", e); + transaction_converter_err_to_deprecated_gw_err(&tx_signature, e) + }, + )?; let executable_tx = self .transaction_converter @@ -162,8 +161,7 @@ impl Gateway { Ok(Err(starknet_err)) => { info!( "Gateway validation failed for tx with signature: {:?} with error: {}", - tx.signature(), - starknet_err + &tx_signature, starknet_err ); metric_counters.record_add_tx_failure(&starknet_err); return Err(starknet_err); @@ -171,7 +169,7 @@ impl Gateway { Err(join_err) => { let err = StarknetError::internal_with_signature_logging( "Failed to process tx", - tx.signature(), + &tx_signature, join_err, ); metric_counters.record_add_tx_failure(&err); @@ -185,10 +183,8 @@ impl Gateway { args: AddTransactionArgs::new(internal_tx, nonce), p2p_message_metadata, }; - match mempool_client_result_to_deprecated_gw_result( - tx.signature(), - self.mempool_client.add_tx(add_tx_args).await, - ) { + let mempool_client_result = self.mempool_client.add_tx(add_tx_args).await; + match mempool_client_result_to_deprecated_gw_result(&tx_signature, mempool_client_result) { Ok(()) => {} Err(e) => { metric_counters.record_add_tx_failure(&e); From 8bb9677cfc3c55ed93203bb39646ea48c71e1200 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Mon, 3 Nov 2025 15:57:22 +0200 Subject: [PATCH 247/313] ci: don't run system test and docker test for prod scripts. They are unrelated. (#9927) --- .github/workflows/hybrid_system_test.yaml | 4 +++- .github/workflows/sequencer_docker-test.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hybrid_system_test.yaml b/.github/workflows/hybrid_system_test.yaml index 0d747de7adf..17ff3780e31 100644 --- a/.github/workflows/hybrid_system_test.yaml +++ b/.github/workflows/hybrid_system_test.yaml @@ -18,6 +18,7 @@ env: cluster_name: hybrid-system-test crate_triggers: "apollo_node,apollo_deployments,apollo_integration_tests" path_triggers: ".github/workflows/hybrid_system_test.yaml,scripts/*.py,scripts/system_tests/**/*.py,deployments/sequencer/**" + path_triggers_exclude: "scripts/prod/**/*" pvc_storage_class_name: "premium-rwo" anvil_port: "8545" dockerfile_base_path: ./deployments/images/sequencer @@ -61,7 +62,8 @@ jobs: python ./scripts/check_test_trigger.py --output_file $OUTPUT_FILE \ --commit_id ${{ github.event.pull_request.base.sha }} \ --crate_triggers ${{ env.crate_triggers }} \ - --path_triggers ${{ env.path_triggers }} + --path_triggers ${{ env.path_triggers }} \ + --path_triggers_exclude ${{ env.path_triggers_exclude }} should_run=$(cat "$OUTPUT_FILE") echo "Captured output: $should_run" diff --git a/.github/workflows/sequencer_docker-test.yml b/.github/workflows/sequencer_docker-test.yml index b4c2c1f0d67..9e2bb94b88a 100644 --- a/.github/workflows/sequencer_docker-test.yml +++ b/.github/workflows/sequencer_docker-test.yml @@ -14,6 +14,7 @@ on: env: crate_triggers: "apollo_node,apollo_dashboard,apollo_integration_tests" path_triggers: ".github/workflows/sequencer_docker-test.yml,scripts/*.py,scripts/system_tests/**/*.py" + path_triggers_exclude: "scripts/prod/**/*" permissions: contents: read @@ -53,7 +54,8 @@ jobs: python ./scripts/check_test_trigger.py --output_file $OUTPUT_FILE \ --commit_id ${{ github.event.pull_request.base.sha }} \ --crate_triggers ${{ env.crate_triggers }} \ - --path_triggers ${{ env.path_triggers }} + --path_triggers ${{ env.path_triggers }} \ + --path_triggers_exclude ${{ env.path_triggers_exclude }} should_run=$(cat "$OUTPUT_FILE") echo "Captured output: $should_run" From 8129c2c150a55e067c0f82c2735d8477bfcd7905 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:03:15 +0200 Subject: [PATCH 248/313] starknet_api: add size limit for decompression (#9859) --- .../src/deprecated_gateway_transaction.rs | 9 ++++-- .../apollo_protobuf/src/converters/class.rs | 7 ++-- crates/apollo_rpc/src/v0_8/api/mod.rs | 1 + crates/starknet_api/src/compression_utils.rs | 32 +++++++++++++++---- .../src/compression_utils_test.rs | 29 +++++++++++++++-- 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/crates/apollo_http_server/src/deprecated_gateway_transaction.rs b/crates/apollo_http_server/src/deprecated_gateway_transaction.rs index cb5281c5e7b..f186f254718 100644 --- a/crates/apollo_http_server/src/deprecated_gateway_transaction.rs +++ b/crates/apollo_http_server/src/deprecated_gateway_transaction.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; #[cfg(any(feature = "testing", test))] use starknet_api::compression_utils::compress_and_encode; -use starknet_api::compression_utils::{decode_and_decompress, CompressionError}; +use starknet_api::compression_utils::{decode_and_decompress_with_size_limit, CompressionError}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::rpc_transaction::{ @@ -282,7 +282,12 @@ impl TryFrom for SierraContractClass { fn try_from( rest_sierra_contract_class: DeprecatedGatewaySierraContractClass, ) -> Result { - let sierra_program = decode_and_decompress(&rest_sierra_contract_class.sierra_program)?; + // TODO(dan): use config for this. + const MAX_SIERRA_PROGRAM_SIZE: usize = 4 * 1024 * 1024; // 4MB + let sierra_program = decode_and_decompress_with_size_limit( + &rest_sierra_contract_class.sierra_program, + MAX_SIERRA_PROGRAM_SIZE, + )?; Ok(SierraContractClass { sierra_program, contract_class_version: rest_sierra_contract_class.contract_class_version, diff --git a/crates/apollo_protobuf/src/converters/class.rs b/crates/apollo_protobuf/src/converters/class.rs index e664554f08f..9b0998be8df 100644 --- a/crates/apollo_protobuf/src/converters/class.rs +++ b/crates/apollo_protobuf/src/converters/class.rs @@ -9,7 +9,7 @@ use papyrus_common::pending_classes::ApiContractClass; use papyrus_common::python_json::PythonJsonFormatter; use prost::Message; use serde::Serialize; -use starknet_api::compression_utils::{compress_and_encode, decode_and_decompress}; +use starknet_api::compression_utils::{compress_and_encode, decode_and_decompress_with_size_limit}; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, EntryPointSelector}; use starknet_api::data_availability::DataAvailabilityMode; @@ -129,7 +129,10 @@ impl TryFrom for deprecated_contract_class::ContractClass ); } let abi = serde_json::from_str(&value.abi)?; - let program = decode_and_decompress(&value.program)?; + // TODO(dan): use config for this. + const MAX_CAIRO0_PROGRAM_SIZE: usize = 4 * 1024 * 1024; // 4MB + let program = + decode_and_decompress_with_size_limit(&value.program, MAX_CAIRO0_PROGRAM_SIZE)?; Ok(Self { program, entry_points_by_type, abi }) } diff --git a/crates/apollo_rpc/src/v0_8/api/mod.rs b/crates/apollo_rpc/src/v0_8/api/mod.rs index ccd892235cf..5d9a1d5ae23 100644 --- a/crates/apollo_rpc/src/v0_8/api/mod.rs +++ b/crates/apollo_rpc/src/v0_8/api/mod.rs @@ -673,6 +673,7 @@ pub(crate) fn decompress_program( base64::decode(base64_compressed_program).map_err(internal_server_error)?; let compressed_data = base64::decode(base64_compressed_program).map_err(internal_server_error)?; + // TODO(dan): add time and size limits. let mut decoder = GzDecoder::new(compressed_data.as_slice()); let mut decompressed = Vec::new(); decoder.read_to_end(&mut decompressed).map_err(internal_server_error)?; diff --git a/crates/starknet_api/src/compression_utils.rs b/crates/starknet_api/src/compression_utils.rs index 43b126d6cbf..5bdba77b125 100644 --- a/crates/starknet_api/src/compression_utils.rs +++ b/crates/starknet_api/src/compression_utils.rs @@ -14,6 +14,8 @@ pub enum CompressionError { Serde(#[from] serde_json::Error), #[error(transparent)] Decode(#[from] base64::DecodeError), + #[error("Decompressed data exceeds maximum size limit of {limit} bytes")] + SizeLimitExceeded { limit: usize }, } /// Compress the value using gzip with the default compression level and encode it in base64. @@ -27,11 +29,29 @@ where Ok(base64::encode(compressed_data)) } -/// Decompress the value from base64 and gzip. -pub fn decode_and_decompress(value: &str) -> Result { +/// Decompresses the provided data with size limits. +fn decompress_with_size_limit( + decoded_data: Vec, + max_size: usize, +) -> Result, CompressionError> { + let decompressor = flate2::read::GzDecoder::new(&decoded_data[..]); + let mut decompressed_data = Vec::new(); + decompressor + .take((max_size + 1).try_into().expect("max_size should be less than usize::MAX")) + .read_to_end(&mut decompressed_data)?; + if decompressed_data.len() > max_size { + return Err(CompressionError::SizeLimitExceeded { limit: max_size }); + } + Ok(decompressed_data) +} + +/// Decodes the provided data with size limits. +// TODO(dan): consider limiting the time it takes to decompress. +pub fn decode_and_decompress_with_size_limit( + value: &str, + max_size: usize, +) -> Result { let decoded_data = base64::decode(value)?; - let mut decompressor = flate2::read::GzDecoder::new(&decoded_data[..]); - let mut decompressed_data = String::new(); - decompressor.read_to_string(&mut decompressed_data)?; - Ok(serde_json::from_str(&decompressed_data)?) + let decompressed_data = decompress_with_size_limit(decoded_data, max_size)?; + Ok(serde_json::from_reader(decompressed_data.as_slice())?) } diff --git a/crates/starknet_api/src/compression_utils_test.rs b/crates/starknet_api/src/compression_utils_test.rs index 01b4434996c..24b4324434a 100644 --- a/crates/starknet_api/src/compression_utils_test.rs +++ b/crates/starknet_api/src/compression_utils_test.rs @@ -1,7 +1,12 @@ +use assert_matches::assert_matches; use pretty_assertions::assert_eq; use starknet_crypto::Felt; -use crate::compression_utils::{compress_and_encode, decode_and_decompress}; +use crate::compression_utils::{ + compress_and_encode, + decode_and_decompress_with_size_limit, + CompressionError, +}; use crate::test_utils::read_json_file; #[test] @@ -16,6 +21,26 @@ fn compress_and_encode_hardcoded_value() { fn decode_and_decompress_hardcoded_value() { let sierra_program_base64: String = read_json_file("sierra_program_base64.json"); let expected_value: Vec = read_json_file("sierra_program.json"); - let value: Vec = decode_and_decompress(&sierra_program_base64).unwrap(); + let serialized_size_of_expected_value = serde_json::to_string(&expected_value).unwrap().len(); + let value: Vec = decode_and_decompress_with_size_limit( + &sierra_program_base64, + serialized_size_of_expected_value, + ) + .unwrap(); assert_eq!(value, expected_value); } + +#[test] +fn decode_and_decompress_hardcoded_value_with_size_limit_exceeded() { + let sierra_program_base64: String = read_json_file("sierra_program_base64.json"); + let expected_value: Vec = read_json_file("sierra_program.json"); + let serialized_size_of_expected_value = serde_json::to_string(&expected_value).unwrap().len(); + let result: Result, CompressionError> = decode_and_decompress_with_size_limit( + &sierra_program_base64, + serialized_size_of_expected_value - 1, + ); + assert_matches!( + result, + Err(CompressionError::SizeLimitExceeded { limit: expected_limit }) if expected_limit == serialized_size_of_expected_value - 1 + ); +} From fc811a3ba0e8754794127dbe374a8be147cd8111 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:18:08 +0200 Subject: [PATCH 249/313] apollo_integration_tests: mine a new block every second (#9704) --- crates/apollo_integration_tests/src/anvil_base_layer.rs | 7 +++++-- crates/apollo_integration_tests/src/flow_test_setup.rs | 2 +- .../src/integration_test_manager.rs | 2 +- .../tests/events_from_other_contracts.rs | 2 +- .../tests/l1_events_scraper_end_to_end.rs | 2 +- .../tests/mocked_starknet_state_update_test.rs | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/crates/apollo_integration_tests/src/anvil_base_layer.rs b/crates/apollo_integration_tests/src/anvil_base_layer.rs index 3b341e0429b..5df300ac65f 100644 --- a/crates/apollo_integration_tests/src/anvil_base_layer.rs +++ b/crates/apollo_integration_tests/src/anvil_base_layer.rs @@ -49,7 +49,7 @@ impl AnvilBaseLayer { /// Note: if you have port conflicts, you might have a zombie anvil instance /// running, but that should be impossible if using through this service, you probably have a /// manually triggered Anvil instance somewhere in your shell. - pub async fn new() -> Self { + pub async fn new(block_time: Option) -> Self { let is_unit_test = cfg!(test); if is_unit_test { panic!( @@ -60,7 +60,10 @@ impl AnvilBaseLayer { } let anvil_client = ProviderBuilder::new() - .connect_anvil_with_wallet_and_config(|anvil| anvil.port(Self::DEFAULT_ANVIL_PORT)) + .connect_anvil_with_wallet_and_config(|anvil| { + let anvil = anvil.port(Self::DEFAULT_ANVIL_PORT); + if let Some(block_time) = block_time { anvil.block_time(block_time) } else { anvil } + }) .unwrap_or_else(|error| match error { AnvilError::SpawnError(e) if e.to_string().contains("No such file or directory") => diff --git a/crates/apollo_integration_tests/src/flow_test_setup.rs b/crates/apollo_integration_tests/src/flow_test_setup.rs index f7f122c9c3e..de2926e2511 100644 --- a/crates/apollo_integration_tests/src/flow_test_setup.rs +++ b/crates/apollo_integration_tests/src/flow_test_setup.rs @@ -121,7 +121,7 @@ impl FlowTestSetup { .try_into() .unwrap(); - let anvil_base_layer = AnvilBaseLayer::new().await; + let anvil_base_layer = AnvilBaseLayer::new(None).await; let base_layer_url = anvil_base_layer.get_url().await.unwrap(); let base_layer_config = anvil_base_layer.ethereum_base_layer.config.clone(); diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index 1bd849f3d40..fff19006660 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -293,7 +293,7 @@ impl IntegrationTestManager { let l1_gas_price_scraper_config = get_l1_gas_price_scraper_config(sequencers_setup.first().unwrap()); - let anvil_base_layer = AnvilBaseLayer::new().await; + let anvil_base_layer = AnvilBaseLayer::new(Some(1)).await; // Send some transactions to L1 so it has a history of blocks to scrape gas prices from. let num_blocks_needed_on_l1 = l1_gas_price_scraper_config.number_of_blocks_for_mean + l1_gas_price_scraper_config.finality; diff --git a/crates/apollo_integration_tests/tests/events_from_other_contracts.rs b/crates/apollo_integration_tests/tests/events_from_other_contracts.rs index da17b812b90..89fdcc07ea0 100644 --- a/crates/apollo_integration_tests/tests/events_from_other_contracts.rs +++ b/crates/apollo_integration_tests/tests/events_from_other_contracts.rs @@ -14,7 +14,7 @@ use starknet_api::{calldata, contract_address, felt}; async fn events_from_other_contract() { const EVENT_IDENTIFIERS: &[EventIdentifier] = &[LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER]; - let anvil_base_layer = AnvilBaseLayer::new().await; + let anvil_base_layer = AnvilBaseLayer::new(None).await; // Anvil base layer already auto-deployed a starknet contract. let this_contract = &anvil_base_layer.ethereum_base_layer.contract; diff --git a/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs index c1ae3904df3..76d64dd1d22 100644 --- a/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs +++ b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs @@ -22,7 +22,7 @@ use starknet_api::transaction::{L1HandlerTransaction, TransactionHasher, Transac #[tokio::test] async fn scraper_end_to_end() { // Setup. - let base_layer = AnvilBaseLayer::new().await; + let base_layer = AnvilBaseLayer::new(None).await; let contract = &base_layer.ethereum_base_layer.contract; let mut l1_provider_client = MockL1ProviderClient::default(); diff --git a/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs b/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs index d65f388cdbc..dcb659b610d 100644 --- a/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs +++ b/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs @@ -10,7 +10,7 @@ use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; #[tokio::test] async fn test_mocked_starknet_state_update() { - let base_layer = AnvilBaseLayer::new().await; + let base_layer = AnvilBaseLayer::new(None).await; // Check that the contract was initialized (during the construction above). let no_finality = 0; From 608758b27c22051af87e97cb9d1147f4a3d1736f Mon Sep 17 00:00:00 2001 From: einat-starkware Date: Mon, 3 Nov 2025 17:38:43 +0200 Subject: [PATCH 250/313] starknet_os: add blob utils (#9904) --- .../src/hints/hint_implementation/kzg/test.rs | 31 +++++++++++++++++++ .../hints/hint_implementation/kzg/utils.rs | 27 ++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/test.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/test.rs index 79b3f674645..5d108b1d558 100644 --- a/crates/starknet_os/src/hints/hint_implementation/kzg/test.rs +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/test.rs @@ -1,6 +1,7 @@ use std::sync::LazyLock; use ark_bls12_381::Fr; +use ark_ff::{BigInteger, PrimeField}; use c_kzg::KzgCommitment; use num_bigint::BigUint; use num_traits::{Num, One, Zero}; @@ -9,6 +10,8 @@ use starknet_types_core::felt::Felt; use crate::hints::hint_implementation::kzg::utils::{ bit_reversal, + decode_blobs, + deserialize_blob, polynomial_coefficients_to_blob, serialize_blob, split_commitment, @@ -108,3 +111,31 @@ fn test_fft_blob_regression(#[case] input: Vec, #[case] expected_output: &Ve let bytes = polynomial_coefficients_to_blob(input).unwrap(); assert_eq!(&bytes, expected_output); } + +#[rstest] +fn test_serialize_deserialize_blob() { + let blob: Vec = (1..=FIELD_ELEMENTS_PER_BLOB).map(|i| Fr::from(BigUint::from(i))).collect(); + let bytes = serialize_blob(&blob).unwrap(); + let deserialized_blob = deserialize_blob(&bytes); + assert_eq!(deserialized_blob, blob); +} + +#[rstest] +#[case::simple(vec![Fr::from(1_u8), Fr::from(2_u8), Fr::from(3_u8)])] +#[case::zero(vec![Fr::zero()])] +#[case::one(vec![Fr::one()])] +#[case::regression(BLOB_REGRESSION_INPUT.to_vec())] +fn test_decode_blobs(#[case] coefficients: Vec) { + let raw_blob = polynomial_coefficients_to_blob(coefficients.clone()).unwrap(); + let decoded = decode_blobs(vec![raw_blob]).unwrap(); + let mut expected = coefficients.clone(); + expected.resize(FIELD_ELEMENTS_PER_BLOB, Fr::zero()); + let expected_felt: Vec = expected + .iter() + .map(|fr| { + let bytes = fr.into_bigint().to_bytes_be(); + Felt::from_bytes_be_slice(&bytes) + }) + .collect(); + assert_eq!(decoded, expected_felt); +} diff --git a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs index 832d6bec479..8ef14b0715b 100644 --- a/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs +++ b/crates/starknet_os/src/hints/hint_implementation/kzg/utils.rs @@ -75,6 +75,10 @@ pub(crate) fn serialize_blob(blob: &[Fr]) -> Result, FftError> { .collect()) } +pub(crate) fn deserialize_blob(raw_blob: &[u8]) -> Vec { + raw_blob.chunks(BYTES_PER_FIELD_ELEMENT).map(BigUint::from_bytes_be).map(Fr::from).collect() +} + pub(crate) fn split_commitment(commitment: &KzgCommitment) -> Result<(Felt, Felt), FftError> { let commitment_bytes: [u8; COMMITMENT_BYTES_LENGTH] = *commitment.to_bytes().as_ref(); @@ -263,3 +267,26 @@ pub fn compute_blob_commitments(raw_blobs: Vec>) -> Result>) -> Result, FftError> { + let mut result = Vec::new(); + + for raw_blob in raw_blobs.iter() { + let mut coeffs = deserialize_blob(raw_blob); + + if coeffs.len() != FIELD_ELEMENTS_PER_BLOB { + return Err(FftError::InvalidBlobSize(coeffs.len())); + } + + bit_reversal(&mut coeffs)?; + let domain = Radix2EvaluationDomain::::new(FIELD_ELEMENTS_PER_BLOB) + .ok_or(FftError::EvalDomainCreation)?; + domain.ifft_in_place(&mut coeffs); + + for fr_elem in coeffs { + let bytes = fr_elem.into_bigint().to_bytes_be(); + result.push(Felt::from_bytes_be_slice(&bytes)); + } + } + Ok(result) +} From 7be55d785e2a325ebd8bc014ffdbf2e5d5043cc3 Mon Sep 17 00:00:00 2001 From: noamsp-starkware Date: Tue, 4 Nov 2025 10:23:57 +0200 Subject: [PATCH 251/313] apollo_state_sync: test get_block_hash with starknet_client fallback (#9933) --- Cargo.lock | 1 + crates/apollo_state_sync/Cargo.toml | 2 ++ crates/apollo_state_sync/src/lib.rs | 1 - crates/apollo_state_sync/src/test.rs | 34 ++++++++++++++++++++++++++-- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1774be624d2..f2eada046fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2448,6 +2448,7 @@ dependencies = [ "futures", "indexmap 2.11.0", "libp2p", + "mockall", "papyrus_common", "rand_chacha 0.3.1", "starknet-types-core", diff --git a/crates/apollo_state_sync/Cargo.toml b/crates/apollo_state_sync/Cargo.toml index 3bd806359f5..d1699c33179 100644 --- a/crates/apollo_state_sync/Cargo.toml +++ b/crates/apollo_state_sync/Cargo.toml @@ -34,8 +34,10 @@ tokio.workspace = true tracing.workspace = true [dev-dependencies] +apollo_starknet_client = { workspace = true, features = ["testing"] } apollo_storage = { workspace = true, features = ["testing"] } apollo_test_utils.workspace = true indexmap = { workspace = true, features = ["serde"] } libp2p.workspace = true +mockall.workspace = true rand_chacha.workspace = true diff --git a/crates/apollo_state_sync/src/lib.rs b/crates/apollo_state_sync/src/lib.rs index 9176f498fbc..dfb4f18da54 100644 --- a/crates/apollo_state_sync/src/lib.rs +++ b/crates/apollo_state_sync/src/lib.rs @@ -160,7 +160,6 @@ impl StateSync { (Err(StateSyncError::BlockNotFound(_)), Some(starknet_client)) => { // As a fallback, try to get the block hash through the feeder directly. This // method is faster than get_block which the sync runner uses. - // TODO(shahak): Test this flow. starknet_client .block_hash(block_number) .await? diff --git a/crates/apollo_state_sync/src/test.rs b/crates/apollo_state_sync/src/test.rs index 8e7266df3ec..850742153a5 100644 --- a/crates/apollo_state_sync/src/test.rs +++ b/crates/apollo_state_sync/src/test.rs @@ -1,5 +1,7 @@ -// TODO(shahak): Test is_class_declared_at. +use std::sync::Arc; + use apollo_infra::component_definitions::ComponentRequestHandler; +use apollo_starknet_client::reader::{MockStarknetReader, StarknetReader}; use apollo_state_sync_types::communication::{StateSyncRequest, StateSyncResponse}; use apollo_state_sync_types::errors::StateSyncError; use apollo_storage::body::BodyStorageWriter; @@ -10,9 +12,11 @@ use apollo_storage::StorageWriter; use apollo_test_utils::{get_rng, get_test_block, get_test_state_diff, GetTestInstance}; use futures::channel::mpsc::channel; use indexmap::IndexMap; +use mockall::predicate; use rand_chacha::rand_core::RngCore; -use starknet_api::block::{Block, BlockHeader, BlockNumber}; +use starknet_api::block::{Block, BlockHash, BlockHeader, BlockNumber}; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::hash::StarkHash; use starknet_api::state::{StorageKey, ThinStateDiff}; use starknet_types_core::felt::Felt; @@ -102,6 +106,32 @@ async fn test_get_block_hash() { assert_eq!(block_hash, expected_header.block_hash); } +#[tokio::test] +async fn test_get_block_hash_fallback_to_starknet_client() { + let mut starknet_client = MockStarknetReader::new(); + let block_number = BlockNumber(100); + let expected_block_hash = BlockHash(StarkHash::from_hex_unchecked("0x123")); + starknet_client + .expect_block_hash() + .with(predicate::eq(block_number)) + .times(1) + .returning(move |_block_number| Ok(Some(expected_block_hash))); + + let starknet_client: Option> = + Some(Arc::new(starknet_client)); + let ((storage_reader, _storage_writer), _) = get_test_storage(); + let mut state_sync = + StateSync { storage_reader, new_block_sender: channel(0).0, starknet_client }; + + // The block is not in storage, so it should fall back to starknet_client + let response = state_sync.handle_request(StateSyncRequest::GetBlockHash(block_number)).await; + let StateSyncResponse::GetBlockHash(Ok(block_hash)) = response else { + panic!("Expected StateSyncResponse::GetBlockHash::Ok(_), but got {response:?}"); + }; + + assert_eq!(block_hash, expected_block_hash); +} + #[tokio::test] async fn test_get_storage_at() { let (mut state_sync, mut storage_writer) = setup(); From bb352ac1ad7d50c97cf57ff0b03a53a886ff571d Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Tue, 4 Nov 2025 10:24:34 +0200 Subject: [PATCH 252/313] apollo_state_sync: fix bug in state sync get_block_hash (#9879) --- crates/apollo_state_sync/src/lib.rs | 21 ++++++++++++++++----- crates/apollo_state_sync/src/test.rs | 7 ++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/crates/apollo_state_sync/src/lib.rs b/crates/apollo_state_sync/src/lib.rs index dfb4f18da54..65c197e4b3c 100644 --- a/crates/apollo_state_sync/src/lib.rs +++ b/crates/apollo_state_sync/src/lib.rs @@ -154,10 +154,21 @@ impl StateSync { } async fn get_block_hash(&self, block_number: BlockNumber) -> StateSyncResult { - // Getting the next block because the Sync block only contains parent hash. - match (self.get_block(block_number).await, self.starknet_client.as_ref()) { - (Ok(block), _) => Ok(block.block_header_without_hash.parent_hash), - (Err(StateSyncError::BlockNotFound(_)), Some(starknet_client)) => { + // Attempt reading the block hash from the storage. + let storage_reader = self.storage_reader.clone(); + let block_hash_opt = tokio::task::spawn_blocking(move || { + Ok::<_, StateSyncError>( + storage_reader + .begin_ro_txn()? + .get_block_header(block_number)? + .map(|header| header.block_hash), + ) + }) + .await??; + + match (block_hash_opt, self.starknet_client.as_ref()) { + (Some(block_hash), _) => Ok(block_hash), + (None, Some(starknet_client)) => { // As a fallback, try to get the block hash through the feeder directly. This // method is faster than get_block which the sync runner uses. starknet_client @@ -165,7 +176,7 @@ impl StateSync { .await? .ok_or(StateSyncError::BlockNotFound(block_number)) } - (Err(err), _) => Err(err), + (None, None) => Err(StateSyncError::BlockNotFound(block_number)), } } diff --git a/crates/apollo_state_sync/src/test.rs b/crates/apollo_state_sync/src/test.rs index 850742153a5..d53932b727c 100644 --- a/crates/apollo_state_sync/src/test.rs +++ b/crates/apollo_state_sync/src/test.rs @@ -76,9 +76,14 @@ async fn test_get_block() { async fn test_get_block_hash() { let (mut state_sync, mut storage_writer) = setup(); - let Block { header: expected_header, body: expected_body } = + let Block { header: mut expected_header, body: expected_body } = get_test_block(1, None, None, None); + // get_test_block returns a block with parent_hash == block_hash. Need to change that to make + // sure we don't return the parent hash + expected_header.block_hash.0 = + expected_header.block_header_without_hash.parent_hash.0 + Felt::from(1); + storage_writer .begin_rw_txn() .unwrap() From efa31c19f2a031714d0d9318ab7ef96f6ed0af38 Mon Sep 17 00:00:00 2001 From: asmaa-starkware <163830216+asmaastarkware@users.noreply.github.com> Date: Tue, 4 Nov 2025 10:45:54 +0200 Subject: [PATCH 253/313] apollo_time: gate sleep_until behind tokio feature (#9940) --- crates/apollo_time/src/time.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/apollo_time/src/time.rs b/crates/apollo_time/src/time.rs index 40f41583c90..d18c9447e9a 100644 --- a/crates/apollo_time/src/time.rs +++ b/crates/apollo_time/src/time.rs @@ -19,6 +19,7 @@ pub trait Clock: Send + Sync + Debug { } pub trait ClockExt: Clock { + #[cfg(feature = "tokio")] fn sleep_until<'a>( &'a self, deadline: DateTime, From 0e921bdb09502aa45b924136e2c12e6620382938 Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:28:37 +0200 Subject: [PATCH 254/313] apollo_state_sync: add TODO to remove spawn blocking (#9939) --- crates/apollo_state_sync/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/apollo_state_sync/src/lib.rs b/crates/apollo_state_sync/src/lib.rs index 65c197e4b3c..1f276f54a83 100644 --- a/crates/apollo_state_sync/src/lib.rs +++ b/crates/apollo_state_sync/src/lib.rs @@ -119,6 +119,7 @@ impl ComponentRequestHandler for StateSync impl StateSync { async fn get_block(&self, block_number: BlockNumber) -> StateSyncResult { let storage_reader = self.storage_reader.clone(); + // TODO(Tsabary): remove spawn blocking from this file. tokio::task::spawn_blocking(move || { let txn = storage_reader.begin_ro_txn()?; From b0664282f2d3c0a0334d8bfcf2dad11587eacf4e Mon Sep 17 00:00:00 2001 From: noamsp-starkware Date: Tue, 4 Nov 2025 13:28:39 +0200 Subject: [PATCH 255/313] Revert "apollo_gateway: whitelist classes declared by deploy as always declared (#9402)" (#9932) --- .../apollo_gateway/src/sync_state_reader.rs | 149 +----------------- .../src/sync_state_reader_test.rs | 9 +- 2 files changed, 2 insertions(+), 156 deletions(-) diff --git a/crates/apollo_gateway/src/sync_state_reader.rs b/crates/apollo_gateway/src/sync_state_reader.rs index c0b9a821019..01f95161a48 100644 --- a/crates/apollo_gateway/src/sync_state_reader.rs +++ b/crates/apollo_gateway/src/sync_state_reader.rs @@ -17,12 +17,10 @@ use blockifier::execution::contract_class::RunnableCompiledClass; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader as BlockifierStateReader, StateResult}; use futures::executor::block_on; -use lazy_static::lazy_static; use starknet_api::block::{BlockHash, BlockInfo, BlockNumber, GasPriceVector, GasPrices}; use starknet_api::contract_class::ContractClass; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::data_availability::L1DataAvailabilityMode; -use starknet_api::felt; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; @@ -125,16 +123,11 @@ impl BlockifierStateReader for SyncStateReader { } fn get_compiled_class(&self, class_hash: ClassHash) -> StateResult { - let mut is_class_declared = self + let is_class_declared = self .runtime .block_on(self.state_sync_client.is_class_declared_at(self.block_number, class_hash)) .map_err(|e| StateError::StateReadError(e.to_string()))?; - // TODO(shahak): Remove this once we've resynced all production nodes. - if OLD_DEPLOY_CLASS_HASH_WHITELIST.contains(&class_hash) { - is_class_declared = true; - } - if !is_class_declared { return Err(StateError::UndeclaredClassHash(class_hash)); } @@ -306,143 +299,3 @@ impl StateReaderFactory for SyncStateReaderFactory { ))) } } - -lazy_static! { - pub(crate) static ref OLD_DEPLOY_CLASS_HASH_WHITELIST: [ClassHash; 135] = [ - ClassHash(felt!("00a4e57ac025a86e283b7ef0132a6543305600788b783ba6fb48426703a5abbf")), - ClassHash(felt!("03f43dfee1c6e5c33065a714535e06a8ffd7e76a12bb74ed9093946be6c2d798")), - ClassHash(felt!("0726edb35cc732c1b3661fd837592033bd85ae8dde31533c35711fb0422d8993")), - ClassHash(felt!("07ab58843a19e516c83057cd49beaba917aa9477cab703b3c6ae1ab9d822c4b1")), - ClassHash(felt!("07f1c7e439328634d159aeb68f1b40b74f7a05da3832515561e77aadaf57a591")), - ClassHash(felt!("0157d87bdad1328cbf429826a83545f6ffb6505138983885a75997ee2c49e66b")), - ClassHash(felt!("075da0ac40ebc084e87ba5f22f1c2743a9e7e85d88dc795d0379cd00d04a7072")), - ClassHash(felt!("07b5e991587f0c59db1c4c4ff9b26fa8ec49198ca6d8a82823cc2c6177d918fa")), - ClassHash(felt!("0665d8f3ff5d12d8e1f4bcfea7b54f10eb5fe294cac5a428d6549eba08e00451")), - ClassHash(felt!("07595b4f7d50010ceb00230d8b5656e3c3dd201b6df35d805d3f2988c69a1432")), - ClassHash(felt!("03ec0f1fa8614a821596bae6ecbacca66b52b5c1c92fe1a950656b9a3beaf012")), - ClassHash(felt!("0631217418b8965601291874c906989517fa934babbce7a7ea18a7668c7c6304")), - ClassHash(felt!("05d9a7bdec373b49efef91c6da3d595a96e1a5e8302bc62c7c8ac7df730e751d")), - ClassHash(felt!("020c279bb3d77dce970cf5dc98341251bbc20eb021d029a8fd28020a4bd9c3c1")), - ClassHash(felt!("0733734fa0dab1158bccdfe0df7b0becf3827f908971fac8d39cc73d99ad8645")), - ClassHash(felt!("0784f488f47e20acfc738456581c2c7d34e7a0b74b040a8ab347f24f10c00b6e")), - ClassHash(felt!("04d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f")), - ClassHash(felt!("069236f4ab1d052ca50b7574436e6a6b760503d7973bb7133255a2676c1bdb69")), - ClassHash(felt!("008b12f11b1ea5e43cdf8870be6a0579e920873a83c4b8931a27abc4c032ee64")), - ClassHash(felt!("039547c16c9ca7ab54882da944161eb7b13805e5dbb01dab45d814baada6f282")), - ClassHash(felt!("0626424ef94979b877311ac1be3099b2021977d281e5c8c66acc92b40ba1e1df")), - ClassHash(felt!("057a4fbfcfcde85f3d99ca1053266cb29c513856fd2a758df6774def2101e677")), - ClassHash(felt!("023d98a23d5f542269486edc2b9c0394cc510a9862c3f3ea82fa0798269ee0bc")), - ClassHash(felt!("008d8726481b7b8a4a8f95aa2ce6a18932c33148600c75b1b4fe40c5987c6c9a")), - ClassHash(felt!("04c53698c9a42341e4123632e87b752d6ae470ddedeb8b0063eaa2deea387eeb")), - ClassHash(felt!("066a3ec9166b2b39de4bb5f46dee36998c29d2ae3bc61bd1187fb11fa676555b")), - ClassHash(felt!("046f844ea1a3b3668f81d38b5c1bd55e816e0373802aefe732138628f0133486")), - ClassHash(felt!("04e709a7d569e5b041f46e0d4d654cbf96d8b4749088705892d4e6969dff3e35")), - ClassHash(felt!("029d2cc5f6beac7fef596a256c8bd3a0eb0f83248886599ec80ee72133d747eb")), - ClassHash(felt!("017eddd685efc7966e9ceb26d5ccf58180f802c72f06f1a1bff1c4d74a59c872")), - ClassHash(felt!("03131fa018d520a037686ce3efddeab8f28895662f019ca3ca18a626650f7d1e")), - ClassHash(felt!("06dadf634444dfa550750191a1b8ba77970d0f11bea3df469c968bb59ba73158")), - ClassHash(felt!("002f09c8cc7698d6a220b929b525efd5b3622a7658e9a9e4c8a52d5ed995d6fe")), - ClassHash(felt!("07e35b811e3d4e2678d037b632a0c8a09a46d82185187762c0d429363e3ef9cf")), - ClassHash(felt!("0042477e2f668af48c85770ffc9ececcd39d5aaf077da491a5bdc6204f71bdb6")), - ClassHash(felt!("02c3348ad109f7f3967df6494b3c48741d61675d9a7915b265aa7101a631dc33")), - ClassHash(felt!("04a153d1ef11d0bdff01e51ae866e7a8c66f2e968cfeabcb30793220b5910e2f")), - ClassHash(felt!("07d32ee16204aef3a9e4ed9b8b681fda37ab299e29fe1b21413ce3768d4e4a76")), - ClassHash(felt!("060924bf85cdd22c7e24cf8b6ac45a9a6b753671dfd0da07aae5d6b3c65a05e2")), - ClassHash(felt!("070aa6f103ec0e73e7acb691f0f05208d6b1cd67c309e22f4e2605db109600f1")), - ClassHash(felt!("027f27c5dcec1611d303e65ddb12acc92def6202203c5b3f8762855306d01065")), - ClassHash(felt!("010455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8")), - ClassHash(felt!("008dbcb158b134f80d7cdfc2afe7c1fca21de99865d41b9b17bc3303432e8c51")), - ClassHash(felt!("01cb96b938da26c060d5fd807eef8b580c49490926393a5eeb408a89f84b9b46")), - ClassHash(felt!("04e6d8a7f0b6178e2e8f0789e34925fe425b761b0bb608916b0d86531c65c16d")), - ClassHash(felt!("0167470236540c4537a005a1d1cabc08e7ebb10a6f75c9a1d1171a131e41a95b")), - ClassHash(felt!("033143c31c75a787ebdb16a3d9400e0d1a71fbeac2a067793bf93c289d56b03b")), - ClassHash(felt!("0399f629212fd7f2f06723f84340fddd48720c6a1bc19c159313138520a097d5")), - ClassHash(felt!("05605533726157c4b3aa2213365539cad99273b993bc35e91043a8cae42cd402")), - ClassHash(felt!("026033711f79998aadcaee45eab3d8b7d04d83f2efb3334cf38db1fbd947339e")), - ClassHash(felt!("07c44f58c7a0f03c74f96ba5cfd4e3b1036411d5cca1e65695ef1ae11751414d")), - ClassHash(felt!("07c8296b1c53c8000b10f54c5b2aa6a36dd4a69b1074dafdf7d0215403ae3e27")), - ClassHash(felt!("01ba5d32901bb498ab120297923786da8f3425d2ad518c3ceedf9fa2723a0eaa")), - ClassHash(felt!("02dbfa1499840ded1107c63d3ddf4612e0765ef69d511ddaaebc6bf91bb1388d")), - ClassHash(felt!("034de8f05f757772514aafe058245731ba93796cbcf1274fca6ba1d04eeac950")), - ClassHash(felt!("00d0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3")), - ClassHash(felt!("055dd147f5ac39904b109b7407396529ab6defb8feef46a147e742accd6f8795")), - ClassHash(felt!("011eb881c6330b42c1d6d0d37581c134ab51235850bebbc604ebf96ef8dea5d7")), - ClassHash(felt!("0037150ba6f2ccb3a19a45ebe2de28e85b21dbdcaf77436f4e0cdf686a109989")), - ClassHash(felt!("048498ebae1afc22157322db4bb7814b668c7ee20237cc8be64d934649679da1")), - ClassHash(felt!("07543f8eb21f10b1827a495084697a519274ac9c1a1fbf931bac40133a6b9c15")), - ClassHash(felt!("048a7114e47629575c260b184686018c61c34055fefc53f6c100dedf3bc10eba")), - ClassHash(felt!("00edf4a4a2928afc19b038ab799899e0e179c7abdd86f5f1c0c5dd1b307a6b96")), - ClassHash(felt!("039a43c9b60a8f5f8de4c06a163b3f24bf9e59f1a889c323ba5b5578b1d90d95")), - ClassHash(felt!("0064aaf619d5b32b5496cb17d64ad38f390598442d6ac9a2d72c6280b863efba")), - ClassHash(felt!("0639a9186c8d9daa7c44186e7cf987cc458a46965e2658d27020554f9671677b")), - ClassHash(felt!("071c3c99f5cf76fc19945d4b8b7d34c7c5528f22730d56192b50c6bbfd338a64")), - ClassHash(felt!("078dac186418f94cb1eb2a32ed909a6e81028ce8b40b9ec0fe7f6fe4e11addd8")), - ClassHash(felt!("07d72193cd1a0a4ae7ad8b478bc7c431ce0af2803d20726253eb3e18f13f39f6")), - ClassHash(felt!("03115d29825b1a3563ada334fd4b55b36bef7f9ed01e76abe9fd0d4be616a1a7")), - ClassHash(felt!("0621b53649ddc3170f4c7db984252e9de2fd54c8080686aa9aaf5803194a9179")), - ClassHash(felt!("0750cd490a7cd1572411169eaa8be292325990d33c5d4733655fe6b926985062")), - ClassHash(felt!("071b7f73b5e2b4f81f7cf01d4d1569ccba2921b3fa3170cf11cff3720dfe918e")), - ClassHash(felt!("02895b8c4c21ed47527fa779bab13857247580553dc9f66f0a6f2146110a5a29")), - ClassHash(felt!("05915aa48a8b558dacbab894ff2e0062c6957b0b01ae89b2c609f905b7f4e19d")), - ClassHash(felt!("07122c9477ac445f6bf217176b5bc0e2d059b86f32f914a7500d9fd8f24e38ef")), - ClassHash(felt!("05e5bad04b75726fb33f4f146193ab9640a80d9fbc8f2a569192efb086b72307")), - ClassHash(felt!("031008229e9725331feb1ceff338c0e355139de300935285c2e3b76025c4abd0")), - ClassHash(felt!("026fe8ea36ec7703569cfe4693b05102940bf122647c4dbf0abc0bb919ce27bd")), - ClassHash(felt!("022a7efd343b272e499c4ae2c4250f9d345ec50a1daae97cfced921c99775ff9")), - ClassHash(felt!("014eb6c9903997faff3ad620aed584f2d0dccba5c5a016863c14228b319e09ec")), - ClassHash(felt!("00d245a36e35446ccff2ac0c6bf8d1054c970b3f5f8567113e9985724009be5a")), - ClassHash(felt!("03bcf9bad9f636f13527bde8273473314eac6f428956c03fadae1c247d03633f")), - ClassHash(felt!("00655101fb9a3c803a50de65fe9e347a71300e0f9db058da5b8ddebca2681a93")), - ClassHash(felt!("0142f4510d6a58a01091bc5ac9273535868ef6e5c8ac579ad6970c479e0553f1")), - ClassHash(felt!("06b4ee05bc5d19e932c20e5ffc2c184f1d844627a3bfebba1f0d03a2f811145f")), - ClassHash(felt!("06a1776964b9f991c710bfe910b8b37578b32b26a7dffd1669a1a59ac94bf82f")), - ClassHash(felt!("02073b7903c36c9c126c580da737b5b80bd5d77b856ae2b3906a412bbbf47480")), - ClassHash(felt!("044b511cbb25497a1534b4d821a347563a336a3955024a263786b3f19d639c11")), - ClassHash(felt!("03b2a3daa8c6f39fa07ad9847595f1841325ae7a993d6f1919f364235fd62a4b")), - ClassHash(felt!("049c599d777d52365e0e300a24067a0c420776929d398e760660170cb2212248")), - ClassHash(felt!("02cdf5ac65a41b135969dcefa9d52799a48994d4d3aee24732b78580a9fa7c63")), - ClassHash(felt!("06e26cd8efb04ca3ebb27d7b7ce32b2c6668316f26b8569f5c1cf497f27b259b")), - ClassHash(felt!("05829a410055a7da53295c05b7ce39f1b99c202d49f6194ca000d93d35adf491")), - ClassHash(felt!("07b553907c45d4be5b72a7816068518f1a1e326cef33fb1d244852965da6e8eb")), - ClassHash(felt!("0031da92cf5f54bcb81b447e219e2b791b23f3052d12b6c9abd04ff2e5626576")), - ClassHash(felt!("041efe53a722b4325d7f86b97c24b41eb6d16b98ae8a3f3374a8422033666a3e")), - ClassHash(felt!("01a315bf4e9fb59fe57c20b3d959ede354c12786e315fc4c656a7112659aa31f")), - ClassHash(felt!("07e24e482a41ba9c85e74fa62755f8dc1e378ba451cb9da2e89975d13dfa3117")), - ClassHash(felt!("04d1f4cf4ef520c768a326d34f919227e1f075effda532f57cbaec6a1228db88")), - ClassHash(felt!("00cc97194621de7ad998d64cda4554ef35c4e8931940997b2629e743eaccb4a7")), - ClassHash(felt!("00631071be7e7f42a5445af1a4bd30f97b90495f9cb4a8a82d5a94eb08a25a1f")), - ClassHash(felt!("066cc273d328e53eb56b3788684d22062bbe1a915c04594a476b33225d4ab1f4")), - ClassHash(felt!("074a7ed7f1236225600f355efe70812129658c82c295ff0f8307b3fad4bf09a9")), - ClassHash(felt!("03e44a8ce106126fbe5e777db2ca6faa7f53665e0c3d67b5794d5d95874e7472")), - ClassHash(felt!("078a6a24cd6406b3f170fd99db0d2157618203180d79c5c6807bcf633972180d")), - ClassHash(felt!("00c6529e402abdc91cc51f61ae71df2337bc6c535fd96eb79235b1a32bbc6fdc")), - ClassHash(felt!("06921d057693ea95d25883c8e0ba59d047497c23083384d95cd5937c01ae22f6")), - ClassHash(felt!("04225e15fc63c5b127e47238c9be8a403c1c75488eab215210126bcbdc48aec5")), - ClassHash(felt!("074ddc960b4568092956dade86c2919a6f5c06524beefcb5a0a7b25ee3db250c")), - ClassHash(felt!("02f885b664728291d97d8e4b27df3af8c58b69514fd825782153db9c32009763")), - ClassHash(felt!("07797ede55ea525e24078b973467b40850311f9de31913fa13fc5ef92305d849")), - ClassHash(felt!("068bb00f783b88aeb61551f5383e6b7f1621463cb570e8f63df89e3681045134")), - ClassHash(felt!("02f07cff96aff7147d4434d5cba381b75fe3d77d6b1e7f9fdd94845761afd452")), - ClassHash(felt!("0550a4b8f65f1fc1abd9f93527460c252e5a17fb2af1b5f46c981c7a646b707e")), - ClassHash(felt!("057473cd614625f7bc6998840cd2c62fe4fff39834322ac74c16eb6aa2b8f2d3")), - ClassHash(felt!("03f7a4ce5403d3a7417d9115a0982bf4bf2bc86bbfd881506a2fb466e41a8575")), - ClassHash(felt!("05d26d8883e71933c33db502cc874c6366d536970d1a399ee3a5624c94022cb2")), - ClassHash(felt!("07197021c108b0cc57ae354f5ad02222c4b3d7344664e6dd602a0e2298595434")), - ClassHash(felt!("0228a118243209dfe39069d25be535590435227e4df558cbcc54e70913b515d3")), - ClassHash(felt!("033f02ceeb057e36174b12a640376e5ade0c16a31a20ea129e7601160f85d383")), - ClassHash(felt!("04e840d1641e38c1f32d57ff062804c8666823f541a508b341651c8fa9d942dd")), - ClassHash(felt!("025529e95e8f10bef74fb4adb395652ccba2707d98e7eaa114a234f12385b447")), - ClassHash(felt!("02693dd12b58ce4da887ee9530a79c71bdeb739cf888ae9528f58d513abbd336")), - ClassHash(felt!("0710c5eedefc2c2e2dff5d6c432fda3e1e4af93579a3dbb7ee55cf260fadd543")), - ClassHash(felt!("06d135aff146d54d4dea40cdd0588845788468d1cdc0bddf5138d98567d3a7c3")), - ClassHash(felt!("01d492f0765a73712d0cd6654433945c8ac5b3409862cff41e7260315517747b")), - ClassHash(felt!("055dd2a2cf55321ff7130d68fc941a0d887b19e46eff6eae4a13b1f02bc231f6")), - ClassHash(felt!("0108a32ec851d37c8f15387dadc87dc80c302c5278b24211ea5b227a4bfdc752")), - ClassHash(felt!("071891339979b295508cd61a8477959484b955c08a617cec54ade3ccedf63762")), - ClassHash(felt!("0248339769e0b06b7d259bcaec19756d883c8610770c4f77c750a04f2401ea3b")), - ClassHash(felt!("04c2879de40a4af38083026ebf92c40dc674d7148b2369f2adb1ca155b995c30")), - ClassHash(felt!("05cc0c9569aa4e7845780a3359c88f847003bbf8bede6a55bad96da7b9fb4d50")), - ClassHash(felt!("04572af1cd59b8b91055ebb78df8f1d11c59f5270018b291366ba4585d4cdff0")), - ClassHash(felt!("05109f0f2e1db1a9977f4e59361041fd4b63988aa8bee898becb47f87307cfd4")), - ]; -} diff --git a/crates/apollo_gateway/src/sync_state_reader_test.rs b/crates/apollo_gateway/src/sync_state_reader_test.rs index efa02316d17..c36d474dfe1 100644 --- a/crates/apollo_gateway/src/sync_state_reader_test.rs +++ b/crates/apollo_gateway/src/sync_state_reader_test.rs @@ -31,7 +31,7 @@ use starknet_api::data_availability::L1DataAvailabilityMode; use starknet_api::{class_hash, contract_address, felt, nonce, storage_key}; use crate::state_reader::MempoolStateReader; -use crate::sync_state_reader::{SyncStateReader, OLD_DEPLOY_CLASS_HASH_WHITELIST}; +use crate::sync_state_reader::SyncStateReader; #[tokio::test] async fn test_get_block_info() { let mut mock_state_sync_client = MockStateSyncClient::new(); @@ -243,13 +243,6 @@ fn assert_eq_state_result( Err(StateError::UndeclaredClassHash(*DUMMY_CLASS_HASH)), *DUMMY_CLASS_HASH, )] -// TODO(shahak): Put cairo 0 class here to better illustrate the possible scenario. -#[case::class_in_whitelist( - Ok(Some(ContractClass::V1((dummy_casm_contract_class(), SierraVersion::default())))), - Ok(false), - Ok(RunnableCompiledClass::V1((dummy_casm_contract_class(), SierraVersion::default()).try_into().unwrap())), - OLD_DEPLOY_CLASS_HASH_WHITELIST[0], -)] #[tokio::test] async fn test_get_compiled_class( #[case] class_manager_client_result: ClassManagerClientResult>, From cda162d781ba1c8f50ad3c928d332dd5b80748d5 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:29:09 +0200 Subject: [PATCH 256/313] apollo_integration_tests: fix polling_interval_seconds (#9705) --- crates/apollo_integration_tests/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/apollo_integration_tests/src/utils.rs b/crates/apollo_integration_tests/src/utils.rs index 98f673f2714..9c758a69c7a 100644 --- a/crates/apollo_integration_tests/src/utils.rs +++ b/crates/apollo_integration_tests/src/utils.rs @@ -201,7 +201,7 @@ pub fn create_node_config( let l1_scraper_config = L1ScraperConfig { chain_id: chain_info.chain_id.clone(), startup_rewind_time_seconds: Duration::from_secs(0), - polling_interval_seconds: Duration::from_secs(0), + polling_interval_seconds: Duration::from_secs(1), ..Default::default() }; let l1_provider_config = L1ProviderConfig { From 40c960aebf4881807e25e1ce1549e780605a6b73 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Tue, 4 Nov 2025 13:31:11 +0200 Subject: [PATCH 257/313] apollo_dashboard: use 10m as DEFAULT_DURATION for most panels (#9905) --- crates/apollo_dashboard/src/panels/batcher.rs | 26 +++++--- .../apollo_dashboard/src/panels/consensus.rs | 61 +++++++++++-------- .../src/panels/http_server.rs | 14 +++-- .../src/panels/l1_gas_price.rs | 37 ++++++----- .../src/panels/l1_provider.rs | 17 ++++-- crates/apollo_dashboard/src/panels/mempool.rs | 5 +- crates/apollo_dashboard/src/query_builder.rs | 2 + 7 files changed, 103 insertions(+), 59 deletions(-) diff --git a/crates/apollo_dashboard/src/panels/batcher.rs b/crates/apollo_dashboard/src/panels/batcher.rs index 412917c8c2a..b160051af3e 100644 --- a/crates/apollo_dashboard/src/panels/batcher.rs +++ b/crates/apollo_dashboard/src/panels/batcher.rs @@ -16,12 +16,16 @@ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; use crate::query_builder; +use crate::query_builder::DEFAULT_DURATION; fn get_panel_validator_wasted_txs() -> Panel { Panel::new( "Proposal Validation: Wasted TXs", - "Number of txs executed by the validator but excluded from the block (10m window)", - query_builder::increase(&VALIDATOR_WASTED_TXS, "10m"), + format!( + "Number of txs executed by the validator but excluded from the block \ + ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&VALIDATOR_WASTED_TXS, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("Finished building block as validator. Started executing") @@ -30,8 +34,11 @@ fn get_panel_validator_wasted_txs() -> Panel { fn get_panel_proposer_deferred_txs() -> Panel { Panel::new( "Proposal Build: Deferred TXs", - "Number of txs started execution by the proposer but excluded from the block (10m window)", - query_builder::increase(&PROPOSER_DEFERRED_TXS, "10m"), + format!( + "Number of txs started execution by the proposer but excluded from the block \ + ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&PROPOSER_DEFERRED_TXS, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("Finished building block as proposer. Started executing") @@ -48,18 +55,21 @@ fn get_panel_storage_height() -> Panel { } fn get_panel_rejection_reverted_ratio() -> Panel { - let rejected_txs_expr = query_builder::increase(&REJECTED_TRANSACTIONS, "10m"); - let reverted_txs_expr = query_builder::increase(&REVERTED_TRANSACTIONS, "10m"); + let rejected_txs_expr = query_builder::increase(&REJECTED_TRANSACTIONS, DEFAULT_DURATION); + let reverted_txs_expr = query_builder::increase(&REVERTED_TRANSACTIONS, DEFAULT_DURATION); let denominator_expr = format!( "({} + {} + {})", rejected_txs_expr, reverted_txs_expr, - query_builder::increase(&BATCHED_TRANSACTIONS, "10m"), + query_builder::increase(&BATCHED_TRANSACTIONS, DEFAULT_DURATION), ); Panel::new( "Rejected / Reverted TXs Ratio", - "Ratio of rejected / reverted transactions out of all processed txs (10m window)", + format!( + "Ratio of rejected / reverted transactions out of all processed txs \ + ({DEFAULT_DURATION} window)" + ), vec![ format!("{rejected_txs_expr} / {denominator_expr}"), format!("{reverted_txs_expr} / {denominator_expr}"), diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 6bc7b1a8a25..8e0c18b3c66 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -47,6 +47,7 @@ use apollo_state_sync_metrics::metrics::STATE_SYNC_CLASS_MANAGER_MARKER; use crate::dashboard::{Panel, PanelType, Row, Unit}; use crate::query_builder; +use crate::query_builder::DEFAULT_DURATION; // The key events that are relevant to the consensus panel. const CONSENSUS_KEY_EVENTS_LOG_QUERY: &str = @@ -95,9 +96,11 @@ pub(crate) fn get_panel_consensus_round() -> Panel { pub(crate) fn get_panel_consensus_round_advanced() -> Panel { Panel::new( "Consensus Round Advanced", - "The number of times the consensus round advanced (counter is increased whenever round > \ - 0) (10m window)", - query_builder::increase(&CONSENSUS_ROUND_ADVANCES, "10m"), + format!( + "The number of times the consensus round advanced (counter is increased whenever \ + round > 0) ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&CONSENSUS_ROUND_ADVANCES, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") @@ -131,8 +134,8 @@ pub(crate) fn get_panel_consensus_block_time_avg() -> Panel { fn get_panel_consensus_decisions_reached_by_consensus() -> Panel { Panel::new( "Decisions Reached By Consensus", - "The number of decisions reached by way of consensus (10m window)", - query_builder::increase(&CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, "10m"), + format!("The number of decisions reached by way of consensus ({DEFAULT_DURATION} window)",), + query_builder::increase(&CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("DECISION_REACHED: Decision reached for round") @@ -142,8 +145,8 @@ fn get_panel_consensus_decisions_reached_by_consensus() -> Panel { fn get_panel_consensus_decisions_reached_by_sync() -> Panel { Panel::new( "Decisions Reached By Sync", - "The number of decisions reached by way of sync (10m window)", - query_builder::increase(&CONSENSUS_DECISIONS_REACHED_BY_SYNC, "10m"), + format!("The number of decisions reached by way of sync ({DEFAULT_DURATION} window)",), + query_builder::increase(&CONSENSUS_DECISIONS_REACHED_BY_SYNC, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("Decision learned via sync protocol.") @@ -153,8 +156,8 @@ fn get_panel_consensus_decisions_reached_by_sync() -> Panel { fn get_panel_consensus_proposals_received() -> Panel { Panel::new( "Proposal Validation: Number of Received Proposals", - "The number of proposals received from the network (10m window)", - query_builder::increase(&CONSENSUS_PROPOSALS_RECEIVED, "10m"), + format!("The number of proposals received from the network ({DEFAULT_DURATION} window)",), + query_builder::increase(&CONSENSUS_PROPOSALS_RECEIVED, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -162,8 +165,11 @@ fn get_panel_consensus_proposals_received() -> Panel { fn get_panel_consensus_proposals_validated() -> Panel { Panel::new( "Proposal Validation: Number of Validated Proposals", - "The number of proposals received and validated successfully (10m window)", - query_builder::increase(&CONSENSUS_PROPOSALS_VALIDATED, "10m"), + format!( + "The number of proposals received and validated successfully ({DEFAULT_DURATION} \ + window)", + ), + query_builder::increase(&CONSENSUS_PROPOSALS_VALIDATED, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") @@ -173,8 +179,10 @@ fn get_panel_consensus_proposals_validated() -> Panel { fn get_panel_consensus_proposals_invalid() -> Panel { Panel::new( "Proposal Validation: Number of Invalid Proposals", - "The number of proposals received and failed validation (10m window)", - query_builder::increase(&CONSENSUS_PROPOSALS_INVALID, "10m"), + format!( + "The number of proposals received and failed validation ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&CONSENSUS_PROPOSALS_INVALID, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") @@ -199,8 +207,8 @@ fn get_panel_validate_proposal_failure() -> Panel { fn get_panel_consensus_build_proposal_total() -> Panel { Panel::new( "Proposal Build: Number of Proposals Started", - "The number of proposals that started building (10m window)", - query_builder::increase(&CONSENSUS_BUILD_PROPOSAL_TOTAL, "10m"), + format!("The number of proposals that started building ({DEFAULT_DURATION} window)",), + query_builder::increase(&CONSENSUS_BUILD_PROPOSAL_TOTAL, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -208,8 +216,8 @@ fn get_panel_consensus_build_proposal_total() -> Panel { fn get_panel_consensus_build_proposal_failed() -> Panel { Panel::new( "Proposal Build: Number of Proposals Failed", - "The number of proposals that failed to be built (10m window)", - query_builder::increase(&CONSENSUS_BUILD_PROPOSAL_FAILED, "10m"), + format!("The number of proposals that failed to be built ({DEFAULT_DURATION} window)",), + query_builder::increase(&CONSENSUS_BUILD_PROPOSAL_FAILED, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -287,8 +295,8 @@ fn get_panel_cende_write_blob_success() -> Panel { Panel::new( "Write Blob Success", - "The number of successful blob writes to Cende (10m window)", - query_builder::increase(&CENDE_WRITE_BLOB_SUCCESS, "10m"), + format!("The number of successful blob writes to Cende ({DEFAULT_DURATION} window)"), + query_builder::increase(&CENDE_WRITE_BLOB_SUCCESS, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query(query_expression) @@ -311,9 +319,11 @@ fn get_panel_cende_write_blob_failure() -> Panel { fn get_panel_cende_write_preconfirmed_block() -> Panel { Panel::new( "Write Preconfirmed Block Success", - "The number of successful writes to Cende for preconfirmed blocks (10m window). Each \ - preconfirmed block may involve multiple writes.", - query_builder::increase(&PRECONFIRMED_BLOCK_WRITTEN, "10m"), + format!( + "The number of successful writes to Cende for preconfirmed blocks ({DEFAULT_DURATION} \ + window). Each preconfirmed block may involve multiple writes.", + ), + query_builder::increase(&PRECONFIRMED_BLOCK_WRITTEN, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("write_pre_confirmed_block request succeeded.") @@ -420,8 +430,11 @@ fn get_panel_consensus_proposals_dropped_messages_by_reason() -> Panel { fn get_panel_consensus_decisions_reached_as_proposer() -> Panel { Panel::new( "Consensus Decisions Reached As Proposer", - "The number of rounds with decision reached where this node is the proposer (10m window)", - query_builder::increase(&CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, "10m"), + format!( + "The number of rounds with decision reached where this node is the proposer \ + ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"Building proposal\" OR \"BATCHER_FIN_PROPOSER\"") diff --git a/crates/apollo_dashboard/src/panels/http_server.rs b/crates/apollo_dashboard/src/panels/http_server.rs index e2060765629..95f9bcbcd39 100644 --- a/crates/apollo_dashboard/src/panels/http_server.rs +++ b/crates/apollo_dashboard/src/panels/http_server.rs @@ -10,12 +10,13 @@ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; use crate::query_builder; +use crate::query_builder::DEFAULT_DURATION; fn get_panel_total_transactions_received() -> Panel { Panel::new( "Transactions Received", - "Number of transactions received (10m window)", - query_builder::increase(&ADDED_TRANSACTIONS_TOTAL, "10m"), + format!("Number of transactions received ({DEFAULT_DURATION} window)"), + query_builder::increase(&ADDED_TRANSACTIONS_TOTAL, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"ADD_TX_START\"") @@ -24,11 +25,14 @@ fn get_panel_transaction_success_rate() -> Panel { // TODO(MatanL): use Panel::ratio_time_series Panel::new( "Transaction Success Rate", - "The ratio of transactions successfully added to the gateway (10m window)", + format!( + "The ratio of transactions successfully added to the gateway ({DEFAULT_DURATION} \ + window)", + ), format!( "{s} / ({s} + {f})", - s = query_builder::increase(&ADDED_TRANSACTIONS_SUCCESS, "10m"), - f = query_builder::increase(&ADDED_TRANSACTIONS_FAILURE, "10m"), + s = query_builder::increase(&ADDED_TRANSACTIONS_SUCCESS, DEFAULT_DURATION), + f = query_builder::increase(&ADDED_TRANSACTIONS_FAILURE, DEFAULT_DURATION), ), PanelType::TimeSeries, ) diff --git a/crates/apollo_dashboard/src/panels/l1_gas_price.rs b/crates/apollo_dashboard/src/panels/l1_gas_price.rs index 1b232bc0fad..190c8f77efe 100644 --- a/crates/apollo_dashboard/src/panels/l1_gas_price.rs +++ b/crates/apollo_dashboard/src/panels/l1_gas_price.rs @@ -15,12 +15,13 @@ use apollo_metrics::MetricCommon; use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; use crate::query_builder; +use crate::query_builder::DEFAULT_DURATION; fn get_panel_eth_to_strk_error_count() -> Panel { Panel::new( "ETH→STRK Rate Query Error Count", - "The number of times the ETH→STRK rate query failed (10m window)", - query_builder::increase(Ð_TO_STRK_ERROR_COUNT, "10m"), + format!("The number of times the ETH→STRK rate query failed ({DEFAULT_DURATION} window)"), + query_builder::increase(Ð_TO_STRK_ERROR_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -60,9 +61,11 @@ fn get_panel_eth_to_strk_rate() -> Panel { fn get_panel_l1_gas_price_provider_insufficient_history() -> Panel { Panel::new( "L1 Gas Price Provider Insufficient History", - "The number of times the L1 gas price provider calculated an average with too few blocks \ - (10m window)", - query_builder::increase(&L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, "10m"), + format!( + "The number of times the L1 gas price provider calculated an average with too few \ + blocks ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("Not enough history to calculate the mean gas price.") @@ -71,9 +74,11 @@ fn get_panel_l1_gas_price_provider_insufficient_history() -> Panel { fn get_panel_l1_gas_price_scraper_success_count() -> Panel { Panel::new( "L1 Gas Price Scraper Success Count", - "The number of times the L1 gas price scraper successfully scraped and updated gas prices \ - (10m window)", - query_builder::increase(&L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, "10m"), + format!( + "The number of times the L1 gas price scraper successfully scraped and updated gas \ + prices ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -81,9 +86,11 @@ fn get_panel_l1_gas_price_scraper_success_count() -> Panel { fn get_panel_l1_gas_price_scraper_baselayer_error_count() -> Panel { Panel::new( "L1 Gas Price Scraper Base Layer Error Count", - "The number of times the L1 gas price scraper encountered an error while scraping the \ - base layer (10m window)", - query_builder::increase(&L1_GAS_PRICE_SCRAPER_BASELAYER_ERROR_COUNT, "10m"), + format!( + "The number of times the L1 gas price scraper encountered an error while scraping the \ + base layer ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&L1_GAS_PRICE_SCRAPER_BASELAYER_ERROR_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -91,9 +98,11 @@ fn get_panel_l1_gas_price_scraper_baselayer_error_count() -> Panel { fn get_panel_l1_gas_price_scraper_reorg_detected() -> Panel { Panel::new( "L1 Gas Price Scraper Reorg Detected", - "The number of times the L1 gas price scraper detected a reorganization in the base layer \ - (10m window)", - query_builder::increase(&L1_GAS_PRICE_SCRAPER_REORG_DETECTED, "10m"), + format!( + "The number of times the L1 gas price scraper detected a reorganization in the base \ + layer ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&L1_GAS_PRICE_SCRAPER_REORG_DETECTED, DEFAULT_DURATION), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/l1_provider.rs b/crates/apollo_dashboard/src/panels/l1_provider.rs index 399f2464bf6..d8e6eb86945 100644 --- a/crates/apollo_dashboard/src/panels/l1_provider.rs +++ b/crates/apollo_dashboard/src/panels/l1_provider.rs @@ -7,22 +7,27 @@ use apollo_metrics::MetricCommon; use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; use crate::query_builder; +use crate::query_builder::DEFAULT_DURATION; fn get_panel_l1_message_scraper_success_count() -> Panel { Panel::new( "L1 Message Scraper Success Count", - "The increase in the number of times the L1 message scraper successfully scraped messages \ - (10m window)", - query_builder::increase(&L1_MESSAGE_SCRAPER_SUCCESS_COUNT, "10m"), + format!( + "The increase in the number of times the L1 message scraper successfully scraped \ + messages ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&L1_MESSAGE_SCRAPER_SUCCESS_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } fn get_panel_l1_message_scraper_baselayer_error_count() -> Panel { Panel::new( "L1 Message Scraper Base Layer Error Count", - "The increase in the number of times the L1 message scraper encountered an error while \ - scraping the base layer (10m window)", - query_builder::increase(&L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT, "10m"), + format!( + "The increase in the number of times the L1 message scraper encountered an error \ + while scraping the base layer ({DEFAULT_DURATION} window)", + ), + query_builder::increase(&L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/mempool.rs b/crates/apollo_dashboard/src/panels/mempool.rs index 3c314f187ec..2a9903c84d5 100644 --- a/crates/apollo_dashboard/src/panels/mempool.rs +++ b/crates/apollo_dashboard/src/panels/mempool.rs @@ -15,6 +15,7 @@ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; use crate::query_builder; +use crate::query_builder::DEFAULT_DURATION; fn get_panel_mempool_transactions_received_rate() -> Panel { Panel::new( @@ -31,8 +32,8 @@ fn get_panel_mempool_transactions_received_rate() -> Panel { fn get_panel_mempool_transactions_committed() -> Panel { Panel::new( "Transactions Committed", - "Number of transactions committed to a block (10m window)", - query_builder::increase(&MEMPOOL_TRANSACTIONS_COMMITTED, "10m"), + format!("Number of transactions committed to a block ({DEFAULT_DURATION} window)"), + query_builder::increase(&MEMPOOL_TRANSACTIONS_COMMITTED, DEFAULT_DURATION), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/query_builder.rs b/crates/apollo_dashboard/src/query_builder.rs index 9b92ff8786e..55452366a9b 100644 --- a/crates/apollo_dashboard/src/query_builder.rs +++ b/crates/apollo_dashboard/src/query_builder.rs @@ -4,6 +4,8 @@ use apollo_metrics::metrics::MetricCommon; #[path = "query_builder_test.rs"] pub mod query_builder_test; +pub(crate) const DEFAULT_DURATION: &str = "10m"; + pub(crate) fn increase(metric: &dyn MetricCommon, duration: &str) -> String { format!("increase({}[{}])", metric.get_name_with_filter(), duration) } From 82d72fdc4166d1c2d2593557be2b643e8a8b2835 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Tue, 4 Nov 2025 13:33:15 +0200 Subject: [PATCH 258/313] scripts: when disabling revert mode also set skip_write_height and immediate_active_height (#9928) --- scripts/prod/set_node_revert_mode.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index f77f5b40eb0..95fdf5b7109 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -41,14 +41,22 @@ def set_revert_mode( project_name: str, should_revert: bool, revert_up_to_block: int, + immediate_active_height: Optional[int] = None, ): config_overrides = { "revert_config.should_revert": should_revert, "revert_config.revert_up_to_and_including": revert_up_to_block, } + if immediate_active_height is not None: + assert not should_revert, "Immediate active height should not be set when reverting" + # We need a short variable name to avoid splitting to multiple lines which local black + # formatting does in a way that CI black doesn't like and fails on. + height = immediate_active_height + config_overrides["consensus_manager_config.immediate_active_height"] = height + config_overrides["consensus_manager_config.cende_config.skip_write_height"] = height post_restart_instructions = [] - for namespace, context in zip(namespace_list, context_list or [None] * len(namespace_list)): + for namespace in namespace_list: url = get_logs_explorer_url_for_revert(namespace, revert_up_to_block, project_name) post_restart_instructions.append( @@ -183,6 +191,8 @@ def main(): args.project_name, False, 18446744073709551615, + # Immediate active height is the block number which will be the first block proposed. + revert_up_to_block, ) From 93fb5cf03fafe2deae8cc9f7739039ccc3ed60d1 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:50:44 +0200 Subject: [PATCH 259/313] blockifier: create a unique name to the transfers benchmark (#9938) --- crates/blockifier/benches/main.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/blockifier/benches/main.rs b/crates/blockifier/benches/main.rs index fd7fa9b4c79..c6a84f82e0d 100644 --- a/crates/blockifier/benches/main.rs +++ b/crates/blockifier/benches/main.rs @@ -21,6 +21,14 @@ use blockifier::test_utils::transfers_generator::{ use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +/// The name of the benchmark. +/// Differentiates between the benchmark running with the Cairo Native and the Cairo VM, +/// enabling proper comparison and regression tracking for each. +#[cfg(feature = "cairo_native")] +pub const BENCHMARK_NAME: &str = "transfers_benchmark_cairo_native"; +#[cfg(not(feature = "cairo_native"))] +pub const BENCHMARK_NAME: &str = "transfers_benchmark_vm"; + // TODO(Arni): Consider how to run this benchmark both with and without setting the allocator. Maybe // hide this macro call under a feature, and run this benchmark regularly or with // `cargo bench --bench blockifier --feature=specified_allocator` @@ -41,7 +49,7 @@ pub fn transfers_benchmark(c: &mut Criterion) { let mut transfers_generator = TransfersGenerator::new(transfers_generator_config); // Benchmark only the execution phase (run_block_of_transfers call). // Transaction generation and state setup happen for each iteration but are not timed. - c.bench_function("transfers", |benchmark| { + c.bench_function(BENCHMARK_NAME, |benchmark| { benchmark.iter_batched( || { // Setup: prepare transactions and executor (not measured). From 20b3f966305da2a49f5abf50566ceb63f99f265e Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:30:55 +0200 Subject: [PATCH 260/313] bench_tools: add blockifier transfer benchmark (#9890) * blockifier: create a unique name to the transfers benchmark * bench_tools: add blockifier transfer benchmark --- .../bench_tools/src/types/benchmark_config.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/crates/bench_tools/src/types/benchmark_config.rs b/crates/bench_tools/src/types/benchmark_config.rs index 4b12aa70804..bafe9b4a684 100644 --- a/crates/bench_tools/src/types/benchmark_config.rs +++ b/crates/bench_tools/src/types/benchmark_config.rs @@ -60,6 +60,28 @@ pub const BENCHMARKS: &[BenchmarkConfig] = &[ "dummy_process_large_input", ]), }, + BenchmarkConfig { + name: "transfers_benchmark_cairo_native", + package: "blockifier", + cmd_args: &[ + "bench", + "-p", + "blockifier", + "--bench", + "blockifier", + "--features", + "testing,cairo_native", + ], + input_dir: None, + criterion_benchmark_names: None, // Single benchmark with same name. + }, + BenchmarkConfig { + name: "transfers_benchmark_vm", + package: "blockifier", + cmd_args: &["bench", "-p", "blockifier", "--bench", "blockifier", "--features", "testing"], + input_dir: None, + criterion_benchmark_names: None, // Single benchmark with same name. + }, ]; /// Helper functions for working with benchmarks. From 6d256c9e83c801dbdeab4b53310ce28dc8aa634a Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Tue, 4 Nov 2025 14:35:49 +0200 Subject: [PATCH 261/313] papyrus_base_layer: update starknetforsequencertesting.sol to have messageCancellationDelay 0 (#9930) --- .../resources/StarknetForSequencerTesting.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/papyrus_base_layer/resources/StarknetForSequencerTesting.json b/crates/papyrus_base_layer/resources/StarknetForSequencerTesting.json index 4a337e6be78..b368b9e1f44 100644 --- a/crates/papyrus_base_layer/resources/StarknetForSequencerTesting.json +++ b/crates/papyrus_base_layer/resources/StarknetForSequencerTesting.json @@ -553,5 +553,5 @@ "type": "function" } ], - "bytecode": "0x6080604052348015600e575f5ffd5b506120458061001c5f395ff3fe60806040526004361061011b575f3560e01c806377c7d7a91161009d5780639be446bf116100625780639be446bf146102c7578063a46efaf3146102e6578063b64b673714610305578063c415b95c14610324578063e1f1176d14610350575f5ffd5b806377c7d7a91461024d5780637a98660b1461026c5780638303bd8a1461028b5780638a9bf0901461029f5780639588eca2146102b3575f5ffd5b80633e3aa6c5116100e35780633e3aa6c5146101ac57806354eccba4146101d45780636170ff1b146101ee57806363142fb81461020d5780636e107a8c1461022e575f5ffd5b8063018cccdf1461011f5780632c9dd5c01461014657806335befa5d14610165578063382d83e3146101795780633d8a5df81461018d575b5f5ffd5b34801561012a575f5ffd5b50610133610364565b6040519081526020015b60405180910390f35b348015610151575f5ffd5b506101336101603660046119b3565b6103a8565b348015610170575f5ffd5b5061013361049b565b348015610184575f5ffd5b506101336104ad565b348015610198575f5ffd5b506101336101a7366004611a11565b6104bf565b6101bf6101ba366004611a67565b610503565b6040805192835260208301919091520161013d565b3480156101df575f5ffd5b50670de0b6b3a7640000610133565b3480156101f9575f5ffd5b50610133610208366004611a9e565b610694565b348015610218575f5ffd5b5061022c610227366004611af4565b6108a8565b005b348015610239575f5ffd5b5061022c610248366004611b3c565b610990565b348015610258575f5ffd5b50610133610267366004611baa565b6109fa565b348015610277575f5ffd5b50610133610286366004611a9e565b610a13565b348015610296575f5ffd5b50610133610aed565b3480156102aa575f5ffd5b50610133610b0f565b3480156102be575f5ffd5b50610133610b31565b3480156102d2575f5ffd5b506101336102e1366004611baa565b610b40565b3480156102f1575f5ffd5b50610133610300366004611baa565b610b49565b348015610310575f5ffd5b5061013361031f366004611bc1565b610b52565b34801561032f575f5ffd5b50610338610b9c565b6040516001600160a01b03909116815260200161013d565b34801561035b575f5ffd5b50610133610bdb565b5f6103a36040518060400160405280602081526020017f535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4e4f4e4345815250610bf9565b905090565b5f5f6103b6853386866104bf565b90505f6103c1610c2c565b5f8381526020919091526040902054116104225760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f4d4553534147455f544f5f434f4e53554d4500000000000060448201526064015b60405180910390fd5b336001600160a01b0316857f7a06c571aa77f34d9706c51e5d8122b5595aebeaa34233bfe866f22befb973b1868660405161045e929190611c5c565b60405180910390a36001610470610c2c565b5f8381526020019081526020015f205f82825461048d9190611c8b565b909155509095945050505050565b5f6104a4610c4e565b60010154905090565b5f6104b6610c4e565b60020154905090565b6040515f906104e39086906001600160a01b03871690859087908290602001611cc5565b604051602081830303815290604052805190602001209050949350505050565b5f5f5f341161055e5760405162461bcd60e51b815260206004820152602160248201527f4c315f4d53475f4645455f4d5553545f42455f475245415445525f5448414e5f6044820152600360fc1b6064820152608401610419565b670de0b6b3a76400003411156105b65760405162461bcd60e51b815260206004820152601760248201527f4d41585f4c315f4d53475f4645455f45584345454445440000000000000000006044820152606401610419565b5f6105bf610364565b905061060c6040518060400160405280602081526020017f535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4e4f4e43458152508260016106079190611cee565b610c97565b8587336001600160a01b03167fdb80dd488acf86d17c747445b0eabb5d57c541d3bd7b6b87af987858e5066b2b8888863460405161064d9493929190611d01565b60405180910390a45f610664338989898987610b52565b9050610671346001611cee565b610679610cc9565b5f838152602091909152604090205597909650945050505050565b5f8486336001600160a01b03167f8abd2ec2e0a10c82f5b60ea00455fa96c41fd144f225fcc52b8d83d94f803ed88787876040516106d493929190611d27565b60405180910390a45f6106eb338888888888610b52565b90505f6106f6610cc9565b5f8381526020919091526040812054915081900361074d5760405162461bcd60e51b81526020600482015260146024820152731393d7d35154d4d051d157d513d7d0d05390d15360621b6044820152606401610419565b5f610756610ceb565b5f848152602091909152604081205491508190036107c15760405162461bcd60e51b815260206004820152602260248201527f4d4553534147455f43414e43454c4c4154494f4e5f4e4f545f52455155455354604482015261115160f21b6064820152608401610419565b5f6107ca610aed565b6107d49083611cee565b9050818110156108265760405162461bcd60e51b815260206004820152601c60248201527f43414e43454c5f414c4c4f5745445f54494d455f4f564552464c4f57000000006044820152606401610419565b804210156108825760405162461bcd60e51b8152602060048201526024808201527f4d4553534147455f43414e43454c4c4154494f4e5f4e4f545f414c4c4f57454460448201526317d6515560e21b6064820152608401610419565b5f61088b610cc9565b5f8681526020919091526040902055509198975050505050505050565b600a82116108f85760405162461bcd60e51b815260206004820152601960248201527f535441524b4e45545f4f55545055545f544f4f5f53484f5254000000000000006044820152606401610419565b61090c8383610905610c4e565b9190610d0d565b8282600881811061091f5761091f611d4a565b905060200201355f1461096d5760405162461bcd60e51b8152602060048201526016602482015275554e45585045435445445f4b5a475f44415f464c414760501b6044820152606401610419565b6109778383610da1565b61098b8383610984610c4e565b9190610f3c565b505050565b610998610f9d565b156109e65780156109e25760405162461bcd60e51b8152602060048201526014602482015273554e45585045435445445f494e49545f4441544160601b6044820152606401610419565b5050565b6109f08282610fad565b6109e28282611057565b5f610a03610cc9565b5f92835260205250604090205490565b5f8486336001600160a01b03167f2e00dccd686fd6823ec7dc3e125582aa82881b6ff5f6b5a73856e1ea8338a3be878787604051610a5393929190611d27565b60405180910390a45f610a6a338888888888610b52565b90505f610a75610cc9565b5f8381526020919091526040902054905080610aca5760405162461bcd60e51b81526020600482015260146024820152731393d7d35154d4d051d157d513d7d0d05390d15360621b6044820152606401610419565b42610ad3610ceb565b5f8481526020919091526040902055509695505050505050565b5f6103a36040518060600160405280602d8152602001611f4c602d9139610bf9565b5f6103a3604051806060016040528060268152602001611f2660269139610bf9565b5f610b3a610c4e565b54919050565b5f610a03610ceb565b5f610a03610c2c565b6040515f90610b7a906001600160a01b0389169088908590899088908a908290602001611d5e565b6040516020818303038152906040528051906020012090509695505050505050565b5f6103a36040518060400160405280601f81526020017f4645455f434f4c4c454354494f4e5f414444524553535f534c4f545f54414700815250610bf9565b5f6103a3604051806060016040528060248152602001611f79602491395b5f5f82604051602001610c0c9190611d95565b60408051601f198184030181529190528051602090910120549392505050565b5f6103a3604051806060016040528060238152602001611f9d602391396110b8565b5f5f6040518060600160405280602a8152602001611fc0602a9139604051602001610c799190611d95565b60408051601f19818403018152919052805160209091012092915050565b5f82604051602001610ca99190611d95565b604051602081830303815290604052805190602001209050818155505050565b5f6103a3604051806060016040528060268152602001611fea602691396110b8565b5f6103a3604051806060016040528060308152602001611ef6603091396110b8565b5f83600101545f1903610d2c575067080000000000001160c01b610d33565b5060018301545b8083836002818110610d4757610d47611d4a565b9050602002013514610d9b5760405162461bcd60e51b815260206004820152601960248201527f494e56414c49445f505245565f424c4f434b5f4e554d424552000000000000006044820152606401610419565b50505050565b610dab82826110ea565b81816009818110610dbe57610dbe611d4a565b905060200201355f14610e135760405162461bcd60e51b815260206004820152601960248201527f46554c4c5f4f55545055545f4e4f545f535550504f52544544000000000000006044820152606401610419565b610e278282610e20610c4e565b919061117d565b5f610e328383611293565b90505f610e3d611330565b9050610e5e6001610e5085858189611dab565b610e58610c2c565b85611356565b610e689083611cee565b9150610e825f610e7a85858189611dab565b610e58610cc9565b610e8c9083611cee565b9150828214610edd5760405162461bcd60e51b815260206004820152601860248201527f535441524b4e45545f4f55545055545f544f4f5f4c4f4e4700000000000000006044820152606401610419565b5f610ee6610c4e565b805460018201546002830154604080519384526020840192909252908201529091507fd342ddf7a308dec111745b00315c14b7efb2bdae570a6856e088ed0c65a3576c9060600160405180910390a15050505050565b81816003818110610f4f57610f4f611d4a565b9050602002013583600101541461098b5760405162461bcd60e51b81526020600482015260126024820152715245454e5452414e43595f4641494c55524560701b6044820152606401610419565b5f610fa6610b0f565b1515919050565b60e08114610ff65760405162461bcd60e51b8152602060048201526016602482015275494c4c4547414c5f494e49545f444154415f53495a4560501b6044820152606401610419565b5f6110046020828486611dd6565b8101906110119190611baa565b9050805f0361098b5760405162461bcd60e51b81526020600482015260126024820152712120a22fa4a724aa24a0a624ad20aa24a7a760711b6044820152606401610419565b5f808061106684860186611dfd565b92509250925061107583611902565b61109c81611081610c4e565b90805182556020810151600183015560400151600290910155565b6110a582611927565b6110b162069780611949565b5050505050565b5f5f826040516020016110cb9190611d95565b60408051601f1981840301815291905280516020909101209392505050565b6001600167080000000000001160c01b01602083028401845b81811015611123578281351061111b575f9350611123565b602001611103565b5050508061098b5760405162461bcd60e51b815260206004820152602160248201527f50524f4752414d5f4f55545055545f56414c55455f4f55545f4f465f52414e476044820152604560f81b6064820152608401610419565b611188838383610d0d565b5f8282600381811061119c5761119c611d4a565b905060200201359050836001015481136111f85760405162461bcd60e51b815260206004820152601860248201527f494e56414c49445f4e45575f424c4f434b5f4e554d42455200000000000000006044820152606401610419565b6001840181905560028401548383600481811061121757611217611d4a565b905060200201351461126b5760405162461bcd60e51b815260206004820152601760248201527f494e56414c49445f505245565f424c4f434b5f484153480000000000000000006044820152606401610419565b8282600581811061127e5761127e611d4a565b90506020020135846002018190555050505050565b5f828260088181106112a7576112a7611d4a565b905060200201355f036112bc5750600a61132a565b5f83836112cb6001600a611cee565b8181106112da576112da611d4a565b9050602002013590508060026112f09190611e86565b6112fb826002611e86565b611307600a6001611cee565b611312906001611cee565b61131c9190611cee565b6113269190611cee565b9150505b92915050565b5f5f61133a610b9c565b90506001600160a01b038116611351573391505090565b919050565b5f5f85855f81811061136a5761136a611d4a565b905060200201359050634000000081106113c65760405162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f4d4553534147455f5345474d454e545f53495a45000000006044820152606401610419565b60015f6113d38383611cee565b90505f896113e25760046113e5565b60025b90505f5b82841015611807575f806113fd8487611cee565b90508a81106114425760405162461bcd60e51b8152602060048201526011602482015270135154d4d051d157d513d3d7d4d213d495607a1b6044820152606401610419565b5f8c8c8381811061145557611455611d4a565b905060200201359050634000000081106114aa5760405162461bcd60e51b81526020600482015260166024820152750929cac82989288bea082b2989e8288be988a9c8ea8960531b6044820152606401610419565b806114b6836001611cee565b6114c09190611cee565b92508b8311156115125760405162461bcd60e51b815260206004820152601960248201527f5452554e43415445445f4d4553534147455f5041594c4f4144000000000000006044820152606401610419565b50508b1561161e575f61152782878d8f611dab565b604051602001611538929190611e9d565b6040516020818303038152906040528051906020012090508b8b60018861155f9190611cee565b81811061156e5761156e611d4a565b905060200201356001600160a01b03168c8c5f8961158c9190611cee565b81811061159b5761159b611d4a565b905060200201357f4264ac208b5fde633ccdd42e0f12c3d6d443a4f3779bbf886925b94665b63a228e8e60038b6115d29190611cee565b6115de92889290611dab565b6040516115ec929190611c5c565b60405180910390a35f81815260208b905260408120805460019290611612908490611cee565b90915550611800915050565b5f61162b82878d8f611dab565b60405160200161163c929190611e9d565b60408051601f1981840301815291815281516020928301205f818152928d9052912054909150806116af5760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f4d4553534147455f544f5f434f4e53554d450000000000006044820152606401610419565b6116ba600182611c8b565b6116c49085611cee565b5f92835260208c90526040832083905593508c90508b6116e5600289611cee565b8181106116f4576116f4611d4a565b9050602002013590505f8c8c60058961170d9190611cee565b61171992869290611dab565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152509293508f92508e915061175c905060038a611cee565b81811061176b5761176b611d4a565b905060200201358d8d60018a6117819190611cee565b81811061179057611790611d4a565b905060200201358e8e5f8b6117a59190611cee565b8181106117b4576117b4611d4a565b905060200201356001600160a01b03167f9592d37825c744e33fa80c469683bbd04d336241bb600b574758efd182abe26a84866040516117f5929190611ea9565b60405180910390a450505b93506113e9565b8284146118565760405162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f4d4553534147455f5345474d454e545f53495a45000000006044820152606401610419565b80156118f3575f876001600160a01b0316826040515f6040518083038185875af1925050503d805f81146118a5576040519150601f19603f3d011682016040523d82523d5f602084013e6118aa565b606091505b50509050806118f15760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610419565b505b50919998505050505050505050565b611924604051806060016040528060268152602001611f266026913982610c97565b50565b611924604051806060016040528060248152602001611f796024913982610c97565b6119246040518060600160405280602d8152602001611f4c602d913982610c97565b5f5f83601f84011261197b575f5ffd5b50813567ffffffffffffffff811115611992575f5ffd5b6020830191508360208260051b85010111156119ac575f5ffd5b9250929050565b5f5f5f604084860312156119c5575f5ffd5b83359250602084013567ffffffffffffffff8111156119e2575f5ffd5b6119ee8682870161196b565b9497909650939450505050565b80356001600160a01b0381168114611351575f5ffd5b5f5f5f5f60608587031215611a24575f5ffd5b84359350611a34602086016119fb565b9250604085013567ffffffffffffffff811115611a4f575f5ffd5b611a5b8782880161196b565b95989497509550505050565b5f5f5f5f60608587031215611a7a575f5ffd5b8435935060208501359250604085013567ffffffffffffffff811115611a4f575f5ffd5b5f5f5f5f5f60808688031215611ab2575f5ffd5b8535945060208601359350604086013567ffffffffffffffff811115611ad6575f5ffd5b611ae28882890161196b565b96999598509660600135949350505050565b5f5f5f60408486031215611b06575f5ffd5b833567ffffffffffffffff811115611b1c575f5ffd5b611b288682870161196b565b909790965060209590950135949350505050565b5f5f60208385031215611b4d575f5ffd5b823567ffffffffffffffff811115611b63575f5ffd5b8301601f81018513611b73575f5ffd5b803567ffffffffffffffff811115611b89575f5ffd5b856020828401011115611b9a575f5ffd5b6020919091019590945092505050565b5f60208284031215611bba575f5ffd5b5035919050565b5f5f5f5f5f5f60a08789031215611bd6575f5ffd5b611bdf876119fb565b95506020870135945060408701359350606087013567ffffffffffffffff811115611c08575f5ffd5b611c1489828a0161196b565b979a9699509497949695608090950135949350505050565b8183525f6001600160fb1b03831115611c43575f5ffd5b8260051b80836020870137939093016020019392505050565b602081525f611c6f602083018486611c2c565b949350505050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561132a5761132a611c77565b5f6001600160fb1b03831115611cb2575f5ffd5b8260051b80838637939093019392505050565b8581528460208201528360408201525f611ce3606083018486611c9e565b979650505050505050565b8082018082111561132a5761132a611c77565b606081525f611d14606083018688611c2c565b6020830194909452506040015292915050565b604081525f611d3a604083018587611c2c565b9050826020830152949350505050565b634e487b7160e01b5f52603260045260245ffd5b8781528660208201528560408201528460608201528360808201525f611d8860a083018486611c9e565b9998505050505050505050565b5f82518060208501845e5f920191825250919050565b5f5f85851115611db9575f5ffd5b83861115611dc5575f5ffd5b5050600583901b0193919092039150565b5f5f85851115611de4575f5ffd5b83861115611df0575f5ffd5b5050820193919092039150565b5f5f5f83850360a0811215611e10575f5ffd5b84359350602085013592506060603f1982011215611e2c575f5ffd5b506040516060810181811067ffffffffffffffff82111715611e5c57634e487b7160e01b5f52604160045260245ffd5b60409081528581013582526060860135602083015260809095013594810194909452509093909250565b808202811582820484141761132a5761132a611c77565b5f611c6f828486611c9e565b604080825283519082018190525f9060208501906060840190835b81811015611ee2578351835260209384019390920191600101611ec4565b505060209390930193909352509291505056fe535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f43414e43454c4c4154494f4e5f4d41505050494e474d4f434b5f535441524b4e45542e305f494e49545f50524f4752414d5f484153485f55494e54535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f43414e43454c4c4154494f4e5f44454c41594d4f434b5f535441524b4e45542e305f535441524b4e45545f434f4e4649475f48415348535441524b4e45545f312e305f4d5347494e475f4c32544f4c315f4d41505050494e474d4f434b5f535441524b4e45542e305f494e49545f535441524b4e45545f53544154455f535452554354535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4d41505050494e475f5632a2646970667358221220d9005266682d99d8505ab7e1245d78941da643a272fac5f08c3c38a0e69e849064736f6c634300081d0033" + "bytecode": "0x6080604052348015600e575f5ffd5b506120428061001c5f395ff3fe60806040526004361061011b575f3560e01c806377c7d7a91161009d5780639be446bf116100625780639be446bf146102c7578063a46efaf3146102e6578063b64b673714610305578063c415b95c14610324578063e1f1176d14610350575f5ffd5b806377c7d7a91461024d5780637a98660b1461026c5780638303bd8a1461028b5780638a9bf0901461029f5780639588eca2146102b3575f5ffd5b80633e3aa6c5116100e35780633e3aa6c5146101ac57806354eccba4146101d45780636170ff1b146101ee57806363142fb81461020d5780636e107a8c1461022e575f5ffd5b8063018cccdf1461011f5780632c9dd5c01461014657806335befa5d14610165578063382d83e3146101795780633d8a5df81461018d575b5f5ffd5b34801561012a575f5ffd5b50610133610364565b6040519081526020015b60405180910390f35b348015610151575f5ffd5b506101336101603660046119b0565b6103a8565b348015610170575f5ffd5b5061013361049b565b348015610184575f5ffd5b506101336104ad565b348015610198575f5ffd5b506101336101a7366004611a0e565b6104bf565b6101bf6101ba366004611a64565b610503565b6040805192835260208301919091520161013d565b3480156101df575f5ffd5b50670de0b6b3a7640000610133565b3480156101f9575f5ffd5b50610133610208366004611a9b565b610694565b348015610218575f5ffd5b5061022c610227366004611af1565b6108a8565b005b348015610239575f5ffd5b5061022c610248366004611b39565b610990565b348015610258575f5ffd5b50610133610267366004611ba7565b6109fa565b348015610277575f5ffd5b50610133610286366004611a9b565b610a13565b348015610296575f5ffd5b50610133610aed565b3480156102aa575f5ffd5b50610133610b0f565b3480156102be575f5ffd5b50610133610b31565b3480156102d2575f5ffd5b506101336102e1366004611ba7565b610b40565b3480156102f1575f5ffd5b50610133610300366004611ba7565b610b49565b348015610310575f5ffd5b5061013361031f366004611bbe565b610b52565b34801561032f575f5ffd5b50610338610b9c565b6040516001600160a01b03909116815260200161013d565b34801561035b575f5ffd5b50610133610bdb565b5f6103a36040518060400160405280602081526020017f535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4e4f4e4345815250610bf9565b905090565b5f5f6103b6853386866104bf565b90505f6103c1610c2c565b5f8381526020919091526040902054116104225760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f4d4553534147455f544f5f434f4e53554d4500000000000060448201526064015b60405180910390fd5b336001600160a01b0316857f7a06c571aa77f34d9706c51e5d8122b5595aebeaa34233bfe866f22befb973b1868660405161045e929190611c59565b60405180910390a36001610470610c2c565b5f8381526020019081526020015f205f82825461048d9190611c88565b909155509095945050505050565b5f6104a4610c4e565b60010154905090565b5f6104b6610c4e565b60020154905090565b6040515f906104e39086906001600160a01b03871690859087908290602001611cc2565b604051602081830303815290604052805190602001209050949350505050565b5f5f5f341161055e5760405162461bcd60e51b815260206004820152602160248201527f4c315f4d53475f4645455f4d5553545f42455f475245415445525f5448414e5f6044820152600360fc1b6064820152608401610419565b670de0b6b3a76400003411156105b65760405162461bcd60e51b815260206004820152601760248201527f4d41585f4c315f4d53475f4645455f45584345454445440000000000000000006044820152606401610419565b5f6105bf610364565b905061060c6040518060400160405280602081526020017f535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4e4f4e43458152508260016106079190611ceb565b610c97565b8587336001600160a01b03167fdb80dd488acf86d17c747445b0eabb5d57c541d3bd7b6b87af987858e5066b2b8888863460405161064d9493929190611cfe565b60405180910390a45f610664338989898987610b52565b9050610671346001611ceb565b610679610cc9565b5f838152602091909152604090205597909650945050505050565b5f8486336001600160a01b03167f8abd2ec2e0a10c82f5b60ea00455fa96c41fd144f225fcc52b8d83d94f803ed88787876040516106d493929190611d24565b60405180910390a45f6106eb338888888888610b52565b90505f6106f6610cc9565b5f8381526020919091526040812054915081900361074d5760405162461bcd60e51b81526020600482015260146024820152731393d7d35154d4d051d157d513d7d0d05390d15360621b6044820152606401610419565b5f610756610ceb565b5f848152602091909152604081205491508190036107c15760405162461bcd60e51b815260206004820152602260248201527f4d4553534147455f43414e43454c4c4154494f4e5f4e4f545f52455155455354604482015261115160f21b6064820152608401610419565b5f6107ca610aed565b6107d49083611ceb565b9050818110156108265760405162461bcd60e51b815260206004820152601c60248201527f43414e43454c5f414c4c4f5745445f54494d455f4f564552464c4f57000000006044820152606401610419565b804210156108825760405162461bcd60e51b8152602060048201526024808201527f4d4553534147455f43414e43454c4c4154494f4e5f4e4f545f414c4c4f57454460448201526317d6515560e21b6064820152608401610419565b5f61088b610cc9565b5f8681526020919091526040902055509198975050505050505050565b600a82116108f85760405162461bcd60e51b815260206004820152601960248201527f535441524b4e45545f4f55545055545f544f4f5f53484f5254000000000000006044820152606401610419565b61090c8383610905610c4e565b9190610d0d565b8282600881811061091f5761091f611d47565b905060200201355f1461096d5760405162461bcd60e51b8152602060048201526016602482015275554e45585045435445445f4b5a475f44415f464c414760501b6044820152606401610419565b6109778383610da1565b61098b8383610984610c4e565b9190610f3c565b505050565b610998610f9d565b156109e65780156109e25760405162461bcd60e51b8152602060048201526014602482015273554e45585045435445445f494e49545f4441544160601b6044820152606401610419565b5050565b6109f08282610fad565b6109e28282611057565b5f610a03610cc9565b5f92835260205250604090205490565b5f8486336001600160a01b03167f2e00dccd686fd6823ec7dc3e125582aa82881b6ff5f6b5a73856e1ea8338a3be878787604051610a5393929190611d24565b60405180910390a45f610a6a338888888888610b52565b90505f610a75610cc9565b5f8381526020919091526040902054905080610aca5760405162461bcd60e51b81526020600482015260146024820152731393d7d35154d4d051d157d513d7d0d05390d15360621b6044820152606401610419565b42610ad3610ceb565b5f8481526020919091526040902055509695505050505050565b5f6103a36040518060600160405280602d8152602001611f49602d9139610bf9565b5f6103a3604051806060016040528060268152602001611f2360269139610bf9565b5f610b3a610c4e565b54919050565b5f610a03610ceb565b5f610a03610c2c565b6040515f90610b7a906001600160a01b0389169088908590899088908a908290602001611d5b565b6040516020818303038152906040528051906020012090509695505050505050565b5f6103a36040518060400160405280601f81526020017f4645455f434f4c4c454354494f4e5f414444524553535f534c4f545f54414700815250610bf9565b5f6103a3604051806060016040528060248152602001611f76602491395b5f5f82604051602001610c0c9190611d92565b60408051601f198184030181529190528051602090910120549392505050565b5f6103a3604051806060016040528060238152602001611f9a602391396110b5565b5f5f6040518060600160405280602a8152602001611fbd602a9139604051602001610c799190611d92565b60408051601f19818403018152919052805160209091012092915050565b5f82604051602001610ca99190611d92565b604051602081830303815290604052805190602001209050818155505050565b5f6103a3604051806060016040528060268152602001611fe7602691396110b5565b5f6103a3604051806060016040528060308152602001611ef3603091396110b5565b5f83600101545f1903610d2c575067080000000000001160c01b610d33565b5060018301545b8083836002818110610d4757610d47611d47565b9050602002013514610d9b5760405162461bcd60e51b815260206004820152601960248201527f494e56414c49445f505245565f424c4f434b5f4e554d424552000000000000006044820152606401610419565b50505050565b610dab82826110e7565b81816009818110610dbe57610dbe611d47565b905060200201355f14610e135760405162461bcd60e51b815260206004820152601960248201527f46554c4c5f4f55545055545f4e4f545f535550504f52544544000000000000006044820152606401610419565b610e278282610e20610c4e565b919061117a565b5f610e328383611290565b90505f610e3d61132d565b9050610e5e6001610e5085858189611da8565b610e58610c2c565b85611353565b610e689083611ceb565b9150610e825f610e7a85858189611da8565b610e58610cc9565b610e8c9083611ceb565b9150828214610edd5760405162461bcd60e51b815260206004820152601860248201527f535441524b4e45545f4f55545055545f544f4f5f4c4f4e4700000000000000006044820152606401610419565b5f610ee6610c4e565b805460018201546002830154604080519384526020840192909252908201529091507fd342ddf7a308dec111745b00315c14b7efb2bdae570a6856e088ed0c65a3576c9060600160405180910390a15050505050565b81816003818110610f4f57610f4f611d47565b9050602002013583600101541461098b5760405162461bcd60e51b81526020600482015260126024820152715245454e5452414e43595f4641494c55524560701b6044820152606401610419565b5f610fa6610b0f565b1515919050565b60e08114610ff65760405162461bcd60e51b8152602060048201526016602482015275494c4c4547414c5f494e49545f444154415f53495a4560501b6044820152606401610419565b5f6110046020828486611dd3565b8101906110119190611ba7565b9050805f0361098b5760405162461bcd60e51b81526020600482015260126024820152712120a22fa4a724aa24a0a624ad20aa24a7a760711b6044820152606401610419565b5f808061106684860186611dfa565b925092509250611075836118ff565b61109c81611081610c4e565b90805182556020810151600183015560400151600290910155565b6110a582611924565b6110ae5f611946565b5050505050565b5f5f826040516020016110c89190611d92565b60408051601f1981840301815291905280516020909101209392505050565b6001600167080000000000001160c01b01602083028401845b818110156111205782813510611118575f9350611120565b602001611100565b5050508061098b5760405162461bcd60e51b815260206004820152602160248201527f50524f4752414d5f4f55545055545f56414c55455f4f55545f4f465f52414e476044820152604560f81b6064820152608401610419565b611185838383610d0d565b5f8282600381811061119957611199611d47565b905060200201359050836001015481136111f55760405162461bcd60e51b815260206004820152601860248201527f494e56414c49445f4e45575f424c4f434b5f4e554d42455200000000000000006044820152606401610419565b6001840181905560028401548383600481811061121457611214611d47565b90506020020135146112685760405162461bcd60e51b815260206004820152601760248201527f494e56414c49445f505245565f424c4f434b5f484153480000000000000000006044820152606401610419565b8282600581811061127b5761127b611d47565b90506020020135846002018190555050505050565b5f828260088181106112a4576112a4611d47565b905060200201355f036112b95750600a611327565b5f83836112c86001600a611ceb565b8181106112d7576112d7611d47565b9050602002013590508060026112ed9190611e83565b6112f8826002611e83565b611304600a6001611ceb565b61130f906001611ceb565b6113199190611ceb565b6113239190611ceb565b9150505b92915050565b5f5f611337610b9c565b90506001600160a01b03811661134e573391505090565b919050565b5f5f85855f81811061136757611367611d47565b905060200201359050634000000081106113c35760405162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f4d4553534147455f5345474d454e545f53495a45000000006044820152606401610419565b60015f6113d08383611ceb565b90505f896113df5760046113e2565b60025b90505f5b82841015611804575f806113fa8487611ceb565b90508a811061143f5760405162461bcd60e51b8152602060048201526011602482015270135154d4d051d157d513d3d7d4d213d495607a1b6044820152606401610419565b5f8c8c8381811061145257611452611d47565b905060200201359050634000000081106114a75760405162461bcd60e51b81526020600482015260166024820152750929cac82989288bea082b2989e8288be988a9c8ea8960531b6044820152606401610419565b806114b3836001611ceb565b6114bd9190611ceb565b92508b83111561150f5760405162461bcd60e51b815260206004820152601960248201527f5452554e43415445445f4d4553534147455f5041594c4f4144000000000000006044820152606401610419565b50508b1561161b575f61152482878d8f611da8565b604051602001611535929190611e9a565b6040516020818303038152906040528051906020012090508b8b60018861155c9190611ceb565b81811061156b5761156b611d47565b905060200201356001600160a01b03168c8c5f896115899190611ceb565b81811061159857611598611d47565b905060200201357f4264ac208b5fde633ccdd42e0f12c3d6d443a4f3779bbf886925b94665b63a228e8e60038b6115cf9190611ceb565b6115db92889290611da8565b6040516115e9929190611c59565b60405180910390a35f81815260208b90526040812080546001929061160f908490611ceb565b909155506117fd915050565b5f61162882878d8f611da8565b604051602001611639929190611e9a565b60408051601f1981840301815291815281516020928301205f818152928d9052912054909150806116ac5760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f4d4553534147455f544f5f434f4e53554d450000000000006044820152606401610419565b6116b7600182611c88565b6116c19085611ceb565b5f92835260208c90526040832083905593508c90508b6116e2600289611ceb565b8181106116f1576116f1611d47565b9050602002013590505f8c8c60058961170a9190611ceb565b61171692869290611da8565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152509293508f92508e9150611759905060038a611ceb565b81811061176857611768611d47565b905060200201358d8d60018a61177e9190611ceb565b81811061178d5761178d611d47565b905060200201358e8e5f8b6117a29190611ceb565b8181106117b1576117b1611d47565b905060200201356001600160a01b03167f9592d37825c744e33fa80c469683bbd04d336241bb600b574758efd182abe26a84866040516117f2929190611ea6565b60405180910390a450505b93506113e6565b8284146118535760405162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f4d4553534147455f5345474d454e545f53495a45000000006044820152606401610419565b80156118f0575f876001600160a01b0316826040515f6040518083038185875af1925050503d805f81146118a2576040519150601f19603f3d011682016040523d82523d5f602084013e6118a7565b606091505b50509050806118ee5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610419565b505b50919998505050505050505050565b611921604051806060016040528060268152602001611f236026913982610c97565b50565b611921604051806060016040528060248152602001611f766024913982610c97565b6119216040518060600160405280602d8152602001611f49602d913982610c97565b5f5f83601f840112611978575f5ffd5b50813567ffffffffffffffff81111561198f575f5ffd5b6020830191508360208260051b85010111156119a9575f5ffd5b9250929050565b5f5f5f604084860312156119c2575f5ffd5b83359250602084013567ffffffffffffffff8111156119df575f5ffd5b6119eb86828701611968565b9497909650939450505050565b80356001600160a01b038116811461134e575f5ffd5b5f5f5f5f60608587031215611a21575f5ffd5b84359350611a31602086016119f8565b9250604085013567ffffffffffffffff811115611a4c575f5ffd5b611a5887828801611968565b95989497509550505050565b5f5f5f5f60608587031215611a77575f5ffd5b8435935060208501359250604085013567ffffffffffffffff811115611a4c575f5ffd5b5f5f5f5f5f60808688031215611aaf575f5ffd5b8535945060208601359350604086013567ffffffffffffffff811115611ad3575f5ffd5b611adf88828901611968565b96999598509660600135949350505050565b5f5f5f60408486031215611b03575f5ffd5b833567ffffffffffffffff811115611b19575f5ffd5b611b2586828701611968565b909790965060209590950135949350505050565b5f5f60208385031215611b4a575f5ffd5b823567ffffffffffffffff811115611b60575f5ffd5b8301601f81018513611b70575f5ffd5b803567ffffffffffffffff811115611b86575f5ffd5b856020828401011115611b97575f5ffd5b6020919091019590945092505050565b5f60208284031215611bb7575f5ffd5b5035919050565b5f5f5f5f5f5f60a08789031215611bd3575f5ffd5b611bdc876119f8565b95506020870135945060408701359350606087013567ffffffffffffffff811115611c05575f5ffd5b611c1189828a01611968565b979a9699509497949695608090950135949350505050565b8183525f6001600160fb1b03831115611c40575f5ffd5b8260051b80836020870137939093016020019392505050565b602081525f611c6c602083018486611c29565b949350505050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561132757611327611c74565b5f6001600160fb1b03831115611caf575f5ffd5b8260051b80838637939093019392505050565b8581528460208201528360408201525f611ce0606083018486611c9b565b979650505050505050565b8082018082111561132757611327611c74565b606081525f611d11606083018688611c29565b6020830194909452506040015292915050565b604081525f611d37604083018587611c29565b9050826020830152949350505050565b634e487b7160e01b5f52603260045260245ffd5b8781528660208201528560408201528460608201528360808201525f611d8560a083018486611c9b565b9998505050505050505050565b5f82518060208501845e5f920191825250919050565b5f5f85851115611db6575f5ffd5b83861115611dc2575f5ffd5b5050600583901b0193919092039150565b5f5f85851115611de1575f5ffd5b83861115611ded575f5ffd5b5050820193919092039150565b5f5f5f83850360a0811215611e0d575f5ffd5b84359350602085013592506060603f1982011215611e29575f5ffd5b506040516060810181811067ffffffffffffffff82111715611e5957634e487b7160e01b5f52604160045260245ffd5b60409081528581013582526060860135602083015260809095013594810194909452509093909250565b808202811582820484141761132757611327611c74565b5f611c6c828486611c9b565b604080825283519082018190525f9060208501906060840190835b81811015611edf578351835260209384019390920191600101611ec1565b505060209390930193909352509291505056fe535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f43414e43454c4c4154494f4e5f4d41505050494e474d4f434b5f535441524b4e45542e305f494e49545f50524f4752414d5f484153485f55494e54535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f43414e43454c4c4154494f4e5f44454c41594d4f434b5f535441524b4e45542e305f535441524b4e45545f434f4e4649475f48415348535441524b4e45545f312e305f4d5347494e475f4c32544f4c315f4d41505050494e474d4f434b5f535441524b4e45542e305f494e49545f535441524b4e45545f53544154455f535452554354535441524b4e45545f312e305f4d5347494e475f4c31544f4c325f4d41505050494e475f5632a2646970667358221220cce486760b836245e57f35ea6d7fdaa777d8d1d79675db468e4fd26b8605736764736f6c634300081e0033" } From e11b1de1654b6ca1d3364a236faf94da0bdefbe4 Mon Sep 17 00:00:00 2001 From: Matan Lior Date: Tue, 4 Nov 2025 14:44:04 +0200 Subject: [PATCH 262/313] apollo_dashboard: add sum_by_label to query_builder module (#9920) --- Cargo.lock | 1 + crates/apollo_dashboard/Cargo.toml | 1 + .../resources/dev_grafana.json | 10 +- crates/apollo_dashboard/src/panels/batcher.rs | 22 ++-- .../apollo_dashboard/src/panels/consensus.rs | 104 ++++++++++-------- crates/apollo_dashboard/src/panels/gateway.rs | 49 +++++---- .../src/panels/http_server.rs | 9 +- .../src/panels/l1_gas_price.rs | 13 +-- .../src/panels/l1_provider.rs | 9 +- crates/apollo_dashboard/src/panels/mempool.rs | 18 ++- .../src/panels/mempool_p2p.rs | 14 +-- .../src/panels/sierra_compiler.rs | 8 +- crates/apollo_dashboard/src/query_builder.rs | 40 +++++++ .../src/query_builder_test.rs | 25 ++++- 14 files changed, 207 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2eada046fe..390d788e0a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1341,6 +1341,7 @@ dependencies = [ "apollo_storage", "blockifier", "indexmap 2.11.0", + "rstest", "serde", "serde_json", "serde_with", diff --git a/crates/apollo_dashboard/Cargo.toml b/crates/apollo_dashboard/Cargo.toml index b68cf9063a2..0fa416759e3 100644 --- a/crates/apollo_dashboard/Cargo.toml +++ b/crates/apollo_dashboard/Cargo.toml @@ -59,3 +59,4 @@ apollo_l1_provider = { workspace = true, features = ["testing"] } apollo_mempool = { workspace = true, features = ["testing"] } apollo_mempool_p2p = { workspace = true, features = ["testing"] } apollo_state_sync_metrics = { workspace = true, features = ["testing"] } +rstest.workspace = true diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index f64e06ba693..23fce01d3ad 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -575,7 +575,7 @@ "description": "The number of transactions received by source (over the selected time range)", "type": "stat", "exprs": [ - "sum by (source) (increase(gateway_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) " + "sum by (source) (increase(gateway_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range]))" ], "extra_params": { "log_query": "\"Processing tx\" AND \"is_p2p=\"" @@ -586,7 +586,7 @@ "description": "The number of transactions received by type (over the selected time range)", "type": "stat", "exprs": [ - "sum by (tx_type) (increase(gateway_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range])) " + "sum by (tx_type) (increase(gateway_transactions_received{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range]))" ], "extra_params": { "log_query": "\"Processing tx\"" @@ -617,7 +617,7 @@ "description": "The number of transactions sent to mempool by type (over the selected time range)", "type": "stat", "exprs": [ - "sum by (tx_type) (increase(gateway_transactions_sent_to_mempool{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range]))" + "sum by (tx_type) (increase(gateway_transactions_sent_to_mempool{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range]))" ], "extra_params": {} }, @@ -673,7 +673,7 @@ "description": "Number of transactions dropped from the mempool by reason (over the selected time range)", "type": "stat", "exprs": [ - "sum by (drop_reason) (increase(mempool_transactions_dropped{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range]))" + "sum by (drop_reason) (increase(mempool_transactions_dropped{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__range]))" ], "extra_params": {} }, @@ -1009,7 +1009,7 @@ }, { "title": "Number of Classes", - "description": "Number of classes, labeled by type (regular, deprecated)", + "description": "Number of classes, labeled by type (regular, deprecated) (10m window)", "type": "stat", "exprs": [ "sum by (class_type) (increase(class_manager_n_classes{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m]))" diff --git a/crates/apollo_dashboard/src/panels/batcher.rs b/crates/apollo_dashboard/src/panels/batcher.rs index b160051af3e..12b66b07f1b 100644 --- a/crates/apollo_dashboard/src/panels/batcher.rs +++ b/crates/apollo_dashboard/src/panels/batcher.rs @@ -15,8 +15,7 @@ use apollo_consensus_orchestrator::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; -use crate::query_builder; -use crate::query_builder::DEFAULT_DURATION; +use crate::query_builder::{increase, sum_by_label, DisplayMethod, DEFAULT_DURATION}; fn get_panel_validator_wasted_txs() -> Panel { Panel::new( @@ -25,7 +24,7 @@ fn get_panel_validator_wasted_txs() -> Panel { "Number of txs executed by the validator but excluded from the block \ ({DEFAULT_DURATION} window)", ), - query_builder::increase(&VALIDATOR_WASTED_TXS, DEFAULT_DURATION), + increase(&VALIDATOR_WASTED_TXS, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("Finished building block as validator. Started executing") @@ -38,7 +37,7 @@ fn get_panel_proposer_deferred_txs() -> Panel { "Number of txs started execution by the proposer but excluded from the block \ ({DEFAULT_DURATION} window)", ), - query_builder::increase(&PROPOSER_DEFERRED_TXS, DEFAULT_DURATION), + increase(&PROPOSER_DEFERRED_TXS, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("Finished building block as proposer. Started executing") @@ -55,14 +54,14 @@ fn get_panel_storage_height() -> Panel { } fn get_panel_rejection_reverted_ratio() -> Panel { - let rejected_txs_expr = query_builder::increase(&REJECTED_TRANSACTIONS, DEFAULT_DURATION); - let reverted_txs_expr = query_builder::increase(&REVERTED_TRANSACTIONS, DEFAULT_DURATION); + let rejected_txs_expr = increase(&REJECTED_TRANSACTIONS, DEFAULT_DURATION); + let reverted_txs_expr = increase(&REVERTED_TRANSACTIONS, DEFAULT_DURATION); let denominator_expr = format!( "({} + {} + {})", rejected_txs_expr, reverted_txs_expr, - query_builder::increase(&BATCHED_TRANSACTIONS, DEFAULT_DURATION), + increase(&BATCHED_TRANSACTIONS, DEFAULT_DURATION), ); Panel::new( "Rejected / Reverted TXs Ratio", @@ -93,11 +92,12 @@ pub(crate) fn get_panel_batched_transactions_rate() -> Panel { fn get_panel_block_close_reasons() -> Panel { Panel::new( "Block Close Reasons", - "Number of blocks closed by reason (10m window)", - format!( - "sum by ({}) (increase({}[10m]))", + format!("Number of blocks closed by reason ({} window)", DEFAULT_DURATION), + sum_by_label( + &BLOCK_CLOSE_REASON, LABEL_NAME_BLOCK_CLOSE_REASON, - BLOCK_CLOSE_REASON.get_name_with_filter() + DisplayMethod::Increase(DEFAULT_DURATION), + false, ), PanelType::Stat, ) diff --git a/crates/apollo_dashboard/src/panels/consensus.rs b/crates/apollo_dashboard/src/panels/consensus.rs index 8e0c18b3c66..d8825b2be69 100644 --- a/crates/apollo_dashboard/src/panels/consensus.rs +++ b/crates/apollo_dashboard/src/panels/consensus.rs @@ -46,8 +46,13 @@ use apollo_network::network_manager::metrics::{ use apollo_state_sync_metrics::metrics::STATE_SYNC_CLASS_MANAGER_MARKER; use crate::dashboard::{Panel, PanelType, Row, Unit}; -use crate::query_builder; -use crate::query_builder::DEFAULT_DURATION; +use crate::query_builder::{ + increase, + sum_by_label, + DisplayMethod, + DEFAULT_DURATION, + RANGE_DURATION, +}; // The key events that are relevant to the consensus panel. const CONSENSUS_KEY_EVENTS_LOG_QUERY: &str = @@ -100,7 +105,7 @@ pub(crate) fn get_panel_consensus_round_advanced() -> Panel { "The number of times the consensus round advanced (counter is increased whenever \ round > 0) ({DEFAULT_DURATION} window)", ), - query_builder::increase(&CONSENSUS_ROUND_ADVANCES, DEFAULT_DURATION), + increase(&CONSENSUS_ROUND_ADVANCES, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"START_ROUND\" OR \"PROPOSAL_FAILED\" OR textPayload=~\"DECISION_REACHED\"") @@ -135,7 +140,7 @@ fn get_panel_consensus_decisions_reached_by_consensus() -> Panel { Panel::new( "Decisions Reached By Consensus", format!("The number of decisions reached by way of consensus ({DEFAULT_DURATION} window)",), - query_builder::increase(&CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, DEFAULT_DURATION), + increase(&CONSENSUS_DECISIONS_REACHED_BY_CONSENSUS, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("DECISION_REACHED: Decision reached for round") @@ -146,7 +151,7 @@ fn get_panel_consensus_decisions_reached_by_sync() -> Panel { Panel::new( "Decisions Reached By Sync", format!("The number of decisions reached by way of sync ({DEFAULT_DURATION} window)",), - query_builder::increase(&CONSENSUS_DECISIONS_REACHED_BY_SYNC, DEFAULT_DURATION), + increase(&CONSENSUS_DECISIONS_REACHED_BY_SYNC, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("Decision learned via sync protocol.") @@ -157,7 +162,7 @@ fn get_panel_consensus_proposals_received() -> Panel { Panel::new( "Proposal Validation: Number of Received Proposals", format!("The number of proposals received from the network ({DEFAULT_DURATION} window)",), - query_builder::increase(&CONSENSUS_PROPOSALS_RECEIVED, DEFAULT_DURATION), + increase(&CONSENSUS_PROPOSALS_RECEIVED, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -169,7 +174,7 @@ fn get_panel_consensus_proposals_validated() -> Panel { "The number of proposals received and validated successfully ({DEFAULT_DURATION} \ window)", ), - query_builder::increase(&CONSENSUS_PROPOSALS_VALIDATED, DEFAULT_DURATION), + increase(&CONSENSUS_PROPOSALS_VALIDATED, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") @@ -182,7 +187,7 @@ fn get_panel_consensus_proposals_invalid() -> Panel { format!( "The number of proposals received and failed validation ({DEFAULT_DURATION} window)", ), - query_builder::increase(&CONSENSUS_PROPOSALS_INVALID, DEFAULT_DURATION), + increase(&CONSENSUS_PROPOSALS_INVALID, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"Validated proposal.\" OR \"PROPOSAL_FAILED\"") @@ -193,10 +198,11 @@ fn get_panel_validate_proposal_failure() -> Panel { Panel::new( "Proposal Validation: Proposal Failure by Reason", "The number of validate proposal failures (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range])) > 0", + sum_by_label( + &CONSENSUS_VALIDATE_PROPOSAL_FAILURE, LABEL_VALIDATE_PROPOSAL_FAILURE_REASON, - CONSENSUS_VALIDATE_PROPOSAL_FAILURE.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + true, ), PanelType::Stat, ) @@ -208,7 +214,7 @@ fn get_panel_consensus_build_proposal_total() -> Panel { Panel::new( "Proposal Build: Number of Proposals Started", format!("The number of proposals that started building ({DEFAULT_DURATION} window)",), - query_builder::increase(&CONSENSUS_BUILD_PROPOSAL_TOTAL, DEFAULT_DURATION), + increase(&CONSENSUS_BUILD_PROPOSAL_TOTAL, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -217,7 +223,7 @@ fn get_panel_consensus_build_proposal_failed() -> Panel { Panel::new( "Proposal Build: Number of Proposals Failed", format!("The number of proposals that failed to be built ({DEFAULT_DURATION} window)",), - query_builder::increase(&CONSENSUS_BUILD_PROPOSAL_FAILED, DEFAULT_DURATION), + increase(&CONSENSUS_BUILD_PROPOSAL_FAILED, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -226,10 +232,11 @@ fn get_panel_build_proposal_failure() -> Panel { Panel::new( "Proposal Build: Proposal Failure by Reason", "The number of build proposal failures (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range])) > 0", + sum_by_label( + &CONSENSUS_BUILD_PROPOSAL_FAILURE, LABEL_BUILD_PROPOSAL_FAILURE_REASON, - CONSENSUS_BUILD_PROPOSAL_FAILURE.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + true, ), PanelType::Stat, ) @@ -240,16 +247,19 @@ fn get_panel_build_proposal_failure() -> Panel { fn get_panel_consensus_timeouts_by_type() -> Panel { Panel::new( "Consensus Timeouts By Type", - "The number of times consensus has timed out by type (10m window). \n- TimeoutPropose: as \ - proposer, didn’t finish building in time; as validator, either didn’t receive the \ - proposal or didn’t finish validation in time.\n- TimeoutPrevote: the node voted and \ - received a quorum of prevotes, but not on the same value.\n- TimeoutPrecommit: didn’t \ - finish validation but quorum of precommits received, or it finished but no decision \ - reached.", format!( - "sum by ({}) (increase({}[10m]))", + "The number of times consensus has timed out by type ({DEFAULT_DURATION} window). \n- \ + TimeoutPropose: as proposer, didn’t finish building in time; as validator, either \ + didn’t receive the proposal or didn’t finish validation in time.\n- TimeoutPrevote: \ + the node voted and received a quorum of prevotes, but not on the same value.\n- \ + TimeoutPrecommit: didn’t finish validation but quorum of precommits received, or it \ + finished but no decision reached." + ), + sum_by_label( + &CONSENSUS_TIMEOUTS, LABEL_NAME_TIMEOUT_TYPE, - CONSENSUS_TIMEOUTS.get_name_with_filter() + DisplayMethod::Increase(DEFAULT_DURATION), + false, ), PanelType::TimeSeries, ) @@ -296,7 +306,7 @@ fn get_panel_cende_write_blob_success() -> Panel { Panel::new( "Write Blob Success", format!("The number of successful blob writes to Cende ({DEFAULT_DURATION} window)"), - query_builder::increase(&CENDE_WRITE_BLOB_SUCCESS, DEFAULT_DURATION), + increase(&CENDE_WRITE_BLOB_SUCCESS, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query(query_expression) @@ -305,11 +315,12 @@ fn get_panel_cende_write_blob_success() -> Panel { fn get_panel_cende_write_blob_failure() -> Panel { Panel::new( "Write Blob Failure by Reason", - "The number of failed blob writes to Cende (10m window)", - format!( - "sum by ({}) (increase({}[10m]))", + format!("The number of failed blob writes to Cende ({} window)", DEFAULT_DURATION), + sum_by_label( + &CENDE_WRITE_BLOB_FAILURE, LABEL_CENDE_FAILURE_REASON, - CENDE_WRITE_BLOB_FAILURE.get_name_with_filter() + DisplayMethod::Increase(DEFAULT_DURATION), + false, ), PanelType::TimeSeries, ) @@ -323,7 +334,7 @@ fn get_panel_cende_write_preconfirmed_block() -> Panel { "The number of successful writes to Cende for preconfirmed blocks ({DEFAULT_DURATION} \ window). Each preconfirmed block may involve multiple writes.", ), - query_builder::increase(&PRECONFIRMED_BLOCK_WRITTEN, DEFAULT_DURATION), + increase(&PRECONFIRMED_BLOCK_WRITTEN, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("write_pre_confirmed_block request succeeded.") @@ -343,7 +354,7 @@ fn get_panel_consensus_votes_num_sent_messages() -> Panel { "Consensus Votes Number of Sent Messages", "The increase in the number of vote messages sent by consensus p2p (over the selected \ time range)", - query_builder::increase(&CONSENSUS_VOTES_NUM_SENT_MESSAGES, "$__range"), + increase(&CONSENSUS_VOTES_NUM_SENT_MESSAGES, "$__range"), PanelType::Stat, ) } @@ -353,7 +364,7 @@ fn get_panel_consensus_votes_num_received_messages() -> Panel { "Consensus Votes Number of Received Messages", "The increase in the number of vote messages received by consensus p2p (over the selected \ time range)", - query_builder::increase(&CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, "$__range"), + increase(&CONSENSUS_VOTES_NUM_RECEIVED_MESSAGES, "$__range"), PanelType::Stat, ) } @@ -363,7 +374,7 @@ fn get_panel_consensus_proposals_num_sent_messages() -> Panel { "Consensus Proposals Number of Sent Messages", "The increase in the number of proposal messages sent by consensus p2p (over the selected \ time range)", - query_builder::increase(&CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, "$__range"), + increase(&CONSENSUS_PROPOSALS_NUM_SENT_MESSAGES, "$__range"), PanelType::Stat, ) } @@ -373,7 +384,7 @@ fn get_panel_consensus_proposals_num_received_messages() -> Panel { "Consensus Proposals Number of Received Messages", "The increase in the number of proposal messages received by consensus p2p (over the \ selected time range)", - query_builder::increase(&CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, "$__range"), + increase(&CONSENSUS_PROPOSALS_NUM_RECEIVED_MESSAGES, "$__range"), PanelType::Stat, ) } @@ -382,7 +393,7 @@ fn get_panel_consensus_conflicting_votes() -> Panel { Panel::new( "Consensus Conflicting Votes", "The increase in the number of conflicting votes (over the selected time range)", - query_builder::increase(&CONSENSUS_CONFLICTING_VOTES, "$__range"), + increase(&CONSENSUS_CONFLICTING_VOTES, "$__range"), PanelType::Stat, ) } @@ -391,10 +402,11 @@ fn get_panel_consensus_network_events_by_type() -> Panel { Panel::new( "Consensus Network Events By Type", "Network events received by consensus p2p, by event type (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range])) > 0", + sum_by_label( + &CONSENSUS_NETWORK_EVENTS, LABEL_NAME_EVENT_TYPE, - CONSENSUS_NETWORK_EVENTS.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + true, ), PanelType::Stat, ) @@ -404,10 +416,11 @@ fn get_panel_consensus_votes_dropped_messages_by_reason() -> Panel { Panel::new( "Consensus Votes Dropped Messages By Reason", "The number of dropped consensus votes messages, by reason (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range])) > 0", + sum_by_label( + &CONSENSUS_VOTES_NUM_DROPPED_MESSAGES, LABEL_NAME_BROADCAST_DROP_REASON, - CONSENSUS_VOTES_NUM_DROPPED_MESSAGES.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + true, ), PanelType::Stat, ) @@ -418,10 +431,11 @@ fn get_panel_consensus_proposals_dropped_messages_by_reason() -> Panel { "Consensus Proposals Dropped Messages By Reason", "The number of dropped consensus proposals messages, by reason (over the selected time \ range)", - format!( - "sum by ({}) (increase({}[$__range])) > 0", + sum_by_label( + &CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES, LABEL_NAME_BROADCAST_DROP_REASON, - CONSENSUS_PROPOSALS_NUM_DROPPED_MESSAGES.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + true, ), PanelType::Stat, ) @@ -434,7 +448,7 @@ fn get_panel_consensus_decisions_reached_as_proposer() -> Panel { "The number of rounds with decision reached where this node is the proposer \ ({DEFAULT_DURATION} window)", ), - query_builder::increase(&CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, DEFAULT_DURATION), + increase(&CONSENSUS_DECISIONS_REACHED_AS_PROPOSER, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"Building proposal\" OR \"BATCHER_FIN_PROPOSER\"") diff --git a/crates/apollo_dashboard/src/panels/gateway.rs b/crates/apollo_dashboard/src/panels/gateway.rs index f435a40904d..9e5726911ca 100644 --- a/crates/apollo_dashboard/src/panels/gateway.rs +++ b/crates/apollo_dashboard/src/panels/gateway.rs @@ -14,15 +14,17 @@ use apollo_gateway::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; +use crate::query_builder::{sum_by_label, DisplayMethod, RANGE_DURATION}; fn get_panel_gateway_transactions_received_by_type() -> Panel { Panel::new( "Transactions Received by Type", "The number of transactions received by type (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range])) ", + sum_by_label( + &GATEWAY_TRANSACTIONS_RECEIVED, GATEWAY_LABEL_NAME_TX_TYPE, - GATEWAY_TRANSACTIONS_RECEIVED.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + false, ), PanelType::Stat, ) @@ -33,10 +35,11 @@ fn get_panel_gateway_transactions_received_by_source() -> Panel { Panel::new( "Transactions Received by Source", "The number of transactions received by source (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range])) ", + sum_by_label( + &GATEWAY_TRANSACTIONS_RECEIVED, LABEL_NAME_SOURCE, - GATEWAY_TRANSACTIONS_RECEIVED.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + false, ), PanelType::Stat, ) @@ -77,27 +80,34 @@ pub(crate) fn get_panel_gateway_add_tx_failure_by_reason() -> Panel { Panel::new( "Transactions Failed by Reason", "The number of transactions failed by reason (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range])) > 0", + sum_by_label( + &GATEWAY_ADD_TX_FAILURE, LABEL_NAME_ADD_TX_FAILURE_REASON, - GATEWAY_ADD_TX_FAILURE.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + true, ), PanelType::Stat, ) } fn get_panel_gateway_transactions_failure_rate() -> Panel { + let sum_failed = sum_by_label( + &GATEWAY_TRANSACTIONS_FAILED, + GATEWAY_LABEL_NAME_TX_TYPE, + DisplayMethod::Increase(RANGE_DURATION), + false, + ); + let sum_received = sum_by_label( + &GATEWAY_TRANSACTIONS_RECEIVED, + GATEWAY_LABEL_NAME_TX_TYPE, + DisplayMethod::Increase(RANGE_DURATION), + false, + ); Panel::new( "Transaction Failure Rate by Type", "The rate of failed transactions vs received transactions by type (over the selected time \ range)", - format!( - "(sum by ({}) (increase({}[$__range])) / sum by ({}) (increase({}[$__range])))", - GATEWAY_LABEL_NAME_TX_TYPE, - GATEWAY_TRANSACTIONS_FAILED.get_name_with_filter(), - GATEWAY_LABEL_NAME_TX_TYPE, - GATEWAY_TRANSACTIONS_RECEIVED.get_name_with_filter() - ), + format!("({sum_failed} / {sum_received})",), PanelType::Stat, ) .with_unit(Unit::PercentUnit) @@ -107,10 +117,11 @@ fn get_panel_gateway_transactions_sent_to_mempool() -> Panel { Panel::new( "Transactions Sent to Mempool by Type", "The number of transactions sent to mempool by type (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range]))", + sum_by_label( + &GATEWAY_TRANSACTIONS_SENT_TO_MEMPOOL, GATEWAY_LABEL_NAME_TX_TYPE, - GATEWAY_TRANSACTIONS_SENT_TO_MEMPOOL.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + false, ), PanelType::Stat, ) diff --git a/crates/apollo_dashboard/src/panels/http_server.rs b/crates/apollo_dashboard/src/panels/http_server.rs index 95f9bcbcd39..0fccf45b333 100644 --- a/crates/apollo_dashboard/src/panels/http_server.rs +++ b/crates/apollo_dashboard/src/panels/http_server.rs @@ -9,14 +9,13 @@ use apollo_http_server::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; -use crate::query_builder; -use crate::query_builder::DEFAULT_DURATION; +use crate::query_builder::{increase, DEFAULT_DURATION}; fn get_panel_total_transactions_received() -> Panel { Panel::new( "Transactions Received", format!("Number of transactions received ({DEFAULT_DURATION} window)"), - query_builder::increase(&ADDED_TRANSACTIONS_TOTAL, DEFAULT_DURATION), + increase(&ADDED_TRANSACTIONS_TOTAL, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("\"ADD_TX_START\"") @@ -31,8 +30,8 @@ fn get_panel_transaction_success_rate() -> Panel { ), format!( "{s} / ({s} + {f})", - s = query_builder::increase(&ADDED_TRANSACTIONS_SUCCESS, DEFAULT_DURATION), - f = query_builder::increase(&ADDED_TRANSACTIONS_FAILURE, DEFAULT_DURATION), + s = increase(&ADDED_TRANSACTIONS_SUCCESS, DEFAULT_DURATION), + f = increase(&ADDED_TRANSACTIONS_FAILURE, DEFAULT_DURATION), ), PanelType::TimeSeries, ) diff --git a/crates/apollo_dashboard/src/panels/l1_gas_price.rs b/crates/apollo_dashboard/src/panels/l1_gas_price.rs index 190c8f77efe..32633f12493 100644 --- a/crates/apollo_dashboard/src/panels/l1_gas_price.rs +++ b/crates/apollo_dashboard/src/panels/l1_gas_price.rs @@ -14,14 +14,13 @@ use apollo_l1_gas_price_types::DEFAULT_ETH_TO_FRI_RATE; use apollo_metrics::MetricCommon; use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; -use crate::query_builder; -use crate::query_builder::DEFAULT_DURATION; +use crate::query_builder::{increase, DEFAULT_DURATION}; fn get_panel_eth_to_strk_error_count() -> Panel { Panel::new( "ETH→STRK Rate Query Error Count", format!("The number of times the ETH→STRK rate query failed ({DEFAULT_DURATION} window)"), - query_builder::increase(Ð_TO_STRK_ERROR_COUNT, DEFAULT_DURATION), + increase(Ð_TO_STRK_ERROR_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -65,7 +64,7 @@ fn get_panel_l1_gas_price_provider_insufficient_history() -> Panel { "The number of times the L1 gas price provider calculated an average with too few \ blocks ({DEFAULT_DURATION} window)", ), - query_builder::increase(&L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, DEFAULT_DURATION), + increase(&L1_GAS_PRICE_PROVIDER_INSUFFICIENT_HISTORY, DEFAULT_DURATION), PanelType::TimeSeries, ) .with_log_query("Not enough history to calculate the mean gas price.") @@ -78,7 +77,7 @@ fn get_panel_l1_gas_price_scraper_success_count() -> Panel { "The number of times the L1 gas price scraper successfully scraped and updated gas \ prices ({DEFAULT_DURATION} window)", ), - query_builder::increase(&L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, DEFAULT_DURATION), + increase(&L1_GAS_PRICE_SCRAPER_SUCCESS_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -90,7 +89,7 @@ fn get_panel_l1_gas_price_scraper_baselayer_error_count() -> Panel { "The number of times the L1 gas price scraper encountered an error while scraping the \ base layer ({DEFAULT_DURATION} window)", ), - query_builder::increase(&L1_GAS_PRICE_SCRAPER_BASELAYER_ERROR_COUNT, DEFAULT_DURATION), + increase(&L1_GAS_PRICE_SCRAPER_BASELAYER_ERROR_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -102,7 +101,7 @@ fn get_panel_l1_gas_price_scraper_reorg_detected() -> Panel { "The number of times the L1 gas price scraper detected a reorganization in the base \ layer ({DEFAULT_DURATION} window)", ), - query_builder::increase(&L1_GAS_PRICE_SCRAPER_REORG_DETECTED, DEFAULT_DURATION), + increase(&L1_GAS_PRICE_SCRAPER_REORG_DETECTED, DEFAULT_DURATION), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/l1_provider.rs b/crates/apollo_dashboard/src/panels/l1_provider.rs index d8e6eb86945..aab561df0cc 100644 --- a/crates/apollo_dashboard/src/panels/l1_provider.rs +++ b/crates/apollo_dashboard/src/panels/l1_provider.rs @@ -6,8 +6,7 @@ use apollo_l1_provider::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{get_time_since_last_increase_expr, Panel, PanelType, Row, Unit}; -use crate::query_builder; -use crate::query_builder::DEFAULT_DURATION; +use crate::query_builder::{increase, DEFAULT_DURATION}; fn get_panel_l1_message_scraper_success_count() -> Panel { Panel::new( @@ -16,7 +15,7 @@ fn get_panel_l1_message_scraper_success_count() -> Panel { "The increase in the number of times the L1 message scraper successfully scraped \ messages ({DEFAULT_DURATION} window)", ), - query_builder::increase(&L1_MESSAGE_SCRAPER_SUCCESS_COUNT, DEFAULT_DURATION), + increase(&L1_MESSAGE_SCRAPER_SUCCESS_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -27,7 +26,7 @@ fn get_panel_l1_message_scraper_baselayer_error_count() -> Panel { "The increase in the number of times the L1 message scraper encountered an error \ while scraping the base layer ({DEFAULT_DURATION} window)", ), - query_builder::increase(&L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT, DEFAULT_DURATION), + increase(&L1_MESSAGE_SCRAPER_BASELAYER_ERROR_COUNT, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -35,7 +34,7 @@ fn get_panel_l1_message_scraper_reorg_detected() -> Panel { Panel::new( "L1 Message Scraper Reorg Detected", "The increase in the number of times the L1 message scraper detected a reorg (12h window)", - query_builder::increase(&L1_MESSAGE_SCRAPER_REORG_DETECTED, "12h"), + increase(&L1_MESSAGE_SCRAPER_REORG_DETECTED, "12h"), PanelType::TimeSeries, ) } diff --git a/crates/apollo_dashboard/src/panels/mempool.rs b/crates/apollo_dashboard/src/panels/mempool.rs index 2a9903c84d5..d1b346f8d5d 100644 --- a/crates/apollo_dashboard/src/panels/mempool.rs +++ b/crates/apollo_dashboard/src/panels/mempool.rs @@ -14,8 +14,13 @@ use apollo_mempool::metrics::{ use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; -use crate::query_builder; -use crate::query_builder::DEFAULT_DURATION; +use crate::query_builder::{ + increase, + sum_by_label, + DisplayMethod, + DEFAULT_DURATION, + RANGE_DURATION, +}; fn get_panel_mempool_transactions_received_rate() -> Panel { Panel::new( @@ -33,7 +38,7 @@ fn get_panel_mempool_transactions_committed() -> Panel { Panel::new( "Transactions Committed", format!("Number of transactions committed to a block ({DEFAULT_DURATION} window)"), - query_builder::increase(&MEMPOOL_TRANSACTIONS_COMMITTED, DEFAULT_DURATION), + increase(&MEMPOOL_TRANSACTIONS_COMMITTED, DEFAULT_DURATION), PanelType::TimeSeries, ) } @@ -41,10 +46,11 @@ fn get_panel_mempool_transactions_dropped() -> Panel { Panel::new( "Dropped Transactions by Reason", "Number of transactions dropped from the mempool by reason (over the selected time range)", - format!( - "sum by ({}) (increase({}[$__range]))", + sum_by_label( + &MEMPOOL_TRANSACTIONS_DROPPED, LABEL_NAME_DROP_REASON, - MEMPOOL_TRANSACTIONS_DROPPED.get_name_with_filter() + DisplayMethod::Increase(RANGE_DURATION), + false, ), PanelType::Stat, ) diff --git a/crates/apollo_dashboard/src/panels/mempool_p2p.rs b/crates/apollo_dashboard/src/panels/mempool_p2p.rs index c7215abf83f..d215d5fab85 100644 --- a/crates/apollo_dashboard/src/panels/mempool_p2p.rs +++ b/crates/apollo_dashboard/src/panels/mempool_p2p.rs @@ -13,6 +13,7 @@ use apollo_network::network_manager::metrics::{ }; use crate::dashboard::{Panel, PanelType, Row}; +use crate::query_builder::{sum_by_label, DisplayMethod}; fn get_panel_mempool_p2p_num_connected_peers() -> Panel { Panel::from_gauge(&MEMPOOL_P2P_NUM_CONNECTED_PEERS, PanelType::TimeSeries) @@ -38,11 +39,7 @@ fn get_panel_mempool_p2p_network_events_by_type() -> Panel { Panel::new( MEMPOOL_P2P_NETWORK_EVENTS.get_name(), MEMPOOL_P2P_NETWORK_EVENTS.get_description(), - format!( - "sum by ({}) ({})", - LABEL_NAME_EVENT_TYPE, - MEMPOOL_P2P_NETWORK_EVENTS.get_name_with_filter() - ), + sum_by_label(&MEMPOOL_P2P_NETWORK_EVENTS, LABEL_NAME_EVENT_TYPE, DisplayMethod::Raw, false), PanelType::TimeSeries, ) } @@ -51,10 +48,11 @@ fn get_panel_mempool_p2p_dropped_messages_by_reason() -> Panel { Panel::new( MEMPOOL_P2P_NUM_DROPPED_MESSAGES.get_name(), MEMPOOL_P2P_NUM_DROPPED_MESSAGES.get_description(), - format!( - "sum by ({}) ({})", + sum_by_label( + &MEMPOOL_P2P_NUM_DROPPED_MESSAGES, LABEL_NAME_BROADCAST_DROP_REASON, - MEMPOOL_P2P_NUM_DROPPED_MESSAGES.get_name_with_filter() + DisplayMethod::Raw, + false, ), PanelType::TimeSeries, ) diff --git a/crates/apollo_dashboard/src/panels/sierra_compiler.rs b/crates/apollo_dashboard/src/panels/sierra_compiler.rs index 0a6b6253b3c..81b65d375f7 100644 --- a/crates/apollo_dashboard/src/panels/sierra_compiler.rs +++ b/crates/apollo_dashboard/src/panels/sierra_compiler.rs @@ -1,8 +1,8 @@ use apollo_class_manager::metrics::{CLASS_SIZES, N_CLASSES}; use apollo_compile_to_casm::metrics::COMPILATION_DURATION; -use apollo_metrics::MetricCommon; use crate::dashboard::{Panel, PanelType, Row, Unit}; +use crate::query_builder::{sum_by_label, DisplayMethod, DEFAULT_DURATION}; fn get_panel_compilation_duration() -> Panel { Panel::from_hist( @@ -15,8 +15,10 @@ fn get_panel_compilation_duration() -> Panel { fn get_panel_n_classes() -> Panel { Panel::new( "Number of Classes", - "Number of classes, labeled by type (regular, deprecated)", - format!("sum by ({}) (increase({}[10m]))", "class_type", N_CLASSES.get_name_with_filter()), + format!( + "Number of classes, labeled by type (regular, deprecated) ({DEFAULT_DURATION} window)" + ), + sum_by_label(&N_CLASSES, "class_type", DisplayMethod::Increase(DEFAULT_DURATION), false), PanelType::Stat, ) } diff --git a/crates/apollo_dashboard/src/query_builder.rs b/crates/apollo_dashboard/src/query_builder.rs index 55452366a9b..e7a37a60f92 100644 --- a/crates/apollo_dashboard/src/query_builder.rs +++ b/crates/apollo_dashboard/src/query_builder.rs @@ -5,7 +5,47 @@ use apollo_metrics::metrics::MetricCommon; pub mod query_builder_test; pub(crate) const DEFAULT_DURATION: &str = "10m"; +// Expands to the currently selected dashboard time range +pub(crate) const RANGE_DURATION: &str = "$__range"; +#[derive(Clone, Debug, Eq, PartialEq)] +pub(crate) enum DisplayMethod<'a> { + Increase(&'a str), // duration + Raw, +} + +/// Builds `increase([])` for counters. +/// +/// - `metric`: source metric (with any label filters). +/// - `duration`: range window, e.g. `"5m"`, `"1h"`. +/// +/// Example: `increase(m, "5m")` → `increase(http_requests_total{...}[5m])` pub(crate) fn increase(metric: &dyn MetricCommon, duration: &str) -> String { format!("increase({}[{}])", metric.get_name_with_filter(), duration) } + +/// Returns a query string that sums a metric **by a label**, optionally using +/// `increase()` and filtering zeros. +/// +/// - `metric`: provides the metric. +/// - `label`: label key for `sum by (...)`. +/// - `display`: `DisplayMethod::Raw` or `Increase("5m")`. +/// - `filter_zeros`: if `true`, appends ` > 0`. +/// +/// Example: +/// `sum_by_label(&m, "something", DisplayMethod::Increase("5m"), true)` +/// → `sum by (something) (increase([5m])) > 0` +pub(crate) fn sum_by_label( + metric: &dyn MetricCommon, + label: &str, + display: DisplayMethod<'_>, + filter_zeros: bool, +) -> String { + let inner = match display { + DisplayMethod::Increase(duration) => increase(metric, duration), + DisplayMethod::Raw => metric.get_name_with_filter(), + }; + let filter = if filter_zeros { " > 0" } else { "" }; + + format!("sum by ({}) ({}){}", label, inner, filter) +} diff --git a/crates/apollo_dashboard/src/query_builder_test.rs b/crates/apollo_dashboard/src/query_builder_test.rs index 60bbab71891..fdf48d62a0d 100644 --- a/crates/apollo_dashboard/src/query_builder_test.rs +++ b/crates/apollo_dashboard/src/query_builder_test.rs @@ -1,14 +1,35 @@ use apollo_infra_utils::template::Template; use apollo_metrics::metric_label_filter; use apollo_metrics::metrics::{MetricGauge, MetricScope}; +use rstest::rstest; -use crate::query_builder; +use crate::query_builder::{increase, sum_by_label, DisplayMethod}; #[test] fn increase_formats_correctly() { let m = MetricGauge::new(MetricScope::Batcher, "testing", "Fake description"); - let q = query_builder::increase(&m, "5m"); + let q = increase(&m, "5m"); let expected = Template::new("increase({}{}[{}])").format(&[&"testing", &metric_label_filter!(), &"5m"]); assert_eq!(q, expected); } + +#[rstest] +#[case::raw_filtered(DisplayMethod::Raw, true)] +#[case::increase_filtered(DisplayMethod::Increase("5m"), true)] +#[case::raw_unfiltered(DisplayMethod::Raw, false)] +#[case::increase_unfiltered(DisplayMethod::Increase("15h"), false)] +fn sum_by_label_formats_correctly(#[case] display: DisplayMethod<'_>, #[case] filter_zeros: bool) { + let m = MetricGauge::new(MetricScope::Batcher, "testing", "Fake description"); + let inner = match display { + DisplayMethod::Increase(duration) => increase(&m, duration), + DisplayMethod::Raw => Template::new("{}{}").format(&[&"testing", &metric_label_filter!()]), + }; + let filter = match filter_zeros { + true => " > 0", + false => "", + }; + let q = sum_by_label(&m, "label1", display, filter_zeros); + let expected = Template::new("sum by ({}) ({}){}").format(&[&"label1", &inner, &filter]); + assert_eq!(q, expected); +} From 3c013fcf4c43b00d055dfb62f3324227ffcf5ecd Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Tue, 4 Nov 2025 14:46:06 +0200 Subject: [PATCH 263/313] scripts: Add a new restarter that gates on metrics (#9925) --- scripts/prod/metrics_lib.py | 29 +++++---- scripts/prod/restarter_lib.py | 112 ++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 15 deletions(-) diff --git a/scripts/prod/metrics_lib.py b/scripts/prod/metrics_lib.py index e4403855f07..701891b5d18 100644 --- a/scripts/prod/metrics_lib.py +++ b/scripts/prod/metrics_lib.py @@ -9,10 +9,9 @@ import socket import urllib.error import urllib.request +from common_lib import Colors, get_namespace_args, print_colored, print_error from prometheus_client.parser import text_string_to_metric_families -from scripts.prod.common_lib import Colors, get_namespace_args, print_colored, print_error - class MetricConditionGater: """Gates progress on a metric satisfying a condition. @@ -20,32 +19,32 @@ class MetricConditionGater: This class was meant to be used with counter/gauge metrics. It may not work properly with histogram metrics. """ - class MetricCondition: + class Metric: def __init__( self, + name: str, value_condition: Callable[[Any], bool], condition_description: Optional[str] = None, ): + self.name = name self.value_condition = value_condition self.condition_description = condition_description def __init__( self, - metric_name: str, + metric: "MetricConditionGater.Metric", namespace: str, cluster: Optional[str], pod: str, metrics_port: int, - metric_value_condition: "MetricConditionGater.MetricCondition", refresh_interval_seconds: int = 3, ): - self.metric_name = metric_name + self.metric = metric self.local_port = self._get_free_port() self.namespace = namespace self.cluster = cluster self.pod = pod self.metrics_port = metrics_port - self.metric_value_condition = metric_value_condition self.refresh_interval_seconds = refresh_interval_seconds @staticmethod @@ -77,8 +76,8 @@ def _get_metrics_raw_string(self) -> str: def _poll_until_condition_met(self): """Poll metrics until the condition is met for the metric.""" condition_description = ( - f"({self.metric_value_condition.condition_description}) " - if self.metric_value_condition.condition_description is not None + f"({self.metric.condition_description}) " + if self.metric.condition_description is not None else "" ) @@ -89,26 +88,26 @@ def _poll_until_condition_met(self): metric_families = text_string_to_metric_families(metrics) val = None for metric_family in metric_families: - if metric_family.name == self.metric_name: + if metric_family.name == self.metric.name: if len(metric_family.samples) > 1: print_error( - f"Multiple samples found for metric {self.metric_name}. Using the first one.", + f"Multiple samples found for metric {self.metric.name}. Using the first one.", ) val = metric_family.samples[0].value break if val is None: print_colored( - f"Metric '{self.metric_name}' not found in pod {self.pod}. Assuming the node is not ready." + f"Metric '{self.metric.name}' not found in pod {self.pod}. Assuming the node is not ready." ) - elif self.metric_value_condition.value_condition(val): + elif self.metric.value_condition(val): print_colored( - f"Metric {self.metric_name} condition {condition_description}met (value={val})." + f"Metric {self.metric.name} condition {condition_description}met (value={val})." ) return else: print_colored( - f"Metric {self.metric_name} condition {condition_description}not met (value={val}). Continuing to wait." + f"Metric {self.metric.name} condition {condition_description}not met (value={val}). Continuing to wait." ) sleep(self.refresh_interval_seconds) diff --git a/scripts/prod/restarter_lib.py b/scripts/prod/restarter_lib.py index 9a98ac99778..6f7856029bf 100644 --- a/scripts/prod/restarter_lib.py +++ b/scripts/prod/restarter_lib.py @@ -2,6 +2,7 @@ import sys from abc import ABC, abstractmethod +from time import sleep from typing import Callable, Optional from common_lib import ( @@ -15,6 +16,7 @@ run_kubectl_command, wait_until_y_or_n, ) +from metrics_lib import MetricConditionGater def _get_pod_names( @@ -142,3 +144,113 @@ def restart_service(self, instance_index: int) -> bool: """No-op.""" print_colored("\nSkipping pod restart.") return True + + +class WaitOnMetricRestarter(ChecksBetweenRestarts): + def __init__( + self, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + metrics: list["MetricConditionGater.Metric"], + metrics_port: int, + restart_strategy: RestartStrategy, + ): + self.metrics = metrics + self.metrics_port = metrics_port + if restart_strategy == RestartStrategy.ONE_BY_ONE: + check_function = self._check_between_each_restart + elif restart_strategy == RestartStrategy.ALL_AT_ONCE: + check_function = self._check_all_only_after_last_restart + else: + print_error(f"Invalid restart strategy: {restart_strategy} for WaitOnMetricRestarter.") + sys.exit(1) + + super().__init__(namespace_and_instruction_args, service, check_function) + + def _check_between_each_restart(self, instance_index: int) -> bool: + self._wait_for_pod_to_satisfy_condition(instance_index) + if instance_index == self.namespace_and_instruction_args.size() - 1: + # Last instance, no need to prompt the user about the next restart. + return True + return wait_until_y_or_n(f"Do you want to restart the next pod?") + + def _check_all_only_after_last_restart(self, instance_index: int) -> bool: + # Restart all nodes without waiting for confirmation. + if instance_index < self.namespace_and_instruction_args.size() - 1: + return True + + # After the last node has been restarted, wait for all pods to satisfy the condition. + for instance_index in range(self.namespace_and_instruction_args.size()): + self._wait_for_pod_to_satisfy_condition(instance_index) + return True + + def _wait_for_pod_to_satisfy_condition(self, instance_index: int) -> bool: + # The sleep is to prevent the case where we get the pod name of the old pod we just deleted + # instead of the new one. + # TODO(guy.f): Verify this is not the name of the old pod some other way. + sleep(2) + pod_names = WaitOnMetricRestarter._wait_for_pods_to_be_ready( + self.namespace_and_instruction_args.get_namespace(instance_index), + self.namespace_and_instruction_args.get_cluster(instance_index), + self.service, + ) + if pod_names is None: + return False + + for pod_name in pod_names: + for metric in self.metrics: + metric_condition_gater = MetricConditionGater( + metric, + self.namespace_and_instruction_args.get_namespace(instance_index), + self.namespace_and_instruction_args.get_cluster(instance_index), + pod_name, + self.metrics_port, + ) + metric_condition_gater.gate() + + @staticmethod + def _wait_for_pods_to_be_ready( + namespace: str, + cluster: Optional[str], + service: Service, + wait_timeout: int = 180, + num_retry: int = 3, + refresh_delay_sec: int = 3, + ) -> Optional[list[str]]: + """ + Wait for pods to be in ready mode as reported by Kubernetes. + """ + + for i in range(num_retry): + pods = _get_pod_names(namespace, service, 0, cluster) + if pods: + for pod in pods: + print_colored( + f"Waiting for pod {pod} to be ready... (timeout set to {wait_timeout}s)" + ) + kubectl_args = [ + "wait", + "--for=condition=ready", + f"pod/{pod}", + "--timeout", + f"{wait_timeout}s", + ] + kubectl_args.extend(get_namespace_args(namespace, cluster)) + result = run_kubectl_command(kubectl_args, capture_output=False) + + if result.returncode != 0: + print_colored( + f"Timed out waiting for pod {pod} to be ready: {result.stderr}, retrying... (attempt {i + 1}/{num_retry})", + Colors.YELLOW, + ) + break + return pods + else: + print_colored( + f"Could not get pod names for service {service.pod_name}, retrying... (attempt {i + 1}/{num_retry})", + Colors.YELLOW, + ) + sleep(refresh_delay_sec) + + print_error(f"Pods for service {service.pod_name} are not ready after {num_retry} attempts") + return None From 8b83c3b38ecc2fdc690021a12a774fe8729ef2ea Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:55:50 +0200 Subject: [PATCH 264/313] apollo_batcher: use metrics helper function (#9937) --- crates/apollo_batcher/src/block_builder.rs | 34 ++++++---------------- crates/apollo_batcher/src/metrics.rs | 4 +++ 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/crates/apollo_batcher/src/block_builder.rs b/crates/apollo_batcher/src/block_builder.rs index 3cae0f97f44..46364bb15a1 100644 --- a/crates/apollo_batcher/src/block_builder.rs +++ b/crates/apollo_batcher/src/block_builder.rs @@ -51,7 +51,12 @@ use tracing::{debug, error, info, trace, warn}; use crate::block_builder::FailOnErrorCause::L1HandlerTransactionValidationFailed; use crate::cende_client_types::{StarknetClientStateDiff, StarknetClientTransactionReceipt}; -use crate::metrics::{PROPOSER_DEFERRED_TXS, VALIDATOR_WASTED_TXS}; +use crate::metrics::{ + record_block_close_reason, + BlockCloseReason, + PROPOSER_DEFERRED_TXS, + VALIDATOR_WASTED_TXS, +}; use crate::pre_confirmed_block_writer::{CandidateTxSender, PreconfirmedTxSender}; use crate::transaction_executor::TransactionExecutorTrait; use crate::transaction_provider::{TransactionProvider, TransactionProviderError}; @@ -244,14 +249,7 @@ impl BlockBuilder { if self.execution_params.is_validator { return Err(BlockBuilderError::FailOnError(FailOnErrorCause::DeadlineReached)); } - // TODO(Dan): extract to a function (as in record_validate_proposal_failure). - crate::metrics::BLOCK_CLOSE_REASON.increment( - 1, - &[( - crate::metrics::LABEL_NAME_BLOCK_CLOSE_REASON, - crate::metrics::BlockCloseReason::Deadline.into(), - )], - ); + record_block_close_reason(BlockCloseReason::Deadline); break; } @@ -263,14 +261,7 @@ impl BlockBuilder { started (timeout is set to {:?}), finishing block building.", time_since_start, self.execution_params.proposer_idle_detection_delay, ); - // TODO(Dan): extract to a function (as in record_validate_proposal_failure). - crate::metrics::BLOCK_CLOSE_REASON.increment( - 1, - &[( - crate::metrics::LABEL_NAME_BLOCK_CLOSE_REASON, - crate::metrics::BlockCloseReason::IdleExecutionTimeout.into(), - )], - ); + record_block_close_reason(BlockCloseReason::IdleExecutionTimeout); break; } if final_n_executed_txs.is_none() { @@ -293,14 +284,7 @@ impl BlockBuilder { // Call `handle_executed_txs()` once more to get the last results. self.handle_executed_txs().await?; info!("Block is full."); - // TODO(Dan): extract to a function (as in record_validate_proposal_failure). - crate::metrics::BLOCK_CLOSE_REASON.increment( - 1, - &[( - crate::metrics::LABEL_NAME_BLOCK_CLOSE_REASON, - crate::metrics::BlockCloseReason::FullBlock.into(), - )], - ); + record_block_close_reason(BlockCloseReason::FullBlock); break; } diff --git a/crates/apollo_batcher/src/metrics.rs b/crates/apollo_batcher/src/metrics.rs index 3977de392d3..518ef05beef 100644 --- a/crates/apollo_batcher/src/metrics.rs +++ b/crates/apollo_batcher/src/metrics.rs @@ -71,6 +71,10 @@ generate_permutation_labels! { (LABEL_NAME_BLOCK_CLOSE_REASON, BlockCloseReason), } +pub(crate) fn record_block_close_reason(reason: BlockCloseReason) { + BLOCK_CLOSE_REASON.increment(1, &[(LABEL_NAME_BLOCK_CLOSE_REASON, reason.into())]); +} + pub fn register_metrics(storage_height: BlockNumber) { STORAGE_HEIGHT.register(); STORAGE_HEIGHT.set_lossy(storage_height.0); From d2daf9458807a08b37f16130ce9bfa22805a8520 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:39:25 +0200 Subject: [PATCH 265/313] bench_tools: add absolute limits to benchmark runs (#9861) --- crates/bench_tools/src/comparison.rs | 55 ++++++++++++++++++++++++---- crates/bench_tools/src/lib.rs | 2 +- crates/bench_tools/src/main.rs | 16 +++++++- crates/bench_tools/src/runner.rs | 34 +++++++++++++---- crates/bench_tools/src/utils.rs | 24 ++++++++++++ crates/bench_tools/src/utils_test.rs | 40 +++++++++++++++++++- 6 files changed, 154 insertions(+), 17 deletions(-) diff --git a/crates/bench_tools/src/comparison.rs b/crates/bench_tools/src/comparison.rs index 9a8e5f2454f..d8ae1ad25c0 100644 --- a/crates/bench_tools/src/comparison.rs +++ b/crates/bench_tools/src/comparison.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fs; use std::path::PathBuf; @@ -8,7 +9,9 @@ use crate::types::estimates::Estimates; pub struct BenchmarkComparison { pub name: String, pub change_percentage: f64, - pub exceeds_limit: bool, + pub exceeds_regression_limit: bool, + pub absolute_time_ns: f64, + pub exceeds_absolute_limit: bool, } type RegressionError = (String, Vec); @@ -37,6 +40,29 @@ fn load_change_estimates(bench_name: &str) -> Estimates { }) } +/// Loads absolute timing estimates from criterion's new directory for a given benchmark. +/// Panics if the estimates file doesn't exist. +fn load_absolute_estimates(bench_name: &str) -> Estimates { + let estimates_path = + PathBuf::from("target/criterion").join(bench_name).join("new/estimates.json"); + + if !estimates_path.exists() { + panic!( + "Estimates file not found for benchmark '{}': {}\nThis likely means the benchmark \ + hasn't been run yet. Run the benchmark before using comparison features.", + bench_name, + estimates_path.display() + ); + } + + let data = fs::read_to_string(&estimates_path) + .unwrap_or_else(|e| panic!("Failed to read {}: {}", estimates_path.display(), e)); + + serde_json::from_str(&data).unwrap_or_else(|e| { + panic!("Failed to deserialize {}: {}\nContent: {}", estimates_path.display(), e, data) + }) +} + /// Converts change estimates to percentage. /// The mean.point_estimate in change/estimates.json represents fractional change /// (e.g., 0.0706 = 7.06% change). @@ -46,11 +72,12 @@ pub(crate) fn get_regression_percentage(change_estimates: &Estimates) -> f64 { /// Checks all benchmarks for regressions against a specified limit. /// Returns a vector of comparison results for all benchmarks. -/// If any benchmark exceeds the regression limit, returns an error with detailed results. -/// Panics if change file is not found for any benchmark. +/// If any benchmark exceeds the regression limit or absolute time threshold, returns an error with +/// detailed results. Panics if change file is not found for any benchmark. pub fn check_regressions( bench_names: &[&str], regression_limit: f64, + absolute_time_ns_limits: &HashMap, ) -> BenchmarkComparisonsResult { let mut results = Vec::new(); let mut exceeded_count = 0; @@ -58,21 +85,35 @@ pub fn check_regressions( for bench_name in bench_names { let change_estimates = load_change_estimates(bench_name); let change_percentage = get_regression_percentage(&change_estimates); - let exceeds_limit = change_percentage > regression_limit; + let exceeds_regression_limit = change_percentage > regression_limit; + + // Load absolute timing estimates. + let absolute_estimates = load_absolute_estimates(bench_name); + let absolute_time_ns = absolute_estimates.mean.point_estimate; + + // Check if this benchmark has a specific absolute time limit. + let exceeds_absolute_limit = + if let Some(&threshold) = absolute_time_ns_limits.get(*bench_name) { + absolute_time_ns > threshold + } else { + false + }; - if exceeds_limit { + if exceeds_regression_limit || exceeds_absolute_limit { exceeded_count += 1; } results.push(BenchmarkComparison { name: bench_name.to_string(), change_percentage, - exceeds_limit, + exceeds_regression_limit, + absolute_time_ns, + exceeds_absolute_limit, }); } if exceeded_count > 0 { - let error_msg = format!("{} benchmark(s) exceeded regression threshold!", exceeded_count); + let error_msg = format!("{} benchmark(s) exceeded threshold(s)!", exceeded_count); Err((error_msg, results)) } else { Ok(results) diff --git a/crates/bench_tools/src/lib.rs b/crates/bench_tools/src/lib.rs index 9fce6716173..48846898270 100644 --- a/crates/bench_tools/src/lib.rs +++ b/crates/bench_tools/src/lib.rs @@ -8,6 +8,6 @@ pub mod runner; #[cfg(test)] pub mod test_utils; pub mod types; -pub(crate) mod utils; +pub mod utils; #[cfg(test)] mod utils_test; diff --git a/crates/bench_tools/src/main.rs b/crates/bench_tools/src/main.rs index ce38bb985c7..4f39445e8f7 100644 --- a/crates/bench_tools/src/main.rs +++ b/crates/bench_tools/src/main.rs @@ -6,6 +6,7 @@ use bench_tools::types::benchmark_config::{ find_benchmarks_by_package, BENCHMARKS, }; +use bench_tools::utils::parse_absolute_time_limits; use clap::{Parser, Subcommand}; #[derive(Parser)] @@ -45,6 +46,10 @@ enum Commands { /// Maximum acceptable regression percentage (e.g., 5.0 for 5%). #[arg(long)] regression_limit: f64, + /// Set absolute time limit for a specific benchmark (can be used multiple times). + /// Format: --set-absolute-time-ns-limit + #[arg(long, value_names = ["BENCH_NAME", "LIMIT_NS"], num_args = 2, action = clap::ArgAction::Append)] + set_absolute_time_ns_limit: Vec, }, /// List benchmarks for a package. List { @@ -75,18 +80,27 @@ fn main() { bench_tools::runner::run_benchmarks(&benchmarks, input_dir.as_deref(), &out); } - Commands::RunAndCompare { package, out, input_dir, regression_limit } => { + Commands::RunAndCompare { + package, + out, + input_dir, + regression_limit, + set_absolute_time_ns_limit, + } => { let benchmarks = find_benchmarks_by_package(&package); if benchmarks.is_empty() { panic!("No benchmarks found for package: {}", package); } + let absolute_time_ns_limits = parse_absolute_time_limits(set_absolute_time_ns_limit); + bench_tools::runner::run_and_compare_benchmarks( &benchmarks, input_dir.as_deref(), &out, regression_limit, + absolute_time_ns_limits, ); } Commands::List { package } => match package { diff --git a/crates/bench_tools/src/runner.rs b/crates/bench_tools/src/runner.rs index bb3eb8e3348..931168a5087 100644 --- a/crates/bench_tools/src/runner.rs +++ b/crates/bench_tools/src/runner.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fs; use std::path::PathBuf; @@ -113,6 +114,7 @@ pub fn run_and_compare_benchmarks( input_dir: Option<&str>, output_dir: &str, regression_limit: f64, + absolute_time_ns_limits: HashMap, ) { // Run benchmarks first. run_benchmarks(benchmarks, input_dir, output_dir); @@ -123,8 +125,15 @@ pub fn run_and_compare_benchmarks( bench_names.extend(bench.criterion_benchmark_names.unwrap_or(&[bench.name])); } - println!("\n📊 Checking for performance regressions (limit: {}%):", regression_limit); - let regression_result = crate::comparison::check_regressions(&bench_names, regression_limit); + print!("\n📊 Checking for performance regressions (limit: {}%", regression_limit); + if !absolute_time_ns_limits.is_empty() { + print!(", {} benchmark(s) with absolute time limits", absolute_time_ns_limits.len()); + } + let regression_result = crate::comparison::check_regressions( + &bench_names, + regression_limit, + &absolute_time_ns_limits, + ); match regression_result { Ok(_) => { @@ -134,15 +143,26 @@ pub fn run_and_compare_benchmarks( // Some benchmarks exceeded the limit - print detailed results. println!("\nBenchmark Results:"); for result in results { - if result.exceeds_limit { + if result.exceeds_regression_limit { println!( - " ❌ {}: {:+.2}% (EXCEEDS {:.1}% limit)", + " ❌ {}: {:+.2}% (EXCEEDS {:.1}% limit)", result.name, result.change_percentage, regression_limit ); - } else { + } + + if result.exceeds_absolute_limit { + if let Some(&limit) = absolute_time_ns_limits.get(&result.name) { + println!( + " ❌ {}: {:.2}ns (EXCEEDS {:.0}ns limit)", + result.name, result.absolute_time_ns, limit + ); + } + } + + if !result.exceeds_regression_limit && !result.exceeds_absolute_limit { println!( - " ✓ {}: {:+.2}% (within {:.1}% limit)", - result.name, result.change_percentage, regression_limit + " ✓ {}: {:+.2}% | {:.2}ns", + result.name, result.change_percentage, result.absolute_time_ns ); } } diff --git a/crates/bench_tools/src/utils.rs b/crates/bench_tools/src/utils.rs index 43b79528f27..31e5236f5d2 100644 --- a/crates/bench_tools/src/utils.rs +++ b/crates/bench_tools/src/utils.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fs; use std::path::Path; @@ -61,3 +62,26 @@ pub(crate) fn copy_dir_contents(src: &Path, dst: &Path) { } } } + +/// Parses a flat `Vec` of benchmark names and limits into a HashMap. +/// The input vector should contain pairs: [bench_name1, limit1, bench_name2, limit2, ...]. +/// +/// # Panics +/// Panics if any limit value cannot be parsed as f64. +/// Panics if the input vector has an odd number of elements. +pub fn parse_absolute_time_limits(args: Vec) -> HashMap { + assert!( + args.len() % 2 == 0, + "Invalid number of absolute time limits arguments: expected even number, got {}", + args.len() + ); + let mut limits = HashMap::new(); + for chunk in args.chunks(2) { + let bench_name = chunk[0].clone(); + let limit = chunk[1].parse::().unwrap_or_else(|_| { + panic!("Invalid limit value for benchmark '{}': '{}'", bench_name, chunk[1]) + }); + limits.insert(bench_name, limit); + } + limits +} diff --git a/crates/bench_tools/src/utils_test.rs b/crates/bench_tools/src/utils_test.rs index 0127911a357..a2dfb9e32dc 100644 --- a/crates/bench_tools/src/utils_test.rs +++ b/crates/bench_tools/src/utils_test.rs @@ -1,10 +1,11 @@ +use std::collections::HashMap; use std::fs; use std::path::Path; use rstest::rstest; use tempfile::TempDir; -use crate::utils::copy_dir_contents; +use crate::utils::{copy_dir_contents, parse_absolute_time_limits}; /// Helper function to create a test directory structure in a temporary directory. /// Returns the TempDir to keep it alive for the duration of the test. @@ -103,3 +104,40 @@ fn test_copy_nonexistent_source_panics() { let temp_dst = TempDir::new().unwrap(); copy_dir_contents(Path::new("/nonexistent"), temp_dst.path()); } + +#[rstest] +#[case::basic( + vec!["bench1".to_string(), "1.5".to_string()], + HashMap::from([("bench1".to_string(), 1.5)]) +)] +#[case::empty(vec![], HashMap::new())] +#[case::multiple_pairs( + vec![ + "bench1".to_string(), + "1.5".to_string(), + "bench2".to_string(), + "2.7".to_string(), + "bench3".to_string(), + "3.0".to_string(), + ], + HashMap::from([ + ("bench1".to_string(), 1.5), + ("bench2".to_string(), 2.7), + ("bench3".to_string(), 3.0), + ]) +)] +fn test_parse_absolute_time_limits( + #[case] args: Vec, + #[case] expected: HashMap, +) { + let limits = parse_absolute_time_limits(args); + assert_eq!(limits, expected); +} + +#[rstest] +#[case::invalid_limit(vec!["bench1".to_string(), "not_a_number".to_string()])] +#[case::odd_number(vec!["bench1".to_string(), "1.5".to_string(), "bench2".to_string()])] +#[should_panic] +fn test_parse_absolute_time_limits_panics(#[case] args: Vec) { + parse_absolute_time_limits(args); +} From a46f462b4805eee0dc197fd546b4bc195d2edb4f Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:40:06 +0200 Subject: [PATCH 266/313] apollo_batcher: delete old TODO (#9948) --- crates/apollo_batcher_types/src/batcher_types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/apollo_batcher_types/src/batcher_types.rs b/crates/apollo_batcher_types/src/batcher_types.rs index 25c5e2497d0..dbb4c14c52d 100644 --- a/crates/apollo_batcher_types/src/batcher_types.rs +++ b/crates/apollo_batcher_types/src/batcher_types.rs @@ -72,7 +72,6 @@ pub enum GetProposalContent { } #[derive(Clone, Debug, Serialize, Deserialize)] -// TODO(Dan): Consider unifying with BuildProposalInput as they have the same fields. pub struct ValidateBlockInput { pub proposal_id: ProposalId, pub deadline: chrono::DateTime, From 96634e4a73a303ddc1dd523789f096234bbf072a Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 09:52:45 +0200 Subject: [PATCH 267/313] bench_tools: add readme (#9874) --- crates/bench_tools/README.md | 159 +++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 crates/bench_tools/README.md diff --git a/crates/bench_tools/README.md b/crates/bench_tools/README.md new file mode 100644 index 00000000000..8ebe2854426 --- /dev/null +++ b/crates/bench_tools/README.md @@ -0,0 +1,159 @@ +# bench_tools + +Benchmark framework for running Criterion benchmarks with CI integration, automated input management via GCS, and performance regression detection. + +## Quick Start + +```bash +# List available benchmarks +cargo run -p bench_tools -- list + +# Run benchmarks for a package +cargo run -p bench_tools -- run --package starknet_committer_and_os_cli --out ./results + +# Run with regression checks (requires baseline: cargo bench -p ) +cargo run -p bench_tools -- run-and-compare \ + --package starknet_committer_and_os_cli \ + --out ./results \ + --regression-limit 5.0 +``` + +## CLI Commands + +### `run` + +Execute benchmarks and save results. + +```bash +cargo run -p bench_tools -- run --package --out [--input-dir ] +``` + +- Downloads inputs from GCS automatically, or use `--input-dir` for local inputs +- Saves results to output directory as `{bench_name}_estimates.json` + +### `run-and-compare` + +Execute benchmarks and fail if regressions exceed limits. +Supports both relative (percentage change) and absolute (time in nanoseconds) limits. + +**Limits:** +- `--regression-limit`: Required. Maximum acceptable percentage change vs +baseline (e.g., 5.0 = 5%). +- `--set-absolute-time-ns-limit`: Optional. Can be specified multiple +times to set absolute time thresholds for specific benchmarks. + + +```bash +cargo run -p bench_tools -- run-and-compare \ + --package \ + --out \ + --regression-limit 5.0 \ + [--set-absolute-time-ns-limit ] +``` + +Example with absolute time limits: + +```bash +cargo run -p bench_tools -- run-and-compare \ + --package starknet_committer_and_os_cli \ + --out ./results \ + --regression-limit 5.0 \ + --set-absolute-time-ns-limit full_committer_flow 50000000 \ + --set-absolute-time-ns-limit tree_computation_flow 30000000 +``` + +Output: +``` +✓ full_committer_flow: +2.34% | 45123456.78ns +✓ tree_computation_flow: -0.89% | 28765432.10ns +✅ All benchmarks passed regression check! +``` + +Or if exceeded: +- relative limit: +``` +❌ full_committer_flow: +7.50% (EXCEEDS 5.0% limit) +``` +- absolute limit: +``` +❌ tree_computation_flow: 28765432.10ns (EXCEEDS 28765400ns limit) +``` + +### `list` + +Show available benchmarks. + +```bash +cargo run -p bench_tools -- list [--package ] +``` + +### `upload-inputs` + +Upload benchmark inputs to GCS. Authenticate with `gcloud auth login`. + +```bash +cargo run -p bench_tools -- upload-inputs \ + --benchmark \ + --input-dir +``` + +## Adding New Benchmarks + +Add a `BenchmarkConfig` to the `BENCHMARKS` array in `src/types/benchmark_config.rs`: + +```rust +BenchmarkConfig { + name: "my_benchmark", // Unique identifier + package: "my_package", // Cargo package name + cmd_args: &["bench", "-p", "my_package", "pattern"], // cargo bench args + input_dir: Some("crates/my_package/test_inputs"), // Optional, for GCS inputs + criterion_benchmark_names: None, // None = single bench with same name +}, +``` + +### Multiple Criterion Benchmarks + +If your benchmark file has multiple `bench_function` calls: + +```rust +BenchmarkConfig { + name: "multi_bench", + package: "my_package", + cmd_args: &["bench", "-p", "my_package", "--bench", "my_bench"], + input_dir: None, + criterion_benchmark_names: Some(&["bench_1", "bench_2", "bench_3"]), +}, +``` + +### Field Reference + +| Field | Description | +|-------|-------------| +| `name` | Config identifier (for CLI) | +| `package` | Cargo package containing the benchmark | +| `cmd_args` | Arguments for `cargo bench` | +| `input_dir` | Where to place downloaded inputs (if needed) | +| `criterion_benchmark_names` | List of Criterion bench names (for regression checks). `None` = uses `name` | + +### Steps + +1. Write benchmark in your package's `benches/` directory +2. Add `[[bench]]` section to package's `Cargo.toml` +3. Add `BenchmarkConfig` to `BENCHMARKS` array +4. If inputs needed: `cargo run -p bench_tools -- upload-inputs --benchmark --input-dir ` +5. Run: `cargo run -p bench_tools -- run --package --out ./results` + +## GCS Integration + +Inputs are stored at `gs://apollo_benchmarks/{benchmark_name}/input/`. Authenticate with `gcloud auth login`. + +- Inputs auto-download if `input_dir` is set and no `--input-dir` provided +- Use `--input-dir` to override with local inputs +- Use `upload-inputs` command to push new inputs to GCS + +## Notes + +- First run establishes baseline: `cargo bench -p ` +- Subsequent `run-and-compare` compares against baseline +- Positive % = slower (regression), Negative % = faster (improvement) +- See `src/benches/dummy_bench.rs` for example implementation From 82bc6f70bf363655ffc9657b20e51fdcb2d48716 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 10:25:02 +0200 Subject: [PATCH 268/313] ci: limit committer benchmark absolute time (#9876) --- .github/workflows/committer_ci.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/committer_ci.yml b/.github/workflows/committer_ci.yml index 7228f13c48d..802ed828210 100644 --- a/.github/workflows/committer_ci.yml +++ b/.github/workflows/committer_ci.yml @@ -19,6 +19,8 @@ on: env: RUSTFLAGS: "-D warnings -C link-arg=-fuse-ld=lld" + FULL_COMMITTER_FLOW_TIME_LIMIT_NS: "25000000" + TREE_COMPUTATION_FLOW_TIME_LIMIT_NS: "20000000" # On PR events, cancel existing CI runs on this same PR for this workflow. # Also, create different concurrency groups for different pushed commits, on push events. @@ -110,5 +112,12 @@ jobs: - run: pip install -r scripts/requirements.txt # Benchmark the current branch and compare to the previous run. - # Use the saved inputs. - - run: cargo run -p bench_tools -- run-and-compare --package starknet_committer_and_os_cli --out /tmp/new_results --regression-limit 8.0 --input-dir /tmp/test_inputs + # Use the saved inputs and enforce absolute time limits (full_committer_flow: 25ms, tree_computation_flow: 20ms). + - run: | + cargo run -p bench_tools -- run-and-compare \ + --package starknet_committer_and_os_cli \ + --out /tmp/new_results \ + --regression-limit 8.0 \ + --input-dir /tmp/test_inputs \ + --set-absolute-time-ns-limit full_committer_flow ${FULL_COMMITTER_FLOW_TIME_LIMIT_NS} \ + --set-absolute-time-ns-limit tree_computation_flow ${TREE_COMPUTATION_FLOW_TIME_LIMIT_NS} \ No newline at end of file From 85058dc78a673ca7cd000e1c112125f2e9388d3b Mon Sep 17 00:00:00 2001 From: lev-starkware <155880815+lev-starkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 11:31:25 +0200 Subject: [PATCH 269/313] apollo_gateway: make nonce error more distinct (#9854) --- .../src/stateful_transaction_validator.rs | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/crates/apollo_gateway/src/stateful_transaction_validator.rs b/crates/apollo_gateway/src/stateful_transaction_validator.rs index dd7b4739163..058e109a793 100644 --- a/crates/apollo_gateway/src/stateful_transaction_validator.rs +++ b/crates/apollo_gateway/src/stateful_transaction_validator.rs @@ -186,19 +186,27 @@ impl StatefulTransactionValidator { executable_tx: &ExecutableTransaction, account_nonce: Nonce, ) -> StatefulTransactionValidatorResult<()> { - if !self.is_valid_nonce(executable_tx, account_nonce) { + let (valid, max_allowed_nonce_gap) = self.is_valid_nonce(executable_tx, account_nonce); + if !valid { let tx_nonce = executable_tx.nonce(); - debug!( - "Transaction nonce is invalid. Transaction nonce: {tx_nonce}, account_nonce: \ - {account_nonce}", - ); + let message = if max_allowed_nonce_gap == 0 { + format!( + "Invalid transaction nonce. Expected: nonce = {account_nonce}, got: \ + {tx_nonce}." + ) + } else { + let max_allowed_nonce = Nonce(account_nonce.0 + Felt::from(max_allowed_nonce_gap)); + format!( + "Invalid transaction nonce. Expected: {account_nonce} <= nonce <= \ + {max_allowed_nonce}, got: {tx_nonce}.", + ) + }; + debug!("{message}"); return Err(StarknetError { code: StarknetErrorCode::KnownErrorCode( KnownStarknetErrorCode::InvalidTransactionNonce, ), - message: format!( - "Invalid transaction nonce. Expected: {account_nonce}, got: {tx_nonce}." - ), + message, }); } Ok(()) @@ -228,19 +236,26 @@ impl StatefulTransactionValidator { Ok(()) } - fn is_valid_nonce(&self, executable_tx: &ExecutableTransaction, account_nonce: Nonce) -> bool { + fn is_valid_nonce( + &self, + executable_tx: &ExecutableTransaction, + account_nonce: Nonce, + ) -> (bool, u32) { let incoming_tx_nonce = executable_tx.nonce(); // Declare transactions must have the same nonce as the account nonce. if self.config.reject_future_declare_txs && matches!(executable_tx, ExecutableTransaction::Declare(_)) { - return incoming_tx_nonce == account_nonce; + return (incoming_tx_nonce == account_nonce, 0); } let max_allowed_nonce = Nonce(account_nonce.0 + Felt::from(self.config.max_allowed_nonce_gap)); - account_nonce <= incoming_tx_nonce && incoming_tx_nonce <= max_allowed_nonce + ( + account_nonce <= incoming_tx_nonce && incoming_tx_nonce <= max_allowed_nonce, + self.config.max_allowed_nonce_gap, + ) } // TODO(Arni): Consider running this validation for all gas prices. From 197a00613a16e87166ced6b11a80151813747ecc Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Wed, 5 Nov 2025 13:46:53 +0200 Subject: [PATCH 270/313] blockifier: l1_handler test util selector with lazy lock (#9956) --- crates/blockifier/src/test_utils/l1_handler.rs | 10 ++++++++-- crates/blockifier/src/transaction/transactions_test.rs | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/blockifier/src/test_utils/l1_handler.rs b/crates/blockifier/src/test_utils/l1_handler.rs index 3eb417cdc52..79d3b8316b0 100644 --- a/crates/blockifier/src/test_utils/l1_handler.rs +++ b/crates/blockifier/src/test_utils/l1_handler.rs @@ -1,11 +1,17 @@ +use std::sync::LazyLock; + use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::calldata; -use starknet_api::core::ContractAddress; +use starknet_api::core::{ContractAddress, EntryPointSelector}; use starknet_api::executable_transaction::L1HandlerTransaction; use starknet_api::test_utils::l1_handler::{executable_l1_handler_tx, L1HandlerTxArgs}; use starknet_api::transaction::fields::Fee; use starknet_types_core::felt::Felt; +// This selector is a property of 'FeatureContract::TestContract'. +pub static L1_HANDLER_SET_VALUE_ENTRY_POINT_SELECTOR: LazyLock = + LazyLock::new(|| selector_from_name("l1_handler_set_value")); + pub fn l1handler_tx(l1_fee: Fee, contract_address: ContractAddress) -> L1HandlerTransaction { let calldata = calldata![ Felt::from(0x123), // from_address. @@ -15,7 +21,7 @@ pub fn l1handler_tx(l1_fee: Fee, contract_address: ContractAddress) -> L1Handler executable_l1_handler_tx(L1HandlerTxArgs { contract_address, - entry_point_selector: selector_from_name("l1_handler_set_value"), + entry_point_selector: *L1_HANDLER_SET_VALUE_ENTRY_POINT_SELECTOR, calldata, paid_fee_on_l1: l1_fee, ..Default::default() diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index 52c8997d2ab..bf95a206907 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -132,7 +132,11 @@ use crate::state::state_api::{State, StateReader}; use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::{fund_account, test_state}; -use crate::test_utils::l1_handler::{l1_handler_set_value_and_revert, l1handler_tx}; +use crate::test_utils::l1_handler::{ + l1_handler_set_value_and_revert, + l1handler_tx, + L1_HANDLER_SET_VALUE_ENTRY_POINT_SELECTOR, +}; use crate::test_utils::prices::Prices; use crate::test_utils::test_templates::{cairo_version, two_cairo_versions}; use crate::test_utils::{ @@ -2706,7 +2710,7 @@ fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { class_hash: Some(test_contract.get_class_hash()), code_address: None, entry_point_type: EntryPointType::L1Handler, - entry_point_selector: selector_from_name("l1_handler_set_value"), + entry_point_selector: *L1_HANDLER_SET_VALUE_ENTRY_POINT_SELECTOR, calldata: calldata.clone(), storage_address: contract_address, caller_address: ContractAddress::default(), From 16971c1e1e4c5dd1d70e22fcbeb0064963b2ec09 Mon Sep 17 00:00:00 2001 From: victorkstarkware <160594433+victorkstarkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:57:01 +0200 Subject: [PATCH 271/313] apollo_integration_tests: removed magic numbers regarding deployed services and executables (#9794) --- crates/apollo_deployments/src/service.rs | 23 +++- .../src/node_component_configs.rs | 125 ++++++++---------- .../src/component_config.rs | 8 +- 3 files changed, 81 insertions(+), 75 deletions(-) diff --git a/crates/apollo_deployments/src/service.rs b/crates/apollo_deployments/src/service.rs index c0d8f39e815..19a71bf7cec 100644 --- a/crates/apollo_deployments/src/service.rs +++ b/crates/apollo_deployments/src/service.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::fmt::Display; use std::iter::once; use std::net::{IpAddr, Ipv4Addr}; @@ -415,6 +415,27 @@ impl NodeType { } } + pub fn get_services_of_components( + &self, + component_type: ComponentConfigInService, + ) -> HashSet { + let services: HashSet<_> = self + .all_service_names() + .into_iter() + .filter(|node_service| { + node_service.get_components_in_service().contains(&component_type) + }) + .collect(); + + assert!( + !services.is_empty(), + "Expected at least one NodeService containing component type {:?}", + component_type + ); + + services + } + pub fn get_component_configs( &self, ports: Option>, diff --git a/crates/apollo_integration_tests/src/node_component_configs.rs b/crates/apollo_integration_tests/src/node_component_configs.rs index 3a29d9c3007..72bc914bf90 100644 --- a/crates/apollo_integration_tests/src/node_component_configs.rs +++ b/crates/apollo_integration_tests/src/node_component_configs.rs @@ -1,17 +1,14 @@ -use apollo_deployments::deployments::distributed::{ - DistributedNodeServiceName, - DISTRIBUTED_NODE_REQUIRED_PORTS_NUM, -}; -use apollo_deployments::deployments::hybrid::{ - HybridNodeServiceName, - HYBRID_NODE_REQUIRED_PORTS_NUM, -}; +use apollo_deployments::deployment_definitions::ComponentConfigInService; +use apollo_deployments::deployments::distributed::DISTRIBUTED_NODE_REQUIRED_PORTS_NUM; +use apollo_deployments::deployments::hybrid::HYBRID_NODE_REQUIRED_PORTS_NUM; use apollo_deployments::service::{NodeService, NodeType}; use apollo_infra_utils::test_utils::AvailablePortsGenerator; use apollo_node_config::component_config::{set_urls_to_localhost, ComponentConfig}; +use indexmap::IndexMap; /// Holds the component configs for a set of sequencers, composing a single sequencer node. pub struct NodeComponentConfigs { + // TODO(Tsabary): transition to using the map instead of a vector and indices. component_configs: Vec, batcher_index: usize, http_server_index: usize, @@ -21,16 +18,48 @@ pub struct NodeComponentConfigs { } impl NodeComponentConfigs { - fn new( - component_configs: Vec, - batcher_index: usize, - http_server_index: usize, - state_sync_index: usize, - class_manager_index: usize, - consensus_manager_index: usize, - ) -> Self { + // TODO(victork): only pass node_type and ports, and create the map inside. + fn new(component_configs: IndexMap, node_type: NodeType) -> Self { + fn get_component_index( + component_configs: &IndexMap, + node_type: NodeType, + component_in_service: ComponentConfigInService, + ) -> usize { + component_configs + .get_index_of::( + node_type + .get_services_of_components(component_in_service) + .iter() + .next() + .as_ref() + .unwrap(), + ) + .unwrap() + } + + let batcher_index = + get_component_index(&component_configs, node_type, ComponentConfigInService::Batcher); + + let http_server_index = get_component_index( + &component_configs, + node_type, + ComponentConfigInService::HttpServer, + ); + + let state_sync_index = + get_component_index(&component_configs, node_type, ComponentConfigInService::StateSync); + + let class_manager_index = get_component_index( + &component_configs, + node_type, + ComponentConfigInService::ClassManager, + ); + + let consensus_manager_index = + get_component_index(&component_configs, node_type, ComponentConfigInService::Consensus); + Self { - component_configs, + component_configs: component_configs.into_values().collect(), batcher_index, http_server_index, state_sync_index, @@ -80,12 +109,8 @@ impl IntoIterator for NodeComponentConfigs { pub fn create_consolidated_component_configs() -> NodeComponentConfigs { // All components are in executable index 0. NodeComponentConfigs::new( - NodeType::Consolidated.get_component_configs(None).into_values().collect(), - 0, - 0, - 0, - 0, - 0, + NodeType::Consolidated.get_component_configs(None), + NodeType::Consolidated, ) } @@ -97,32 +122,11 @@ pub fn create_distributed_component_configs( .expect("Failed to get an AvailablePorts instance for distributed node configs"); let ports = available_ports.get_next_ports(DISTRIBUTED_NODE_REQUIRED_PORTS_NUM); - let services_component_config = NodeType::Distributed.get_component_configs(Some(ports)); + let mut services_component_config = NodeType::Distributed.get_component_configs(Some(ports)); - let mut component_configs: Vec = - services_component_config.values().cloned().collect(); - set_urls_to_localhost(&mut component_configs); + set_urls_to_localhost(services_component_config.values_mut()); - // TODO(Tsabary): transition to using the map instead of a vector and indices. - - NodeComponentConfigs::new( - component_configs, - services_component_config - .get_index_of::(&DistributedNodeServiceName::Batcher.into()) - .unwrap(), - services_component_config - .get_index_of::(&DistributedNodeServiceName::HttpServer.into()) - .unwrap(), - services_component_config - .get_index_of::(&DistributedNodeServiceName::StateSync.into()) - .unwrap(), - services_component_config - .get_index_of::(&DistributedNodeServiceName::ClassManager.into()) - .unwrap(), - services_component_config - .get_index_of::(&DistributedNodeServiceName::ConsensusManager.into()) - .unwrap(), - ) + NodeComponentConfigs::new(services_component_config, NodeType::Distributed) } pub fn create_hybrid_component_configs( @@ -133,30 +137,9 @@ pub fn create_hybrid_component_configs( .expect("Failed to get an AvailablePorts instance for distributed node configs"); let ports = available_ports.get_next_ports(HYBRID_NODE_REQUIRED_PORTS_NUM); - let services_component_config = NodeType::Hybrid.get_component_configs(Some(ports)); + let mut services_component_config = NodeType::Hybrid.get_component_configs(Some(ports)); - let mut component_configs: Vec = - services_component_config.values().cloned().collect(); - set_urls_to_localhost(&mut component_configs); + set_urls_to_localhost(services_component_config.values_mut()); - // TODO(Tsabary): transition to using the map instead of a vector and indices. - - NodeComponentConfigs::new( - component_configs, - services_component_config - .get_index_of::(&HybridNodeServiceName::Core.into()) - .unwrap(), - services_component_config - .get_index_of::(&HybridNodeServiceName::HttpServer.into()) - .unwrap(), - services_component_config - .get_index_of::(&HybridNodeServiceName::Core.into()) - .unwrap(), - services_component_config - .get_index_of::(&HybridNodeServiceName::Core.into()) - .unwrap(), - services_component_config - .get_index_of::(&HybridNodeServiceName::Core.into()) - .unwrap(), - ) + NodeComponentConfigs::new(services_component_config, NodeType::Hybrid) } diff --git a/crates/apollo_node_config/src/component_config.rs b/crates/apollo_node_config/src/component_config.rs index 82c151930d6..4b403979439 100644 --- a/crates/apollo_node_config/src/component_config.rs +++ b/crates/apollo_node_config/src/component_config.rs @@ -122,8 +122,10 @@ impl ComponentConfig { } #[cfg(any(feature = "testing", test))] -pub fn set_urls_to_localhost(component_configs: &mut [ComponentConfig]) { - for component_config in component_configs.iter_mut() { - component_config.set_urls_to_localhost(); +pub fn set_urls_to_localhost<'a>( + component_configs: impl IntoIterator, +) { + for config in component_configs { + config.set_urls_to_localhost(); } } From 5f8159e8007ba15e5937ad0f79d7568b4b1c61be Mon Sep 17 00:00:00 2001 From: Yonatan-Starkware Date: Wed, 5 Nov 2025 14:43:37 +0200 Subject: [PATCH 272/313] blockifier: add syscall_usage to call_info (#9804) --- .../resources/central_blob.json | 108 +++++++++++++++++ .../central_transaction_execution_info.json | 110 +++++++++++++++++- ...l_transaction_execution_info_reverted.json | 74 +++++++++++- .../src/cende/central_objects_test.rs | 8 +- crates/blockifier/src/execution/call_info.rs | 3 + .../deprecated_entry_point_execution.rs | 1 + .../deprecated_syscalls_test.rs | 23 ++++ .../src/execution/entry_point_execution.rs | 1 + .../execution/native/entry_point_execution.rs | 1 + .../syscalls/syscall_tests/deploy.rs | 2 +- .../syscalls/syscall_tests/library_call.rs | 17 +++ .../execution/syscalls/vm_syscall_utils.rs | 7 +- crates/blockifier/src/test_utils.rs | 2 +- .../src/transaction/transactions_test.rs | 35 +++++- 14 files changed, 384 insertions(+), 8 deletions(-) diff --git a/crates/apollo_consensus_orchestrator/resources/central_blob.json b/crates/apollo_consensus_orchestrator/resources/central_blob.json index 7f6a7dbfd1e..aca362303c7 100644 --- a/crates/apollo_consensus_orchestrator/resources/central_blob.json +++ b/crates/apollo_consensus_orchestrator/resources/central_blob.json @@ -418,6 +418,24 @@ "builtin_counters": { "range_check": 31, "pedersen": 4 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } ], @@ -455,6 +473,24 @@ "builtin_counters": { "range_check": 31, "pedersen": 4 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } }, "execute_call_info": { @@ -599,6 +635,24 @@ "builtin_counters": { "range_check": 31, "pedersen": 4 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } ], @@ -636,6 +690,24 @@ "builtin_counters": { "range_check": 31, "pedersen": 4 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } }, "fee_transfer_call_info": { @@ -780,6 +852,24 @@ "builtin_counters": { "range_check": 31, "pedersen": 4 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } ], @@ -817,6 +907,24 @@ "builtin_counters": { "range_check": 31, "pedersen": 4 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } }, "actual_fee": "0x26fe9d250e000", diff --git a/crates/apollo_consensus_orchestrator/resources/central_transaction_execution_info.json b/crates/apollo_consensus_orchestrator/resources/central_transaction_execution_info.json index c403b1e9cbe..f981f0c0a92 100644 --- a/crates/apollo_consensus_orchestrator/resources/central_transaction_execution_info.json +++ b/crates/apollo_consensus_orchestrator/resources/central_transaction_execution_info.json @@ -152,6 +152,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } ], @@ -189,6 +207,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } }, "fee_transfer_call_info": { @@ -333,6 +369,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } ], @@ -370,6 +424,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } }, "revert_error": null, @@ -520,6 +592,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } ], @@ -557,6 +647,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } -} +} \ No newline at end of file diff --git a/crates/apollo_consensus_orchestrator/resources/central_transaction_execution_info_reverted.json b/crates/apollo_consensus_orchestrator/resources/central_transaction_execution_info_reverted.json index df6d8e2a5aa..c731caed9c9 100644 --- a/crates/apollo_consensus_orchestrator/resources/central_transaction_execution_info_reverted.json +++ b/crates/apollo_consensus_orchestrator/resources/central_transaction_execution_info_reverted.json @@ -153,6 +153,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } ], @@ -190,6 +208,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } }, "revert_error": "Insufficient fee token balance. Fee: 1, balance: low/high 2/3.", @@ -340,6 +376,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } ], @@ -377,6 +431,24 @@ "builtin_counters": { "pedersen": 4, "range_check": 31 + }, + "syscalls_usage": { + "CallContract": { + "call_count": 7, + "linear_factor": 0 + }, + "StorageRead": { + "call_count": 4, + "linear_factor": 0 + }, + "StorageWrite": { + "call_count": 4, + "linear_factor": 0 + }, + "EmitEvent": { + "call_count": 2, + "linear_factor": 0 + } } } -} +} \ No newline at end of file diff --git a/crates/apollo_consensus_orchestrator/src/cende/central_objects_test.rs b/crates/apollo_consensus_orchestrator/src/cende/central_objects_test.rs index de67f2fe638..86ebceaf61e 100644 --- a/crates/apollo_consensus_orchestrator/src/cende/central_objects_test.rs +++ b/crates/apollo_consensus_orchestrator/src/cende/central_objects_test.rs @@ -28,6 +28,7 @@ use blockifier::execution::call_info::{ }; use blockifier::execution::contract_class::TrackedResource; use blockifier::execution::entry_point::{CallEntryPoint, CallType}; +use blockifier::execution::syscalls::vm_syscall_utils::{SyscallSelector, SyscallUsage}; use blockifier::fee::fee_checks::FeeCheckError; use blockifier::fee::receipt::TransactionReceipt; use blockifier::fee::resources::{ @@ -530,8 +531,13 @@ fn call_info() -> CallInfo { read_block_hash_values: vec![BlockHash(felt!("0xdeafbee"))], accessed_blocks: HashSet::from([BlockNumber(100)]), }, - // TODO(Meshi): insert relevant values. builtin_counters: execution_resources().prover_builtins(), + syscalls_usage: HashMap::from([ + (SyscallSelector::CallContract, SyscallUsage { call_count: 7, linear_factor: 0 }), + (SyscallSelector::StorageRead, SyscallUsage { call_count: 4, linear_factor: 0 }), + (SyscallSelector::StorageWrite, SyscallUsage { call_count: 4, linear_factor: 0 }), + (SyscallSelector::EmitEvent, SyscallUsage { call_count: 2, linear_factor: 0 }), + ]), } } diff --git a/crates/blockifier/src/execution/call_info.rs b/crates/blockifier/src/execution/call_info.rs index a1ae1590289..15dfa772b8a 100644 --- a/crates/blockifier/src/execution/call_info.rs +++ b/crates/blockifier/src/execution/call_info.rs @@ -16,6 +16,7 @@ use starknet_types_core::felt::Felt; use crate::blockifier_versioned_constants::VersionedConstants; use crate::execution::contract_class::TrackedResource; use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::vm_syscall_utils::SyscallUsageMap; use crate::state::cached_state::StorageEntry; use crate::utils::u64_from_usize; @@ -240,6 +241,8 @@ pub struct CallInfo { // Tracks how many times each builtin was called during execution (excluding inner calls). // Used by the bouncer to decide when to close a block. pub builtin_counters: BuiltinCounterMap, + // Tracks how many times each syscall was called during execution (excluding inner calls). + pub syscalls_usage: SyscallUsageMap, } impl CallInfo { diff --git a/crates/blockifier/src/execution/deprecated_entry_point_execution.rs b/crates/blockifier/src/execution/deprecated_entry_point_execution.rs index 50d8c560ae2..8ac6d257754 100644 --- a/crates/blockifier/src/execution/deprecated_entry_point_execution.rs +++ b/crates/blockifier/src/execution/deprecated_entry_point_execution.rs @@ -289,6 +289,7 @@ pub fn finalize_execution( ..Default::default() }, builtin_counters: vm_resources_without_inner_calls.prover_builtins(), + syscalls_usage: syscall_handler.syscalls_usage, }) } diff --git a/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs b/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs index 37a7d22f84e..98c3cca8c25 100644 --- a/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs +++ b/crates/blockifier/src/execution/deprecated_syscalls/deprecated_syscalls_test.rs @@ -39,6 +39,7 @@ use crate::execution::deprecated_syscalls::DeprecatedSyscallSelector; use crate::execution::entry_point::{CallEntryPoint, CallType}; use crate::execution::errors::EntryPointExecutionError; use crate::execution::syscalls::hint_processor::EmitEventError; +use crate::execution::syscalls::vm_syscall_utils::{SyscallSelector, SyscallUsage}; use crate::state::state_api::StateReader; use crate::test_utils::contracts::FeatureContractData; use crate::test_utils::initial_test_state::{test_state, test_state_inner}; @@ -152,6 +153,10 @@ fn test_nested_library_call() { n_memory_holes: 0, builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 2)]), }; + let storage_entry_point_syscalls_usage = HashMap::from([ + (SyscallSelector::StorageRead, SyscallUsage::with_call_count(1)), + (SyscallSelector::StorageWrite, SyscallUsage::with_call_count(1)), + ]); let nested_storage_call_info = CallInfo { call: nested_storage_entry_point, execution: CallExecution::from_retdata(retdata![felt!(value + 1)]), @@ -162,6 +167,7 @@ fn test_nested_library_call() { ..Default::default() }, builtin_counters: HashMap::from([(BuiltinName::range_check, 2)]), + syscalls_usage: storage_entry_point_syscalls_usage.clone(), ..Default::default() }; let mut library_call_resources = @@ -178,6 +184,10 @@ fn test_nested_library_call() { resources: library_call_resources.clone(), inner_calls: vec![nested_storage_call_info], builtin_counters: HashMap::from([(BuiltinName::range_check, 19)]), + syscalls_usage: HashMap::from([( + SyscallSelector::LibraryCall, + SyscallUsage::with_call_count(1), + )]), ..Default::default() }; let storage_call_info = CallInfo { @@ -190,6 +200,7 @@ fn test_nested_library_call() { ..Default::default() }, builtin_counters: HashMap::from([(BuiltinName::range_check, 2)]), + syscalls_usage: storage_entry_point_syscalls_usage.clone(), ..Default::default() }; @@ -208,6 +219,10 @@ fn test_nested_library_call() { resources: main_call_resources, inner_calls: vec![library_call_info, storage_call_info], builtin_counters: HashMap::from([(BuiltinName::range_check, 37)]), + syscalls_usage: HashMap::from([( + SyscallSelector::LibraryCall, + SyscallUsage::with_call_count(2), + )]), ..Default::default() }; @@ -309,6 +324,10 @@ fn test_call_contract() { ..Default::default() }, builtin_counters: HashMap::from([(BuiltinName::range_check, 2)]), + syscalls_usage: HashMap::from([ + (SyscallSelector::StorageWrite, SyscallUsage::with_call_count(1)), + (SyscallSelector::StorageRead, SyscallUsage::with_call_count(1)), + ]), ..Default::default() }; let expected_call_info = CallInfo { @@ -327,6 +346,10 @@ fn test_call_contract() { builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 3)]), }, builtin_counters: HashMap::from([(BuiltinName::range_check, 19)]), + syscalls_usage: HashMap::from([( + SyscallSelector::CallContract, + SyscallUsage::with_call_count(1), + )]), ..Default::default() }; diff --git a/crates/blockifier/src/execution/entry_point_execution.rs b/crates/blockifier/src/execution/entry_point_execution.rs index 2ec1ad95cd2..eebf48a5457 100644 --- a/crates/blockifier/src/execution/entry_point_execution.rs +++ b/crates/blockifier/src/execution/entry_point_execution.rs @@ -483,6 +483,7 @@ pub fn finalize_execution( resources: vm_resources, storage_access_tracker: syscall_handler_base.storage_access_tracker, builtin_counters: vm_resources_without_inner_calls.prover_builtins(), + syscalls_usage: syscall_handler_base.syscalls_usage, }) } diff --git a/crates/blockifier/src/execution/native/entry_point_execution.rs b/crates/blockifier/src/execution/native/entry_point_execution.rs index d005b3d45d7..5d3a597e457 100644 --- a/crates/blockifier/src/execution/native/entry_point_execution.rs +++ b/crates/blockifier/src/execution/native/entry_point_execution.rs @@ -114,6 +114,7 @@ fn create_callinfo( storage_access_tracker: syscall_handler.base.storage_access_tracker, tracked_resource: TrackedResource::SierraGas, builtin_counters, + syscalls_usage: syscall_handler.base.syscalls_usage, }) } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs index 2e85210a58b..d86a8e13799 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs @@ -280,7 +280,7 @@ fn calldata_length(cairo_version: CairoVersion) { .versioned_constants .get_additional_os_syscall_resources(&HashMap::from([( SyscallSelector::Deploy, - (SyscallUsage::new(1, 0)), + SyscallUsage::with_call_count(1), )])) .builtin_instance_counter .get(&BuiltinName::pedersen) diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs index e290a28272a..eb0a5a975ec 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs @@ -13,6 +13,7 @@ use crate::blockifier_versioned_constants::VersionedConstants; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, CallInfo, Retdata, StorageAccessTracker}; use crate::execution::entry_point::{CallEntryPoint, CallType}; +use crate::execution::syscalls::vm_syscall_utils::{SyscallSelector, SyscallUsage}; use crate::retdata; use crate::test_utils::contracts::FeatureContractTrait; use crate::test_utils::initial_test_state::test_state; @@ -208,6 +209,10 @@ fn test_nested_library_call(runnable_version: RunnableCairo1) { ..Default::default() }, builtin_counters: HashMap::from([(BuiltinName::range_check, 7)]), + syscalls_usage: HashMap::from([ + (SyscallSelector::StorageRead, SyscallUsage::with_call_count(1)), + (SyscallSelector::StorageWrite, SyscallUsage::with_call_count(1)), + ]), ..Default::default() }; @@ -225,6 +230,10 @@ fn test_nested_library_call(runnable_version: RunnableCairo1) { inner_calls: vec![nested_storage_call_info], tracked_resource, builtin_counters: HashMap::from([(BuiltinName::range_check, 26)]), + syscalls_usage: HashMap::from([( + SyscallSelector::LibraryCall, + SyscallUsage::with_call_count(1), + )]), ..Default::default() }; @@ -246,6 +255,10 @@ fn test_nested_library_call(runnable_version: RunnableCairo1) { }, tracked_resource, builtin_counters: HashMap::from([(BuiltinName::range_check, 7)]), + syscalls_usage: HashMap::from([ + (SyscallSelector::StorageRead, SyscallUsage::with_call_count(1)), + (SyscallSelector::StorageWrite, SyscallUsage::with_call_count(1)), + ]), ..Default::default() }; @@ -263,6 +276,10 @@ fn test_nested_library_call(runnable_version: RunnableCairo1) { inner_calls: vec![library_call_info, storage_call_info], tracked_resource, builtin_counters: HashMap::from([(BuiltinName::range_check, 41)]), + syscalls_usage: HashMap::from([( + SyscallSelector::LibraryCall, + SyscallUsage::with_call_count(2), + )]), ..Default::default() }; diff --git a/crates/blockifier/src/execution/syscalls/vm_syscall_utils.rs b/crates/blockifier/src/execution/syscalls/vm_syscall_utils.rs index 02c3d031736..de32cbb0e65 100644 --- a/crates/blockifier/src/execution/syscalls/vm_syscall_utils.rs +++ b/crates/blockifier/src/execution/syscalls/vm_syscall_utils.rs @@ -48,7 +48,8 @@ pub type SyscallSelector = DeprecatedSyscallSelector; pub type SyscallUsageMap = HashMap; -#[derive(Clone, Debug, Default, Serialize)] +#[cfg_attr(feature = "transaction_serde", derive(serde::Deserialize))] +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)] pub struct SyscallUsage { pub call_count: usize, pub linear_factor: usize, @@ -58,7 +59,9 @@ impl SyscallUsage { pub fn new(call_count: usize, linear_factor: usize) -> Self { SyscallUsage { call_count, linear_factor } } - + pub fn with_call_count(call_count: usize) -> Self { + SyscallUsage::new(call_count, 0) + } pub fn increment_call_count(&mut self) { self.call_count += 1; } diff --git a/crates/blockifier/src/test_utils.rs b/crates/blockifier/src/test_utils.rs index 6f9e89b0e22..e29655dc35b 100644 --- a/crates/blockifier/src/test_utils.rs +++ b/crates/blockifier/src/test_utils.rs @@ -316,7 +316,7 @@ macro_rules! check_tx_execution_error_for_invalid_scenario { pub fn get_const_syscall_resources(syscall_selector: SyscallSelector) -> ExecutionResources { let versioned_constants = VersionedConstants::create_for_testing(); let syscalls_usage: SyscallUsageMap = - HashMap::from([(syscall_selector, SyscallUsage::new(1, 0))]); + HashMap::from([(syscall_selector, SyscallUsage::with_call_count(1))]); versioned_constants.get_additional_os_syscall_resources(&syscalls_usage) } diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index bf95a206907..f0f64d61525 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -111,7 +111,7 @@ use crate::execution::syscalls::hint_processor::EmitEventError; use crate::execution::syscalls::hint_processor::SyscallExecutionError; #[cfg(feature = "cairo_native")] use crate::execution::syscalls::vm_syscall_utils::SyscallExecutorBaseError; -use crate::execution::syscalls::vm_syscall_utils::SyscallSelector; +use crate::execution::syscalls::vm_syscall_utils::{SyscallSelector, SyscallUsage}; use crate::fee::fee_checks::FeeCheckError; use crate::fee::fee_utils::{balance_to_big_uint, get_fee_by_gas_vector, GasVectorToL1GasForFee}; use crate::fee::gas_usage::{ @@ -438,6 +438,23 @@ fn expected_fee_transfer_call_info( CairoVersion::Cairo0 => Prices::FeeTransfer(account_address, *fee_type).into(), CairoVersion::Cairo1(_) => ExecutionResources::default(), }; + let mut syscalls_usage = HashMap::from([ + (SyscallSelector::StorageRead, SyscallUsage::with_call_count(4)), + (SyscallSelector::StorageWrite, SyscallUsage::with_call_count(4)), + (SyscallSelector::EmitEvent, SyscallUsage::with_call_count(1)), + ]); + + match cairo_version { + CairoVersion::Cairo0 => { + syscalls_usage + .insert(SyscallSelector::GetCallerAddress, SyscallUsage::with_call_count(1)); + } + CairoVersion::Cairo1(_) => { + syscalls_usage + .insert(SyscallSelector::GetExecutionInfo, SyscallUsage::with_call_count(1)); + } + } + Some(CallInfo { call: expected_fee_transfer_call, execution: CallExecution { @@ -461,6 +478,7 @@ fn expected_fee_transfer_call_info( }, tracked_resource: expected_tracked_resource, builtin_counters, + syscalls_usage, ..Default::default() }) } @@ -695,6 +713,16 @@ fn test_invoke_tx( CairoVersion::Cairo0 => HashMap::from([(BuiltinName::range_check, 19)]), CairoVersion::Cairo1(_) => HashMap::from([(BuiltinName::range_check, 27)]), }; + let syscalls_usage = match account_cairo_version { + CairoVersion::Cairo0 => HashMap::from([( + SyscallSelector::CallContract, + SyscallUsage { call_count: 1, linear_factor: 0 }, + )]), + CairoVersion::Cairo1(_) => HashMap::from([ + (SyscallSelector::GetExecutionInfo, SyscallUsage { call_count: 1, linear_factor: 0 }), + (SyscallSelector::CallContract, SyscallUsage { call_count: 1, linear_factor: 0 }), + ]), + }; let expected_execute_call_info = Some(CallInfo { call: expected_execute_call, execution: CallExecution { @@ -707,6 +735,7 @@ fn test_invoke_tx( inner_calls: expected_inner_calls, tracked_resource, builtin_counters, + syscalls_usage, ..Default::default() }); @@ -2735,6 +2764,10 @@ fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { .get_runnable_class() .tracked_resource(&versioned_constants.min_sierra_version_for_sierra_gas, None), builtin_counters: HashMap::from([(BuiltinName::range_check, 6)]), + syscalls_usage: HashMap::from([( + SyscallSelector::StorageWrite, + SyscallUsage { call_count: 1, linear_factor: 0 }, + )]), ..Default::default() }; From 5cdf03a462375e33d21b0c7664c305b77a2291d0 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:44:43 +0200 Subject: [PATCH 273/313] apollo_state_sync: remove redundant spawn_blocking wrappers (#9947) --- Cargo.lock | 1 - crates/apollo_state_sync/src/lib.rs | 178 ++++++++----------- crates/apollo_state_sync_types/Cargo.toml | 1 - crates/apollo_state_sync_types/src/errors.rs | 9 - 4 files changed, 79 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 390d788e0a0..6bb9ad6d902 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2504,7 +2504,6 @@ dependencies = [ "strum 0.25.0", "strum_macros 0.25.3", "thiserror 1.0.69", - "tokio", ] [[package]] diff --git a/crates/apollo_state_sync/src/lib.rs b/crates/apollo_state_sync/src/lib.rs index 1f276f54a83..dc33433ab3a 100644 --- a/crates/apollo_state_sync/src/lib.rs +++ b/crates/apollo_state_sync/src/lib.rs @@ -119,53 +119,46 @@ impl ComponentRequestHandler for StateSync impl StateSync { async fn get_block(&self, block_number: BlockNumber) -> StateSyncResult { let storage_reader = self.storage_reader.clone(); - // TODO(Tsabary): remove spawn blocking from this file. - tokio::task::spawn_blocking(move || { - let txn = storage_reader.begin_ro_txn()?; - let block_header = txn - .get_block_header(block_number)? - .ok_or(StateSyncError::BlockNotFound(block_number))?; - let block_transactions_with_hash = txn - .get_block_transactions_with_hash(block_number)? - .ok_or(StateSyncError::BlockNotFound(block_number))?; - let thin_state_diff = txn - .get_state_diff(block_number)? - .ok_or(StateSyncError::BlockNotFound(block_number))?; - drop(txn); // Drop txn so we don't unnecessarily hold it open during the procedure below. - - let mut l1_transaction_hashes: Vec = vec![]; - let mut account_transaction_hashes: Vec = vec![]; - - for (tx, tx_hash) in block_transactions_with_hash { - match tx { - Transaction::L1Handler(_) => l1_transaction_hashes.push(tx_hash), - _ => account_transaction_hashes.push(tx_hash), - } + let txn = storage_reader.begin_ro_txn()?; + + let block_header = txn + .get_block_header(block_number)? + .ok_or(StateSyncError::BlockNotFound(block_number))?; + let block_transactions_with_hash = txn + .get_block_transactions_with_hash(block_number)? + .ok_or(StateSyncError::BlockNotFound(block_number))?; + let thin_state_diff = + txn.get_state_diff(block_number)?.ok_or(StateSyncError::BlockNotFound(block_number))?; + drop(txn); // Drop txn so we don't unnecessarily hold it open during the procedure below. + + let mut l1_transaction_hashes: Vec = vec![]; + let mut account_transaction_hashes: Vec = vec![]; + + for (tx, tx_hash) in block_transactions_with_hash { + match tx { + Transaction::L1Handler(_) => l1_transaction_hashes.push(tx_hash), + _ => account_transaction_hashes.push(tx_hash), } + } - Ok(SyncBlock { - state_diff: thin_state_diff, - block_header_without_hash: block_header.block_header_without_hash, - account_transaction_hashes, - l1_transaction_hashes, - }) + Ok(SyncBlock { + state_diff: thin_state_diff, + block_header_without_hash: block_header.block_header_without_hash, + account_transaction_hashes, + l1_transaction_hashes, }) - .await? } async fn get_block_hash(&self, block_number: BlockNumber) -> StateSyncResult { // Attempt reading the block hash from the storage. let storage_reader = self.storage_reader.clone(); - let block_hash_opt = tokio::task::spawn_blocking(move || { - Ok::<_, StateSyncError>( - storage_reader - .begin_ro_txn()? - .get_block_header(block_number)? - .map(|header| header.block_hash), - ) - }) - .await??; + let block_hash_opt = Ok::<_, StateSyncError>( + storage_reader + .begin_ro_txn()? + .get_block_header(block_number)? + .map(|header| header.block_hash), + )?; match (block_hash_opt, self.starknet_client.as_ref()) { (Some(block_hash), _) => Ok(block_hash), @@ -188,20 +181,18 @@ impl StateSync { storage_key: StorageKey, ) -> StateSyncResult { let storage_reader = self.storage_reader.clone(); - tokio::task::spawn_blocking(move || { - let txn = storage_reader.begin_ro_txn()?; - verify_synced_up_to(&txn, block_number)?; - let state_number = StateNumber::unchecked_right_after_block(block_number); - let state_reader = txn.get_state_reader()?; + let txn = storage_reader.begin_ro_txn()?; + verify_synced_up_to(&txn, block_number)?; - verify_contract_deployed(&state_reader, state_number, contract_address)?; + let state_number = StateNumber::unchecked_right_after_block(block_number); + let state_reader = txn.get_state_reader()?; - let res = state_reader.get_storage_at(state_number, &contract_address, &storage_key)?; + verify_contract_deployed(&state_reader, state_number, contract_address)?; - Ok(res) - }) - .await? + let res = state_reader.get_storage_at(state_number, &contract_address, &storage_key)?; + + Ok(res) } async fn get_nonce_at( @@ -210,22 +201,20 @@ impl StateSync { contract_address: ContractAddress, ) -> StateSyncResult { let storage_reader = self.storage_reader.clone(); - tokio::task::spawn_blocking(move || { - let txn = storage_reader.begin_ro_txn()?; - verify_synced_up_to(&txn, block_number)?; - let state_number = StateNumber::unchecked_right_after_block(block_number); - let state_reader = txn.get_state_reader()?; + let txn = storage_reader.begin_ro_txn()?; + verify_synced_up_to(&txn, block_number)?; - verify_contract_deployed(&state_reader, state_number, contract_address)?; + let state_number = StateNumber::unchecked_right_after_block(block_number); + let state_reader = txn.get_state_reader()?; - let res = state_reader - .get_nonce_at(state_number, &contract_address)? - .ok_or(StateSyncError::ContractNotFound(contract_address))?; + verify_contract_deployed(&state_reader, state_number, contract_address)?; - Ok(res) - }) - .await? + let res = state_reader + .get_nonce_at(state_number, &contract_address)? + .ok_or(StateSyncError::ContractNotFound(contract_address))?; + + Ok(res) } async fn get_class_hash_at( @@ -234,28 +223,22 @@ impl StateSync { contract_address: ContractAddress, ) -> StateSyncResult { let storage_reader = self.storage_reader.clone(); - tokio::task::spawn_blocking(move || { - let txn = storage_reader.begin_ro_txn()?; - verify_synced_up_to(&txn, block_number)?; - - let state_number = StateNumber::unchecked_right_after_block(block_number); - let state_reader = txn.get_state_reader()?; - let class_hash = state_reader - .get_class_hash_at(state_number, &contract_address)? - .ok_or(StateSyncError::ContractNotFound(contract_address))?; - Ok(class_hash) - }) - .await? + let txn = storage_reader.begin_ro_txn()?; + verify_synced_up_to(&txn, block_number)?; + + let state_number = StateNumber::unchecked_right_after_block(block_number); + let state_reader = txn.get_state_reader()?; + let class_hash = state_reader + .get_class_hash_at(state_number, &contract_address)? + .ok_or(StateSyncError::ContractNotFound(contract_address))?; + Ok(class_hash) } async fn get_latest_block_number(&self) -> StateSyncResult> { let storage_reader = self.storage_reader.clone(); - tokio::task::spawn_blocking(move || { - let txn = storage_reader.begin_ro_txn()?; - let latest_block_number = latest_synced_block(&txn)?; - Ok(latest_block_number) - }) - .await? + let txn = storage_reader.begin_ro_txn()?; + let latest_block_number = latest_synced_block(&txn)?; + Ok(latest_block_number) } async fn is_class_declared_at( @@ -264,28 +247,25 @@ impl StateSync { class_hash: ClassHash, ) -> StateSyncResult { let storage_reader = self.storage_reader.clone(); - tokio::task::spawn_blocking(move || { - let class_definition_block_number_opt = storage_reader - .begin_ro_txn()? - .get_state_reader()? - .get_class_definition_block_number(&class_hash)?; - if let Some(class_definition_block_number) = class_definition_block_number_opt { - return Ok(class_definition_block_number <= block_number); - } + let class_definition_block_number_opt = storage_reader + .begin_ro_txn()? + .get_state_reader()? + .get_class_definition_block_number(&class_hash)?; + if let Some(class_definition_block_number) = class_definition_block_number_opt { + return Ok(class_definition_block_number <= block_number); + } - // TODO(noamsp): Add unit testing for cairo0 - let deprecated_class_definition_block_number_opt = storage_reader - .begin_ro_txn()? - .get_state_reader()? - .get_deprecated_class_definition_block_number(&class_hash)?; - - Ok(deprecated_class_definition_block_number_opt.is_some_and( - |deprecated_class_definition_block_number| { - deprecated_class_definition_block_number <= block_number - }, - )) - }) - .await? + // TODO(noamsp): Add unit testing for cairo0 + let deprecated_class_definition_block_number_opt = storage_reader + .begin_ro_txn()? + .get_state_reader()? + .get_deprecated_class_definition_block_number(&class_hash)?; + + Ok(deprecated_class_definition_block_number_opt.is_some_and( + |deprecated_class_definition_block_number| { + deprecated_class_definition_block_number <= block_number + }, + )) } } diff --git a/crates/apollo_state_sync_types/Cargo.toml b/crates/apollo_state_sync_types/Cargo.toml index 2176df3821e..bd003c1eccb 100644 --- a/crates/apollo_state_sync_types/Cargo.toml +++ b/crates/apollo_state_sync_types/Cargo.toml @@ -26,7 +26,6 @@ starknet_api.workspace = true strum = { workspace = true, features = ["derive"] } strum_macros.workspace = true thiserror.workspace = true -tokio.workspace = true [dev-dependencies] mockall.workspace = true diff --git a/crates/apollo_state_sync_types/src/errors.rs b/crates/apollo_state_sync_types/src/errors.rs index 568cdf57f6b..c1ed2544831 100644 --- a/crates/apollo_state_sync_types/src/errors.rs +++ b/crates/apollo_state_sync_types/src/errors.rs @@ -6,7 +6,6 @@ use starknet_api::block::BlockNumber; use starknet_api::core::{ClassHash, ContractAddress}; use starknet_api::StarknetApiError; use thiserror::Error; -use tokio::task::JoinError; #[derive(Debug, Error, Serialize, Deserialize, Clone, PartialEq, Eq)] pub enum StateSyncError { @@ -32,8 +31,6 @@ pub enum StateSyncError { EmptyState, #[error("Error while trying to communicate with feeder gateway: {0}")] ReaderClientError(String), - #[error("Error while trying to join a task: {0}")] - JoinError(String), } impl From for StateSyncError { @@ -59,9 +56,3 @@ impl From for StateSyncError { StateSyncError::ReaderClientError(error.to_string()) } } - -impl From for StateSyncError { - fn from(error: JoinError) -> Self { - StateSyncError::JoinError(error.to_string()) - } -} From af66526a06d37d12f9992f3d2fa882227404b6a0 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:35:45 +0200 Subject: [PATCH 274/313] ci: add blockifier transfer benchmark (#9891) --- .github/workflows/blockifier_ci.yml | 32 +++++++++++++++++++++++++++++ crates/blockifier/benches/main.rs | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.github/workflows/blockifier_ci.yml b/.github/workflows/blockifier_ci.yml index 572e0f344f2..99cfeff937f 100644 --- a/.github/workflows/blockifier_ci.yml +++ b/.github/workflows/blockifier_ci.yml @@ -92,3 +92,35 @@ jobs: # tracing is not activated by any workspace crate; test the build. - run: cargo build -p blockifier --features tracing - run: cargo test -p blockifier --features tracing + + benchmarking: + runs-on: namespace-profile-medium-ubuntu-24-04-amd64 + if: ${{ github.event_name == 'pull_request' }} + steps: + # Checkout the base branch to benchmark the old code. + - uses: actions/checkout@v4 + with: + ref: ${{ github.base_ref }} + + - uses: ./.github/actions/bootstrap + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + # Restore cargo artifacts build cache. + - name: Restore Cargo build cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: blockifier-bench + cache-on-failure: true + cache-workspace-crates: true + + # Benchmark the base branch code. + - run: cargo run -p bench_tools -- run --package blockifier --out /tmp/base_results + + # Checkout the current branch to benchmark the new code. + - uses: actions/checkout@v4 + with: + clean: false + + # Benchmark the current branch and compare to the previous run. + - run: cargo run -p bench_tools -- run-and-compare --package blockifier --out /tmp/new_results --regression-limit 8.0 diff --git a/crates/blockifier/benches/main.rs b/crates/blockifier/benches/main.rs index c6a84f82e0d..4c5eeb827d7 100644 --- a/crates/blockifier/benches/main.rs +++ b/crates/blockifier/benches/main.rs @@ -66,7 +66,7 @@ pub fn transfers_benchmark(c: &mut Criterion) { criterion_group! { name = benches; - config = Criterion::default().sample_size(50); + config = Criterion::default().sample_size(30); targets = transfers_benchmark } criterion_main!(benches); From f22ffcf5412c0e18c66b1f344bf99db7f7c4138d Mon Sep 17 00:00:00 2001 From: victorkstarkware <160594433+victorkstarkware@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:53:10 +0200 Subject: [PATCH 275/313] apollo_integration_tests: moved inline functions from IntegrationTestManager to NodeSetup (#9795) --- .../src/integration_test_manager.rs | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index fff19006660..00064171a29 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -215,6 +215,17 @@ impl NodeSetup { pub fn get_node_index(&self) -> Option { self.executables.first().map(|executable| executable.node_execution_id.get_node_index()) } + + pub fn get_l1_gas_price_scraper_config(&self) -> L1GasPriceScraperConfig { + for executable_setup in &self.executables { + if let Some(l1_gas_price_scraper_config) = + &executable_setup.get_config().l1_gas_price_scraper_config + { + return l1_gas_price_scraper_config.clone(); + } + } + unreachable!("No executable with a set l1 gas price scraper config.") + } } pub struct RunningNode { @@ -276,22 +287,8 @@ impl IntegrationTestManager { ) .await; - // TODO(Tsabary): these should be functions of `NodeSetup`. - fn get_l1_gas_price_scraper_config( - sequencers_setup: &NodeSetup, - ) -> L1GasPriceScraperConfig { - for executable_setup in &sequencers_setup.executables { - if let Some(l1_gas_price_scraper_config) = - &executable_setup.get_config().l1_gas_price_scraper_config - { - return l1_gas_price_scraper_config.clone(); - } - } - unreachable!("No executable with a set l1 gas price scraper config.") - } - let l1_gas_price_scraper_config = - get_l1_gas_price_scraper_config(sequencers_setup.first().unwrap()); + sequencers_setup.first().unwrap().get_l1_gas_price_scraper_config(); let anvil_base_layer = AnvilBaseLayer::new(Some(1)).await; // Send some transactions to L1 so it has a history of blocks to scrape gas prices from. From e1ccfcf47be3db756da2e6694cb81bcef8a869bb Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:36:33 +0200 Subject: [PATCH 276/313] apollo_deployments: align integration deployment (#9976) --- .../sepolia_integration.json | 2 +- .../deployment_config_hybrid_0.json | 273 ------------------ .../deployment_config_hybrid_1.json | 273 ------------------ .../deployment_config_hybrid_2.json | 273 ------------------ .../deployment_config_override.json | 4 +- .../sepolia_integration/hybrid_0.json | 7 - .../sepolia_integration/hybrid_1.json | 7 - .../sepolia_integration/hybrid_10.json | 2 +- .../sepolia_integration/hybrid_11.json | 2 +- .../sepolia_integration/hybrid_12.json | 2 +- .../sepolia_integration/hybrid_2.json | 7 - 11 files changed, 6 insertions(+), 846 deletions(-) delete mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_0.json delete mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_1.json delete mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_2.json delete mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_0.json delete mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_1.json delete mode 100644 crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_2.json diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json index 8de07283542..814acf6c594 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json @@ -1,5 +1,5 @@ { - "node_and_validator_ids": [[0, "0x64"], [1,"0x65"], [2,"0x66"], [10,"0x1"], [11,"0x1"],[12,"0x1"]], + "node_and_validator_ids": [[10, "0x64"], [11,"0x65"], [12,"0x66"]], "num_validators": 3, "http_server_ingress_alternative_name": "integration-sepolia.starknet.io", "ingress_domain": "starknet.io", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_0.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_0.json deleted file mode 100644 index 7985cc1d67f..00000000000 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_0.json +++ /dev/null @@ -1,273 +0,0 @@ -{ - "application_config_subdir": "crates/apollo_deployments/resources/", - "services": [ - { - "name": "Core", - "controller": "StatefulSet", - "config_paths": [ - "app_configs/batcher_config.json", - "app_configs/class_manager_config.json", - "app_configs/config_manager_config.json", - "app_configs/consensus_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/monitoring_endpoint_config.json", - "app_configs/state_sync_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_0.json", - "services/hybrid/core.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": 1000, - "toleration": "apollo-core-service", - "resources": { - "requests": { - "cpu": 2, - "memory": 4 - }, - "limits": { - "cpu": 7, - "memory": 14 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-0" - }, - "anti_affinity": true, - "update_strategy_type": "RollingUpdate", - "ports": { - "Batcher": 55000, - "ClassManager": 55001, - "SignatureManager": 55008, - "StateSync": 55009, - "ConsensusP2p": 53080, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "HttpServer", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/http_server_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_0.json", - "services/hybrid/http_server.json" - ], - "ingress": { - "domain": "starknet.io", - "alternative_names": [ - "integration-sepolia.starknet.io" - ], - "internal": false, - "rules": [ - { - "path": "/gateway", - "port": 8080, - "backend": null - } - ] - }, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 4, - "memory": 8 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-0" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "HttpServer": 8080, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "Gateway", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/gateway_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_0.json", - "services/hybrid/gateway.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": true, - "replicas": 2, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-0" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "Gateway": 55002, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "L1", - "controller": "Deployment", - "config_paths": [ - "app_configs/base_layer_config.json", - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/l1_endpoint_monitor_config.json", - "app_configs/l1_gas_price_provider_config.json", - "app_configs/l1_gas_price_scraper_config.json", - "app_configs/l1_provider_config.json", - "app_configs/l1_scraper_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_0.json", - "services/hybrid/l1.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-l1-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-0" - }, - "anti_affinity": true, - "update_strategy_type": "Recreate", - "ports": { - "L1EndpointMonitor": 55005, - "L1GasPriceProvider": 55003, - "L1Provider": 55004, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "Mempool", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/mempool_config.json", - "app_configs/mempool_p2p_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_0.json", - "services/hybrid/mempool.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-mempool-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-0" - }, - "anti_affinity": true, - "update_strategy_type": "Recreate", - "ports": { - "Mempool": 55006, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "SierraCompiler", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/monitoring_endpoint_config.json", - "app_configs/sierra_compiler_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_0.json", - "services/hybrid/sierra_compiler.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": true, - "replicas": 2, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-0" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "SierraCompiler": 55007, - "MonitoringEndpoint": 8082 - } - } - ] -} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_1.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_1.json deleted file mode 100644 index 07bf7eb1887..00000000000 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_1.json +++ /dev/null @@ -1,273 +0,0 @@ -{ - "application_config_subdir": "crates/apollo_deployments/resources/", - "services": [ - { - "name": "Core", - "controller": "StatefulSet", - "config_paths": [ - "app_configs/batcher_config.json", - "app_configs/class_manager_config.json", - "app_configs/config_manager_config.json", - "app_configs/consensus_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/monitoring_endpoint_config.json", - "app_configs/state_sync_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_1.json", - "services/hybrid/core.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": 1000, - "toleration": "apollo-core-service", - "resources": { - "requests": { - "cpu": 2, - "memory": 4 - }, - "limits": { - "cpu": 7, - "memory": 14 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-1" - }, - "anti_affinity": true, - "update_strategy_type": "RollingUpdate", - "ports": { - "Batcher": 55000, - "ClassManager": 55001, - "SignatureManager": 55008, - "StateSync": 55009, - "ConsensusP2p": 53080, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "HttpServer", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/http_server_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_1.json", - "services/hybrid/http_server.json" - ], - "ingress": { - "domain": "starknet.io", - "alternative_names": [ - "integration-sepolia.starknet.io" - ], - "internal": false, - "rules": [ - { - "path": "/gateway", - "port": 8080, - "backend": null - } - ] - }, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 4, - "memory": 8 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-1" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "HttpServer": 8080, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "Gateway", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/gateway_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_1.json", - "services/hybrid/gateway.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": true, - "replicas": 2, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-1" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "Gateway": 55002, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "L1", - "controller": "Deployment", - "config_paths": [ - "app_configs/base_layer_config.json", - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/l1_endpoint_monitor_config.json", - "app_configs/l1_gas_price_provider_config.json", - "app_configs/l1_gas_price_scraper_config.json", - "app_configs/l1_provider_config.json", - "app_configs/l1_scraper_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_1.json", - "services/hybrid/l1.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-l1-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-1" - }, - "anti_affinity": true, - "update_strategy_type": "Recreate", - "ports": { - "L1EndpointMonitor": 55005, - "L1GasPriceProvider": 55003, - "L1Provider": 55004, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "Mempool", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/mempool_config.json", - "app_configs/mempool_p2p_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_1.json", - "services/hybrid/mempool.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-mempool-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-1" - }, - "anti_affinity": true, - "update_strategy_type": "Recreate", - "ports": { - "Mempool": 55006, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "SierraCompiler", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/monitoring_endpoint_config.json", - "app_configs/sierra_compiler_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_1.json", - "services/hybrid/sierra_compiler.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": true, - "replicas": 2, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-1" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "SierraCompiler": 55007, - "MonitoringEndpoint": 8082 - } - } - ] -} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_2.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_2.json deleted file mode 100644 index 0da4aa4340e..00000000000 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_hybrid_2.json +++ /dev/null @@ -1,273 +0,0 @@ -{ - "application_config_subdir": "crates/apollo_deployments/resources/", - "services": [ - { - "name": "Core", - "controller": "StatefulSet", - "config_paths": [ - "app_configs/batcher_config.json", - "app_configs/class_manager_config.json", - "app_configs/config_manager_config.json", - "app_configs/consensus_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/monitoring_endpoint_config.json", - "app_configs/state_sync_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_2.json", - "services/hybrid/core.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": 1000, - "toleration": "apollo-core-service", - "resources": { - "requests": { - "cpu": 2, - "memory": 4 - }, - "limits": { - "cpu": 7, - "memory": 14 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-2" - }, - "anti_affinity": true, - "update_strategy_type": "RollingUpdate", - "ports": { - "Batcher": 55000, - "ClassManager": 55001, - "SignatureManager": 55008, - "StateSync": 55009, - "ConsensusP2p": 53080, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "HttpServer", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/http_server_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_2.json", - "services/hybrid/http_server.json" - ], - "ingress": { - "domain": "starknet.io", - "alternative_names": [ - "integration-sepolia.starknet.io" - ], - "internal": false, - "rules": [ - { - "path": "/gateway", - "port": 8080, - "backend": null - } - ] - }, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 4, - "memory": 8 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-2" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "HttpServer": 8080, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "Gateway", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/gateway_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_2.json", - "services/hybrid/gateway.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": true, - "replicas": 2, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-2" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "Gateway": 55002, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "L1", - "controller": "Deployment", - "config_paths": [ - "app_configs/base_layer_config.json", - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/l1_endpoint_monitor_config.json", - "app_configs/l1_gas_price_provider_config.json", - "app_configs/l1_gas_price_scraper_config.json", - "app_configs/l1_provider_config.json", - "app_configs/l1_scraper_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_2.json", - "services/hybrid/l1.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-l1-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-2" - }, - "anti_affinity": true, - "update_strategy_type": "Recreate", - "ports": { - "L1EndpointMonitor": 55005, - "L1GasPriceProvider": 55003, - "L1Provider": 55004, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "Mempool", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/mempool_config.json", - "app_configs/mempool_p2p_config.json", - "app_configs/monitoring_endpoint_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_2.json", - "services/hybrid/mempool.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": false, - "replicas": 1, - "storage": null, - "toleration": "apollo-mempool-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-2" - }, - "anti_affinity": true, - "update_strategy_type": "Recreate", - "ports": { - "Mempool": 55006, - "MonitoringEndpoint": 8082 - } - }, - { - "name": "SierraCompiler", - "controller": "Deployment", - "config_paths": [ - "app_configs/config_manager_config.json", - "app_configs/revert_config.json", - "app_configs/versioned_constants_overrides_config.json", - "app_configs/validate_resource_bounds_config.json", - "app_configs/monitoring_endpoint_config.json", - "app_configs/sierra_compiler_config.json", - "deployments/sepolia_integration/deployment_config_override.json", - "deployments/sepolia_integration/hybrid_2.json", - "services/hybrid/sierra_compiler.json" - ], - "ingress": null, - "k8s_service_config": null, - "autoscale": true, - "replicas": 2, - "storage": null, - "toleration": "apollo-general-service", - "resources": { - "requests": { - "cpu": 1, - "memory": 2 - }, - "limits": { - "cpu": 2, - "memory": 4 - } - }, - "external_secret": { - "gcsm_key": "apollo-sepolia-integration-2" - }, - "anti_affinity": false, - "update_strategy_type": "RollingUpdate", - "ports": { - "SierraCompiler": 55007, - "MonitoringEndpoint": 8082 - } - } - ] -} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json index d557080c9b4..21c0ba3b43f 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json @@ -2,13 +2,13 @@ "base_layer_config.starknet_contract_address": "0x4737c0c1B4D5b1A687B42610DdabEE781152359c", "chain_id": "SN_INTEGRATION_SEPOLIA", "consensus_manager_config.context_config.num_validators": 3, - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-integration-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-integration-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-integration-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://feeder.integration-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_0.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_0.json deleted file mode 100644 index 1b4d7f8b4d2..00000000000 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_0.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "consensus_manager_config.network_config.advertised_multiaddr": "", - "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.advertised_multiaddr": "", - "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "validator_id": "0x64" -} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_1.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_1.json deleted file mode 100644 index 191efac5768..00000000000 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "consensus_manager_config.network_config.advertised_multiaddr": "", - "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.advertised_multiaddr": "", - "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "validator_id": "0x65" -} diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_10.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_10.json index a1e64457f84..1b4d7f8b4d2 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_10.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_10.json @@ -3,5 +3,5 @@ "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, "mempool_p2p_config.network_config.advertised_multiaddr": "", "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "validator_id": "0x1" + "validator_id": "0x64" } diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_11.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_11.json index a1e64457f84..191efac5768 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_11.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_11.json @@ -3,5 +3,5 @@ "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, "mempool_p2p_config.network_config.advertised_multiaddr": "", "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "validator_id": "0x1" + "validator_id": "0x65" } diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_12.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_12.json index a1e64457f84..25524322d64 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_12.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_12.json @@ -3,5 +3,5 @@ "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, "mempool_p2p_config.network_config.advertised_multiaddr": "", "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "validator_id": "0x1" + "validator_id": "0x66" } diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_2.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_2.json deleted file mode 100644 index 25524322d64..00000000000 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/hybrid_2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "consensus_manager_config.network_config.advertised_multiaddr": "", - "consensus_manager_config.network_config.advertised_multiaddr.#is_none": true, - "mempool_p2p_config.network_config.advertised_multiaddr": "", - "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": true, - "validator_id": "0x66" -} From 135ac14024944cf5d435ab2eeebc4e3a50b21284 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:36:45 +0200 Subject: [PATCH 277/313] apollo_deployments: move monitoring port to be part of deployment config (#9919) --- .../resources/app_configs/monitoring_endpoint_config.json | 1 - .../resources/deployment_inputs/mainnet.json | 3 ++- .../resources/deployment_inputs/potc_mock.json | 3 ++- .../resources/deployment_inputs/sepolia_integration.json | 3 ++- .../resources/deployment_inputs/sepolia_testnet.json | 3 ++- .../resources/deployment_inputs/stress_test.json | 3 ++- .../resources/deployment_inputs/upgrade_test.json | 3 ++- .../deployments/mainnet/deployment_config_override.json | 1 + .../deployments/potc_mock/deployment_config_override.json | 1 + .../resources/deployments/replacer_deployment.json | 1 + .../sepolia_integration/deployment_config_override.json | 1 + .../sepolia_testnet/deployment_config_override.json | 1 + .../deployments/stress_test/deployment_config_override.json | 1 + .../deployments/testing/deployment_config_override.json | 1 + .../deployments/upgrade_test/deployment_config_override.json | 1 + crates/apollo_deployments/src/config_override.rs | 4 ++++ crates/apollo_deployments/src/deployment_definitions.rs | 1 + .../apollo_deployments/src/deployment_definitions/testing.rs | 2 ++ crates/apollo_deployments/src/deployments/hybrid.rs | 1 + 19 files changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json b/crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json index 9ce6e598579..7bd5f0bb9fa 100644 --- a/crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json +++ b/crates/apollo_deployments/resources/app_configs/monitoring_endpoint_config.json @@ -2,7 +2,6 @@ "monitoring_endpoint_config.collect_metrics": true, "monitoring_endpoint_config.collect_profiling_metrics": true, "monitoring_endpoint_config.ip": "0.0.0.0", - "monitoring_endpoint_config.port": 8082, "monitoring_config.collect_metrics": true, "monitoring_config.collect_profiling_metrics": true } diff --git a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json index 5b83ad646bb..f11523e1a92 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json @@ -16,5 +16,6 @@ "deployment_environment": "Mainnet", "audited_libfuncs_only": true, "requires_k8s_service_config_params": true, - "http_server_port": 8080 + "http_server_port": 8080, + "monitoring_endpoint_config_port": 8082 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json index 1f1d2cd074f..31715239f4b 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json +++ b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json @@ -41,5 +41,6 @@ "deployment_environment": "PotcMock", "audited_libfuncs_only": true, "requires_k8s_service_config_params": false, - "http_server_port": 8080 + "http_server_port": 8080, + "monitoring_endpoint_config_port": 8082 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json index 814acf6c594..06fb22fa027 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json @@ -16,5 +16,6 @@ "deployment_environment": "SepoliaIntegration", "audited_libfuncs_only": false, "requires_k8s_service_config_params": false, - "http_server_port": 8080 + "http_server_port": 8080, + "monitoring_endpoint_config_port": 8082 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json index 3099b35149b..87dce68d119 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json @@ -16,5 +16,6 @@ "deployment_environment": "SepoliaTestnet", "audited_libfuncs_only": true, "requires_k8s_service_config_params": true, - "http_server_port": 8080 + "http_server_port": 8080, + "monitoring_endpoint_config_port": 8082 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json index b72e9f266e7..c65d0eaa612 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json @@ -16,5 +16,6 @@ "deployment_environment": "StressTest", "audited_libfuncs_only": false, "requires_k8s_service_config_params": false, - "http_server_port": 8080 + "http_server_port": 8080, + "monitoring_endpoint_config_port": 8082 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json index bdad3f92161..23b4a5b9210 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json @@ -16,5 +16,6 @@ "deployment_environment": "UpgradeTest", "audited_libfuncs_only": false, "requires_k8s_service_config_params": true, - "http_server_port": 8080 + "http_server_port": 8080, + "monitoring_endpoint_config_port": 8082 } diff --git a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json index 272b37728b3..9f29de84520 100644 --- a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json @@ -10,6 +10,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-mainnet-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-mainnet-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-mempool-service.apollo-mainnet-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-mempool-service.apollo-mainnet-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-mainnet.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json index c89fded052d..65e2c7077e5 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json @@ -10,6 +10,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-potc-mock-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-potc-mock-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-potc-mock-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.potc-testnet-mock-sepolia.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, diff --git a/crates/apollo_deployments/resources/deployments/replacer_deployment.json b/crates/apollo_deployments/resources/deployments/replacer_deployment.json index e74f12abd96..7be13c956e9 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_deployment.json +++ b/crates/apollo_deployments/resources/deployments/replacer_deployment.json @@ -10,6 +10,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE-IS_NONE_$$$", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", + "monitoring_endpoint_config.port": "$$$_MONITORING_ENDPOINT_CONFIG-PORT_$$$", "sierra_compiler_config.audited_libfuncs_only": "$$$_SIERRA_COMPILER_CONFIG-AUDITED_LIBFUNCS_ONLY_$$$", "starknet_url": "$$$_STARKNET_URL_$$$", "state_sync_config.central_sync_client_config.#is_none": "$$$_STATE_SYNC_CONFIG-CENTRAL_SYNC_CLIENT_CONFIG-IS_NONE_$$$", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json index 21c0ba3b43f..f0dddbd0a4c 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json @@ -10,6 +10,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://feeder.integration-sepolia.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json index 67b6c727ce4..d6a35bbff87 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json @@ -10,6 +10,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-alpha-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-alpha-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-sepolia-alpha-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-alpha-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-sepolia-alpha-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-mempool-service.apollo-sepolia-alpha-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-sepolia.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": false, diff --git a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json index 8c8682849e2..90aecc11016 100644 --- a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json @@ -10,6 +10,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-stresstest-dev-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-stresstest-dev-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-stresstest-dev-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "http://feeder-gateway.starknet-0-14-0-stress-test-05:9713/", "state_sync_config.central_sync_client_config.#is_none": false, diff --git a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json index 32cc705fd6f..057f30862fd 100644 --- a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json @@ -10,6 +10,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": false, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://integration-sepolia.starknet.io/", "state_sync_config.central_sync_client_config.#is_none": true, diff --git a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json index 97fc103ebd4..dd82abaee23 100644 --- a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json @@ -10,6 +10,7 @@ "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-test-0.sw-dev.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-test-1.sw-dev.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-test-2.sw-dev.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-test-10.sw-dev.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-test-11.sw-dev.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-test-12.sw-dev.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://feeder.sn-mainnet-test-upgrade.gateway-proxy.sw-dev.io/", "state_sync_config.central_sync_client_config.#is_none": false, diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index 6b56e3c2494..d2655660cf1 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -158,6 +158,8 @@ pub struct DeploymentConfigOverride { mempool_p2p_bootstrap_config: PeerToPeerBootstrapConfig, #[serde(rename = "http_server_config.port")] http_server_config_port: u16, + #[serde(rename = "monitoring_endpoint_config.port")] + monitoring_endpoint_config_port: u16, } impl DeploymentConfigOverride { @@ -175,6 +177,7 @@ impl DeploymentConfigOverride { mempool_p2p_bootstrap_config: PeerToPeerBootstrapConfig, sierra_compiler_config_audited_libfuncs_only: bool, http_server_config_port: u16, + monitoring_endpoint_config_port: u16, ) -> Self { let ( l1_provider_config_provider_startup_height_override, @@ -198,6 +201,7 @@ impl DeploymentConfigOverride { consensus_p2p_bootstrap_config, mempool_p2p_bootstrap_config, http_server_config_port, + monitoring_endpoint_config_port, } } } diff --git a/crates/apollo_deployments/src/deployment_definitions.rs b/crates/apollo_deployments/src/deployment_definitions.rs index 8a0d9f96324..6939aba1c64 100644 --- a/crates/apollo_deployments/src/deployment_definitions.rs +++ b/crates/apollo_deployments/src/deployment_definitions.rs @@ -89,6 +89,7 @@ pub struct DeploymentInputs { pub requires_k8s_service_config_params: bool, pub audited_libfuncs_only: bool, pub http_server_port: u16, + pub monitoring_endpoint_config_port: u16, } impl DeploymentInputs { diff --git a/crates/apollo_deployments/src/deployment_definitions/testing.rs b/crates/apollo_deployments/src/deployment_definitions/testing.rs index db925678861..9b89fe6287c 100644 --- a/crates/apollo_deployments/src/deployment_definitions/testing.rs +++ b/crates/apollo_deployments/src/deployment_definitions/testing.rs @@ -1,4 +1,5 @@ use apollo_http_server_config::config::HTTP_SERVER_PORT; +use apollo_monitoring_endpoint_config::config::MONITORING_ENDPOINT_DEFAULT_PORT; use starknet_api::block::BlockNumber; use url::Url; @@ -39,6 +40,7 @@ fn testing_deployment_config_override() -> DeploymentConfigOverride { PeerToPeerBootstrapConfig::new(None), false, HTTP_SERVER_PORT, + MONITORING_ENDPOINT_DEFAULT_PORT, ) } diff --git a/crates/apollo_deployments/src/deployments/hybrid.rs b/crates/apollo_deployments/src/deployments/hybrid.rs index 9c049e80c02..4c96db73918 100644 --- a/crates/apollo_deployments/src/deployments/hybrid.rs +++ b/crates/apollo_deployments/src/deployments/hybrid.rs @@ -885,6 +885,7 @@ fn hybrid_deployments(inputs: &DeploymentInputs) -> Vec { mempool_p2p_bootstrap_config.clone(), inputs.audited_libfuncs_only, inputs.http_server_port, + inputs.monitoring_endpoint_config_port, ), &inputs.node_namespace_format, &inputs.ingress_domain, From f7c9e477c56c68c3c2890d18825fcf283c9aaa88 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 6 Nov 2025 10:05:41 +0200 Subject: [PATCH 278/313] scripts: in the update and restart script, if core service, wait for good proposal (#9946) --- .../prod/update_config_and_restart_nodes.py | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index 9dc86a28012..9d7e64ac1f1 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -5,14 +5,23 @@ import sys from typing import Any -from common_lib import Colors, NamespaceAndInstructionArgs, Service, print_colored, print_error -from restarter_lib import ServiceRestarter +from common_lib import ( + Colors, + NamespaceAndInstructionArgs, + RestartStrategy, + Service, + print_colored, + print_error, +) +from restarter_lib import ServiceRestarter, WaitOnMetricRestarter from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, ConstConfigValuesUpdater, update_config_and_restart_nodes, ) +from scripts.prod.metrics_lib import MetricConditionGater + def parse_config_overrides(config_overrides: list[str]) -> dict[str, Any]: """Parse config override strings in key=value format. @@ -135,6 +144,12 @@ def main(): help="Service type to operate on; determines configmap and pod names (default: Core)", ) + args_builder.add_argument( + "--no-check-for-good-proposal", + action="store_true", + help="If set, for restarts of Core (only), will not stop to check that a new proposal succeeded post restarts before continuing.", + ) + args = args_builder.build() config_overrides = parse_config_overrides(args.config_overrides) @@ -152,11 +167,35 @@ def main(): None, ) - restarter = ServiceRestarter.from_restart_strategy( - args.restart_strategy, - namespace_and_instruction_args, - args.service, - ) + if args.no_gate_restart_on_good_proposal: + if args.service != Service.Core: + print_error("The --no-check-for-good-proposal flag is only relevant for Core.") + sys.exit(1) + if args.restart_strategy == RestartStrategy.NO_RESTART: + print_error( + "The --no-check-for-good-proposal flag is not relevant when using no_restart." + ) + sys.exit(1) + + restarter = ServiceRestarter.from_restart_strategy( + args.restart_strategy, + namespace_and_instruction_args, + args.service, + ) + else: + assert args.service == Service.Core + + restarter = WaitOnMetricRestarter( + namespace_and_instruction_args, + args.service, + [ + MetricConditionGater.Metric( + "consensus_decisions_reached_as_proposer", lambda x: x > 0 + ) + ], + metrics_port=8082, + restart_strategy=args.restart_strategy, + ) update_config_and_restart_nodes( ConstConfigValuesUpdater(config_overrides), From edec794b8bb4329ef94ca0df8ff09a41236df97c Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 6 Nov 2025 10:22:48 +0200 Subject: [PATCH 279/313] scripts: use the revert metrics to tell when revert was done. (#9945) --- scripts/prod/set_node_revert_mode.py | 88 ++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index 95fdf5b7109..7f15a8af612 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -5,13 +5,15 @@ import urllib.parse from common_lib import ( + Colors, NamespaceAndInstructionArgs, RestartStrategy, Service, print_colored, print_error, ) -from restarter_lib import ServiceRestarter +from metrics_lib import MetricConditionGater +from restarter_lib import ServiceRestarter, WaitOnMetricRestarter from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, ConstConfigValuesUpdater, @@ -21,8 +23,7 @@ ) -# TODO(guy.f): Remove this once we have metrics we use to decide based on. -def get_logs_explorer_url_for_revert( +def get_logs_explorer_url_for_enable_revert( namespace: str, block_number: int, project_name: str, @@ -36,9 +37,8 @@ def get_logs_explorer_url_for_revert( def set_revert_mode( - namespace_list: list[str], - context_list: Optional[list[str]], - project_name: str, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + restarter: ServiceRestarter, should_revert: bool, revert_up_to_block: int, immediate_active_height: Optional[int] = None, @@ -55,30 +55,73 @@ def set_revert_mode( config_overrides["consensus_manager_config.immediate_active_height"] = height config_overrides["consensus_manager_config.cende_config.skip_write_height"] = height + update_config_and_restart_nodes( + ConstConfigValuesUpdater(config_overrides), + namespace_and_instruction_args, + Service.Core, + restarter, + ) + + +def enable_revert_mode( + namespace_list: list[str], + context_list: Optional[list[str]], + project_name: str, + revert_up_to_block: int, +): + print_colored( + f"Enabling revert mode (reverting up to and including block {revert_up_to_block})", + Colors.YELLOW, + ) post_restart_instructions = [] for namespace in namespace_list: - url = get_logs_explorer_url_for_revert(namespace, revert_up_to_block, project_name) + url = get_logs_explorer_url_for_enable_revert(namespace, revert_up_to_block, project_name) post_restart_instructions.append( f"Please check logs and verify that revert has completed (both in the batcher and for sync). Logs URL: {url}" ) namespace_and_instruction_args = NamespaceAndInstructionArgs( - namespace_list, - context_list, - post_restart_instructions, + namespace_list, context_list, post_restart_instructions ) - restarter = ServiceRestarter.from_restart_strategy( - RestartStrategy.ALL_AT_ONCE, + restarter = WaitOnMetricRestarter( namespace_and_instruction_args, - Service.Core, + Service.Mempool, + [ + MetricConditionGater.Metric( + "apollo_consensus_reverted_batcher_up_to_and_including", + lambda x: x == revert_up_to_block, + f"Waiting for the batcher to revert up to and including {revert_up_to_block}", + ), + MetricConditionGater.Metric( + "apollo_state_sync_reverted_up_to_and_including", + lambda x: x == revert_up_to_block, + f"Waiting for state sync to revert up to and including {revert_up_to_block}", + ), + ], + 8082, + RestartStrategy.ALL_AT_ONCE, ) + set_revert_mode(namespace_and_instruction_args, restarter, True, revert_up_to_block) - update_config_and_restart_nodes( - ConstConfigValuesUpdater(config_overrides), + +def disable_revert_mode( + namespace_list: list[str], + context_list: Optional[list[str]], + immediate_active_height: int, +): + print_colored("Disabling revert mode", Colors.YELLOW) + namespace_and_instruction_args = NamespaceAndInstructionArgs(namespace_list, context_list) + + set_revert_mode( namespace_and_instruction_args, - Service.Core, - restarter, + ServiceRestarter.from_restart_strategy( + RestartStrategy.ALL_AT_ONCE, namespace_and_instruction_args, Service.Core + ), + False, + # Setting to max block to max u64 to disable revert. + 2**64 - 1, + immediate_active_height, ) @@ -174,23 +217,16 @@ def main(): if args.revert_up_to_block is not None else get_current_block_number(args.feeder_url) ) - f"\nEnabling revert mode up to (and including) block {revert_up_to_block}" - set_revert_mode( + enable_revert_mode( namespace_list, context_list, args.project_name, - True, revert_up_to_block, ) if should_disable_revert: - print_colored(f"\nDisabling revert mode") - # Setting to max block to max u64. - set_revert_mode( + disable_revert_mode( namespace_list, context_list, - args.project_name, - False, - 18446744073709551615, # Immediate active height is the block number which will be the first block proposed. revert_up_to_block, ) From 49a64354355b656e6289d239c0958e64f59a1f17 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 6 Nov 2025 10:59:02 +0200 Subject: [PATCH 280/313] scripts: rename the restart script as requested to mention core and not nodes (#9953) --- .../prod/{restart_all_nodes_together.py => restart_all_cores.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/prod/{restart_all_nodes_together.py => restart_all_cores.py} (100%) diff --git a/scripts/prod/restart_all_nodes_together.py b/scripts/prod/restart_all_cores.py similarity index 100% rename from scripts/prod/restart_all_nodes_together.py rename to scripts/prod/restart_all_cores.py From df1c4f1e7d7cb08e9efcbf22f76a112ad993dc8b Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Thu, 6 Nov 2025 13:28:47 +0200 Subject: [PATCH 281/313] apollo_central_sync: validate class_cache_size (#9949) --- crates/apollo_central_sync_config/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/apollo_central_sync_config/src/config.rs b/crates/apollo_central_sync_config/src/config.rs index 5c0904f25e1..f270d23942a 100644 --- a/crates/apollo_central_sync_config/src/config.rs +++ b/crates/apollo_central_sync_config/src/config.rs @@ -23,7 +23,7 @@ pub struct CentralSourceConfig { pub max_state_updates_to_download: usize, pub max_state_updates_to_store_in_memory: usize, pub max_classes_to_download: usize, - // TODO(dan): validate that class_cache_size is a positive integer. + #[validate(range(min = 1))] pub class_cache_size: usize, pub retry_config: RetryConfig, } From 9e762940ddd10824e3f7bd29caef3f102d77ae95 Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Thu, 6 Nov 2025 13:48:49 +0200 Subject: [PATCH 282/313] blockifier: heavy tx benchmark (#9966) --- .../bench_tools/src/types/benchmark_config.rs | 12 +- crates/blockifier/benches/main.rs | 159 ++++++++++++++++-- 2 files changed, 156 insertions(+), 15 deletions(-) diff --git a/crates/bench_tools/src/types/benchmark_config.rs b/crates/bench_tools/src/types/benchmark_config.rs index bafe9b4a684..f92758da726 100644 --- a/crates/bench_tools/src/types/benchmark_config.rs +++ b/crates/bench_tools/src/types/benchmark_config.rs @@ -69,6 +69,7 @@ pub const BENCHMARKS: &[BenchmarkConfig] = &[ "blockifier", "--bench", "blockifier", + "transfers", "--features", "testing,cairo_native", ], @@ -78,7 +79,16 @@ pub const BENCHMARKS: &[BenchmarkConfig] = &[ BenchmarkConfig { name: "transfers_benchmark_vm", package: "blockifier", - cmd_args: &["bench", "-p", "blockifier", "--bench", "blockifier", "--features", "testing"], + cmd_args: &[ + "bench", + "-p", + "blockifier", + "--bench", + "blockifier", + "transfers", + "--features", + "testing", + ], input_dir: None, criterion_benchmark_names: None, // Single benchmark with same name. }, diff --git a/crates/blockifier/benches/main.rs b/crates/blockifier/benches/main.rs index 4c5eeb827d7..a472662ad9e 100644 --- a/crates/blockifier/benches/main.rs +++ b/crates/blockifier/benches/main.rs @@ -10,30 +10,78 @@ //! For Cairo Native compilation run the benchmarks using: //! `cargo bench --bench blockifier --features "cairo_native"`. +use std::sync::Arc; + use apollo_infra_utils::set_global_allocator; -use blockifier::blockifier::config::ConcurrencyConfig; +use blockifier::blockifier::concurrent_transaction_executor::ConcurrentTransactionExecutor; +use blockifier::blockifier::config::{ConcurrencyConfig, TransactionExecutorConfig}; +use blockifier::blockifier::transaction_executor::TransactionExecutor; +use blockifier::concurrency::worker_pool::WorkerPool; +use blockifier::context::BlockContext; +use blockifier::state::cached_state::CachedState; +use blockifier::test_utils::dict_state_reader::DictStateReader; use blockifier::test_utils::transfers_generator::{ RecipientGeneratorType, TransfersGenerator, TransfersGeneratorConfig, }; -#[cfg(feature = "cairo_native")] +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::test_utils::{create_test_init_data, TestInitData}; +use blockifier::transaction::transaction_execution::Transaction; use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; +use blockifier_test_utils::calldata::create_calldata; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +use starknet_api::invoke_tx_args; +use starknet_api::test_utils::invoke::executable_invoke_tx; +use starknet_api::transaction::TransactionVersion; -/// The name of the benchmark. -/// Differentiates between the benchmark running with the Cairo Native and the Cairo VM, -/// enabling proper comparison and regression tracking for each. +/// The name of the benchmarks without the suffix. +const TRANSFERS_BENCHMARK_NAME: &str = "transfers_benchmark"; +const HEAVY_TX_CONCURRENT_BENCHMARK_NAME: &str = "heavy_tx_benchmark_concurrent"; +const HEAVY_TX_SEQUENTIAL_BENCHMARK_NAME: &str = "heavy_tx_benchmark_sequential"; + +/// Suffix for benchmark names to differentiate Cairo Native vs VM. #[cfg(feature = "cairo_native")] -pub const BENCHMARK_NAME: &str = "transfers_benchmark_cairo_native"; +const BENCHMARK_NAME_SUFFIX: &str = "_cairo_native"; #[cfg(not(feature = "cairo_native"))] -pub const BENCHMARK_NAME: &str = "transfers_benchmark_vm"; +const BENCHMARK_NAME_SUFFIX: &str = "_vm"; + +const HEAVY_TX_ENTRY_POINT: &str = "test_builtin_counts_consistency"; // TODO(Arni): Consider how to run this benchmark both with and without setting the allocator. Maybe // hide this macro call under a feature, and run this benchmark regularly or with // `cargo bench --bench blockifier --feature=specified_allocator` set_global_allocator!(); +/// Returns heavy transaction that calls HEAVY_TX_ENTRY_POINT, +/// and initializes the state with the test_init_data. +fn setup_heavy_tx_benchmark( + block_context: &BlockContext, +) -> (Transaction, CachedState) { + // Select Cairo version based on feature flag. + #[cfg(feature = "cairo_native")] + let cairo_version = CairoVersion::Cairo1(RunnableCairo1::Native); + #[cfg(not(feature = "cairo_native"))] + let cairo_version = CairoVersion::Cairo1(RunnableCairo1::Casm); + + let TestInitData { state, account_address, contract_address, mut nonce_manager } = + create_test_init_data(block_context.chain_info(), cairo_version); + + let entry_point_args = vec![]; + let calldata = create_calldata(contract_address, HEAVY_TX_ENTRY_POINT, &entry_point_args); + + let invoke_tx = executable_invoke_tx(invoke_tx_args! { + sender_address: account_address, + calldata, + nonce: nonce_manager.next(account_address), + version: TransactionVersion::THREE, + }); + let account_tx = AccountTransaction::new_for_sequencing(invoke_tx); + let tx = Transaction::Account(account_tx); + + (tx, state) +} + /// Benchmarks the execution phase of the transfers flow. /// The sender account is chosen round-robin. /// The recipient account is chosen randomly. @@ -49,15 +97,96 @@ pub fn transfers_benchmark(c: &mut Criterion) { let mut transfers_generator = TransfersGenerator::new(transfers_generator_config); // Benchmark only the execution phase (run_block_of_transfers call). // Transaction generation and state setup happen for each iteration but are not timed. - c.bench_function(BENCHMARK_NAME, |benchmark| { + c.bench_function( + &format!("{}{}", TRANSFERS_BENCHMARK_NAME, BENCHMARK_NAME_SUFFIX), + |benchmark| { + benchmark.iter_batched( + || { + // Setup: prepare transactions and executor (not measured). + transfers_generator.prepare_to_run_block_of_transfers(None) + }, + |(txs, mut executor_wrapper)| { + // Measured: execute the transactions. + TransfersGenerator::run_block_of_transfers(&txs, &mut executor_wrapper, None) + }, + BatchSize::SmallInput, + ) + }, + ); +} + +/// Benchmarks the execution phase of `HEAVY_TX_ENTRY_POINT` using +/// ConcurrentTransactionExecutor. +pub fn heavy_tx_benchmark_concurrent(c: &mut Criterion) { + let block_context = BlockContext::create_for_account_testing(); + + let executor_config = TransactionExecutorConfig::create_for_testing(true); + let worker_pool = Arc::new(WorkerPool::start(&executor_config.get_worker_pool_config())); + + let bench_name = format!("{}{}", HEAVY_TX_CONCURRENT_BENCHMARK_NAME, BENCHMARK_NAME_SUFFIX); + c.bench_function(&bench_name, |benchmark| { benchmark.iter_batched( || { - // Setup: prepare transactions and executor (not measured). - transfers_generator.prepare_to_run_block_of_transfers(None) + // Setup: prepare transaction and executor (not measured). + let (tx, state) = setup_heavy_tx_benchmark(&block_context); + + let executor = ConcurrentTransactionExecutor::new_for_testing( + state, + block_context.clone(), + worker_pool.clone(), + None, + ); + + (tx, executor) + }, + |(tx, mut executor)| { + // Measured: execute the transaction. + let results = executor.add_txs_and_wait(&[tx]); + let tx_execution_info = &results[0].as_ref().unwrap().0; + tx_execution_info.check_call_infos_native_execution(true); + assert!( + !tx_execution_info.is_reverted(), + "Transaction reverted: {:?}", + tx_execution_info.revert_error + ); + // Abort the block to allow the worker threads to continue to the next block. + executor.abort_block(); + }, + BatchSize::SmallInput, + ) + }); + + // Cleanup worker pool after all benchmark iterations complete. + Arc::try_unwrap(worker_pool).expect("More than one instance of worker pool exists").join(); +} + +/// Benchmarks the execution phase of `HEAVY_TX_ENTRY_POINT` using +/// TransactionExecutor (sequential). +pub fn heavy_tx_benchmark_sequential(c: &mut Criterion) { + let block_context = BlockContext::create_for_account_testing(); + + let bench_name = format!("{}{}", HEAVY_TX_SEQUENTIAL_BENCHMARK_NAME, BENCHMARK_NAME_SUFFIX); + c.bench_function(&bench_name, |benchmark| { + benchmark.iter_batched( + || { + // Setup: prepare transaction and executor (not measured). + let (tx, state) = setup_heavy_tx_benchmark(&block_context); + + let executor_config = TransactionExecutorConfig::create_for_testing(false); + let executor = + TransactionExecutor::new(state, block_context.clone(), executor_config); + + (tx, executor) }, - |(txs, mut executor_wrapper)| { - // Measured: execute the transactions. - TransfersGenerator::run_block_of_transfers(&txs, &mut executor_wrapper, None) + |(tx, mut executor)| { + // Measured: execute the transaction. + let results = executor.execute_txs(&[tx], None); + let tx_execution_info = &results[0].as_ref().unwrap().0; + assert!( + !tx_execution_info.is_reverted(), + "Transaction reverted: {:?}", + tx_execution_info.revert_error + ); }, BatchSize::SmallInput, ) @@ -67,6 +196,8 @@ pub fn transfers_benchmark(c: &mut Criterion) { criterion_group! { name = benches; config = Criterion::default().sample_size(30); - targets = transfers_benchmark + targets = transfers_benchmark, + heavy_tx_benchmark_concurrent, + heavy_tx_benchmark_sequential } criterion_main!(benches); From 55dae651feab8900043e9cfa4094fba48746bfec Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 6 Nov 2025 14:44:32 +0200 Subject: [PATCH 283/313] scripts: fix an import and a few problematic asserts/checks (#9980) --- scripts/prod/restarter_lib.py | 4 ++- .../prod/update_config_and_restart_nodes.py | 29 +++++-------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/scripts/prod/restarter_lib.py b/scripts/prod/restarter_lib.py index 6f7856029bf..7903f6316af 100644 --- a/scripts/prod/restarter_lib.py +++ b/scripts/prod/restarter_lib.py @@ -52,7 +52,9 @@ def _restart_pod( pods = _get_pod_names(namespace, service, index, cluster) if not pods: - print_error(f"Could not find pods for service {service.pod_name}.") + print_error( + f"Could not find pods for service {service.pod_name} with namespace {namespace} and cluster {cluster}." + ) sys.exit(1) # Go over each pod and delete it. diff --git a/scripts/prod/update_config_and_restart_nodes.py b/scripts/prod/update_config_and_restart_nodes.py index 9d7e64ac1f1..5d852941f0f 100755 --- a/scripts/prod/update_config_and_restart_nodes.py +++ b/scripts/prod/update_config_and_restart_nodes.py @@ -8,11 +8,11 @@ from common_lib import ( Colors, NamespaceAndInstructionArgs, - RestartStrategy, Service, print_colored, print_error, ) +from metrics_lib import MetricConditionGater from restarter_lib import ServiceRestarter, WaitOnMetricRestarter from update_config_and_restart_nodes_lib import ( ApolloArgsParserBuilder, @@ -20,8 +20,6 @@ update_config_and_restart_nodes, ) -from scripts.prod.metrics_lib import MetricConditionGater - def parse_config_overrides(config_overrides: list[str]) -> dict[str, Any]: """Parse config override strings in key=value format. @@ -167,24 +165,7 @@ def main(): None, ) - if args.no_gate_restart_on_good_proposal: - if args.service != Service.Core: - print_error("The --no-check-for-good-proposal flag is only relevant for Core.") - sys.exit(1) - if args.restart_strategy == RestartStrategy.NO_RESTART: - print_error( - "The --no-check-for-good-proposal flag is not relevant when using no_restart." - ) - sys.exit(1) - - restarter = ServiceRestarter.from_restart_strategy( - args.restart_strategy, - namespace_and_instruction_args, - args.service, - ) - else: - assert args.service == Service.Core - + if args.service == Service.Core and not args.no_check_for_good_proposal: restarter = WaitOnMetricRestarter( namespace_and_instruction_args, args.service, @@ -196,6 +177,12 @@ def main(): metrics_port=8082, restart_strategy=args.restart_strategy, ) + else: + restarter = ServiceRestarter.from_restart_strategy( + args.restart_strategy, + namespace_and_instruction_args, + args.service, + ) update_config_and_restart_nodes( ConstConfigValuesUpdater(config_overrides), From c3d31565d8f3d87c4b675edd3e84b46a5c10d3e2 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 6 Nov 2025 15:29:08 +0200 Subject: [PATCH 284/313] apollo_base_layer_tests: create crate (#9973) --- Cargo.lock | 15 +++++++++++-- Cargo.toml | 2 ++ commitlint.config.js | 3 ++- crates/apollo_base_layer_tests/Cargo.toml | 21 +++++++++++++++++++ .../src/anvil_base_layer.rs | 0 crates/apollo_base_layer_tests/src/lib.rs | 1 + crates/apollo_integration_tests/Cargo.toml | 3 +-- .../src/flow_test_setup.rs | 2 +- .../src/integration_test_manager.rs | 2 +- crates/apollo_integration_tests/src/lib.rs | 1 - crates/apollo_integration_tests/src/utils.rs | 2 +- .../tests/events_from_other_contracts.rs | 2 +- .../tests/l1_events_scraper_end_to_end.rs | 2 +- .../mocked_starknet_state_update_test.rs | 2 +- workspace_tests/package_integrity_test.rs | 3 ++- 15 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 crates/apollo_base_layer_tests/Cargo.toml rename crates/{apollo_integration_tests => apollo_base_layer_tests}/src/anvil_base_layer.rs (100%) create mode 100644 crates/apollo_base_layer_tests/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6bb9ad6d902..82268377a08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -819,6 +819,18 @@ version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +[[package]] +name = "apollo_base_layer_tests" +version = "0.16.0-rc.1" +dependencies = [ + "alloy", + "async-trait", + "colored 3.0.0", + "papyrus_base_layer", + "starknet_api", + "url", +] + [[package]] name = "apollo_batcher" version = "0.16.0-rc.1" @@ -1563,6 +1575,7 @@ version = "0.16.0-rc.1" dependencies = [ "alloy", "anyhow", + "apollo_base_layer_tests", "apollo_batcher", "apollo_batcher_config", "apollo_class_manager", @@ -1605,13 +1618,11 @@ dependencies = [ "apollo_storage", "apollo_test_utils", "assert_matches", - "async-trait", "axum", "blockifier", "blockifier_test_utils", "cairo-lang-starknet-classes", "clap", - "colored 3.0.0", "futures", "hex", "indexmap 2.11.0", diff --git a/Cargo.toml b/Cargo.toml index f5c3053e4ee..a73a7070f39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ resolver = "2" members = [ + "crates/apollo_base_layer_tests", "crates/apollo_batcher", "crates/apollo_batcher_config", "crates/apollo_batcher_types", @@ -119,6 +120,7 @@ license-file = "LICENSE" [workspace.dependencies] alloy = "1.0.38" anyhow = "1.0.44" +apollo_base_layer_tests.path = "crates/apollo_base_layer_tests" apollo_batcher.path = "crates/apollo_batcher" apollo_batcher_config.path = "crates/apollo_batcher_config" apollo_batcher_types.path = "crates/apollo_batcher_types" diff --git a/commitlint.config.js b/commitlint.config.js index 95a9473a64e..1df3e0e161b 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,4 +1,5 @@ -const AllowedScopes = ['apollo_batcher', +const AllowedScopes = ['apollo_base_layer_tests', + 'apollo_batcher', 'apollo_batcher_config', 'apollo_batcher_types', 'apollo_central_sync', diff --git a/crates/apollo_base_layer_tests/Cargo.toml b/crates/apollo_base_layer_tests/Cargo.toml new file mode 100644 index 00000000000..861bd268e10 --- /dev/null +++ b/crates/apollo_base_layer_tests/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "apollo_base_layer_tests" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + +[features] + +[lints] +workspace = true + +[dependencies] +alloy.workspace = true +async-trait.workspace = true +colored.workspace = true +papyrus_base_layer = { workspace = true, features = ["testing"] } +starknet_api.workspace = true +url.workspace = true + +[dev-dependencies] diff --git a/crates/apollo_integration_tests/src/anvil_base_layer.rs b/crates/apollo_base_layer_tests/src/anvil_base_layer.rs similarity index 100% rename from crates/apollo_integration_tests/src/anvil_base_layer.rs rename to crates/apollo_base_layer_tests/src/anvil_base_layer.rs diff --git a/crates/apollo_base_layer_tests/src/lib.rs b/crates/apollo_base_layer_tests/src/lib.rs new file mode 100644 index 00000000000..f36f6f4d5e0 --- /dev/null +++ b/crates/apollo_base_layer_tests/src/lib.rs @@ -0,0 +1 @@ +pub mod anvil_base_layer; diff --git a/crates/apollo_integration_tests/Cargo.toml b/crates/apollo_integration_tests/Cargo.toml index b63dd968b8e..4cd96c1b9f4 100644 --- a/crates/apollo_integration_tests/Cargo.toml +++ b/crates/apollo_integration_tests/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dependencies] alloy.workspace = true anyhow.workspace = true +apollo_base_layer_tests.workspace = true apollo_batcher.workspace = true apollo_batcher_config.workspace = true apollo_class_manager = { workspace = true, features = ["testing"] } @@ -54,13 +55,11 @@ apollo_state_sync_metrics.workspace = true apollo_storage = { workspace = true, features = ["testing"] } apollo_test_utils.workspace = true assert_matches.workspace = true -async-trait.workspace = true axum.workspace = true blockifier = { workspace = true, features = ["testing"] } blockifier_test_utils.workspace = true cairo-lang-starknet-classes.workspace = true clap = { workspace = true, features = ["derive"] } -colored.workspace = true futures.workspace = true hex.workspace = true indexmap.workspace = true diff --git a/crates/apollo_integration_tests/src/flow_test_setup.rs b/crates/apollo_integration_tests/src/flow_test_setup.rs index de2926e2511..51536f24bf2 100644 --- a/crates/apollo_integration_tests/src/flow_test_setup.rs +++ b/crates/apollo_integration_tests/src/flow_test_setup.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; +use apollo_base_layer_tests::anvil_base_layer::AnvilBaseLayer; use apollo_consensus_manager_config::config::ConsensusManagerConfig; use apollo_http_server::test_utils::HttpTestClient; use apollo_http_server_config::config::HttpServerConfig; @@ -53,7 +54,6 @@ use tokio::sync::Mutex; use tracing::{debug, instrument, Instrument}; use url::Url; -use crate::anvil_base_layer::AnvilBaseLayer; use crate::state_reader::{StorageTestHandles, StorageTestSetup}; use crate::utils::{ create_consensus_manager_configs_from_network_configs, diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index 00064171a29..c4739e44ca9 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -5,6 +5,7 @@ use std::panic; use std::path::PathBuf; use std::time::Duration; +use apollo_base_layer_tests::anvil_base_layer::AnvilBaseLayer; use apollo_http_server::test_utils::HttpTestClient; use apollo_http_server_config::config::HttpServerConfig; use apollo_infra_utils::dumping::serialize_to_file; @@ -41,7 +42,6 @@ use tokio::join; use tokio_util::task::AbortOnDropHandle; use tracing::{info, instrument}; -use crate::anvil_base_layer::AnvilBaseLayer; use crate::executable_setup::{ExecutableSetup, NodeExecutionId}; use crate::monitoring_utils::{ assert_no_reverted_txs, diff --git a/crates/apollo_integration_tests/src/lib.rs b/crates/apollo_integration_tests/src/lib.rs index 9eae4cf8c86..92e8dd84bf8 100644 --- a/crates/apollo_integration_tests/src/lib.rs +++ b/crates/apollo_integration_tests/src/lib.rs @@ -1,4 +1,3 @@ -pub mod anvil_base_layer; pub mod executable_setup; pub mod flow_test_setup; pub mod integration_test_manager; diff --git a/crates/apollo_integration_tests/src/utils.rs b/crates/apollo_integration_tests/src/utils.rs index 9c758a69c7a..82aeabde434 100644 --- a/crates/apollo_integration_tests/src/utils.rs +++ b/crates/apollo_integration_tests/src/utils.rs @@ -2,6 +2,7 @@ use std::future::Future; use std::net::SocketAddr; use std::time::Duration; +use apollo_base_layer_tests::anvil_base_layer::AnvilBaseLayer; use apollo_batcher::pre_confirmed_cende_client::RECORDER_WRITE_PRE_CONFIRMED_BLOCK_PATH; use apollo_batcher_config::config::{BatcherConfig, BlockBuilderConfig}; use apollo_class_manager_config::config::{ @@ -79,7 +80,6 @@ use tokio::task::JoinHandle; use tracing::{debug, info, Instrument}; use url::Url; -use crate::anvil_base_layer::AnvilBaseLayer; use crate::state_reader::StorageTestConfig; pub const ACCOUNT_ID_0: AccountId = 0; diff --git a/crates/apollo_integration_tests/tests/events_from_other_contracts.rs b/crates/apollo_integration_tests/tests/events_from_other_contracts.rs index 89fdcc07ea0..469b3ca5ee1 100644 --- a/crates/apollo_integration_tests/tests/events_from_other_contracts.rs +++ b/crates/apollo_integration_tests/tests/events_from_other_contracts.rs @@ -1,4 +1,4 @@ -use apollo_integration_tests::anvil_base_layer::{send_message_to_l2, AnvilBaseLayer}; +use apollo_base_layer_tests::anvil_base_layer::{send_message_to_l2, AnvilBaseLayer}; use assert_matches::assert_matches; use papyrus_base_layer::constants::{EventIdentifier, LOG_MESSAGE_TO_L2_EVENT_IDENTIFIER}; use papyrus_base_layer::ethereum_base_layer_contract::Starknet; diff --git a/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs index 76d64dd1d22..26797aaef84 100644 --- a/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs +++ b/crates/apollo_integration_tests/tests/l1_events_scraper_end_to_end.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use std::time::Duration; use alloy::primitives::U256; -use apollo_integration_tests::anvil_base_layer::AnvilBaseLayer; +use apollo_base_layer_tests::anvil_base_layer::AnvilBaseLayer; use apollo_l1_provider::event_identifiers_to_track; use apollo_l1_provider::l1_scraper::{fetch_start_block, L1Scraper}; use apollo_l1_provider_types::{Event, MockL1ProviderClient}; diff --git a/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs b/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs index dcb659b610d..bedec803935 100644 --- a/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs +++ b/crates/apollo_integration_tests/tests/mocked_starknet_state_update_test.rs @@ -2,7 +2,7 @@ use alloy::primitives::{I256, U256}; use alloy::providers::Provider; use alloy::rpc::types::eth::Filter as EthEventFilter; use alloy::sol_types::SolEventInterface; -use apollo_integration_tests::anvil_base_layer::{AnvilBaseLayer, MockedStateUpdate}; +use apollo_base_layer_tests::anvil_base_layer::{AnvilBaseLayer, MockedStateUpdate}; use papyrus_base_layer::ethereum_base_layer_contract::Starknet; use papyrus_base_layer::BaseLayerContract; use pretty_assertions::assert_eq; diff --git a/workspace_tests/package_integrity_test.rs b/workspace_tests/package_integrity_test.rs index 246118ac4ca..f0ec4be0723 100644 --- a/workspace_tests/package_integrity_test.rs +++ b/workspace_tests/package_integrity_test.rs @@ -4,7 +4,8 @@ use toml_test_utils::{DependencyValue, PackageEntryValue, MEMBER_TOMLS}; /// Hard-coded list of crates that are allowed to use test code in their (non-dev) dependencies. /// Should only contain test-related crates. -static CRATES_ALLOWED_TO_USE_TESTING_FEATURE: [&str; 6] = [ +static CRATES_ALLOWED_TO_USE_TESTING_FEATURE: [&str; 7] = [ + "apollo_base_layer_tests", "apollo_integration_tests", "apollo_test_utils", "blockifier_test_utils", From da0873fcbea9a62ca1efa45edf3f51a3cd8dfae3 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:27:02 +0200 Subject: [PATCH 285/313] apollo_deployments: move rpc config port to be part of the deployment overrides (#9997) --- Cargo.lock | 1 + crates/apollo_deployments/Cargo.toml | 1 + .../resources/app_configs/state_sync_config.json | 1 - .../resources/deployment_inputs/mainnet.json | 3 ++- .../resources/deployment_inputs/potc_mock.json | 3 ++- .../resources/deployment_inputs/sepolia_integration.json | 3 ++- .../resources/deployment_inputs/sepolia_testnet.json | 3 ++- .../resources/deployment_inputs/stress_test.json | 3 ++- .../resources/deployment_inputs/upgrade_test.json | 3 ++- .../deployments/mainnet/deployment_config_override.json | 1 + .../deployments/potc_mock/deployment_config_override.json | 1 + .../resources/deployments/replacer_deployment.json | 1 + .../sepolia_integration/deployment_config_override.json | 1 + .../sepolia_testnet/deployment_config_override.json | 1 + .../deployments/stress_test/deployment_config_override.json | 1 + .../deployments/testing/deployment_config_override.json | 1 + .../deployments/upgrade_test/deployment_config_override.json | 1 + crates/apollo_deployments/src/config_override.rs | 4 ++++ crates/apollo_deployments/src/deployment_definitions.rs | 1 + .../apollo_deployments/src/deployment_definitions/testing.rs | 2 ++ crates/apollo_deployments/src/deployments/hybrid.rs | 1 + crates/apollo_rpc/src/lib.rs | 4 +++- 22 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82268377a08..393d1524c05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1373,6 +1373,7 @@ dependencies = [ "apollo_monitoring_endpoint_config", "apollo_node", "apollo_node_config", + "apollo_rpc", "indexmap 2.11.0", "libp2p", "serde", diff --git a/crates/apollo_deployments/Cargo.toml b/crates/apollo_deployments/Cargo.toml index 30365785c7a..7a53f9ad3aa 100644 --- a/crates/apollo_deployments/Cargo.toml +++ b/crates/apollo_deployments/Cargo.toml @@ -16,6 +16,7 @@ apollo_infra.workspace = true apollo_infra_utils.workspace = true apollo_monitoring_endpoint_config.workspace = true apollo_node_config.workspace = true +apollo_rpc.workspace = true indexmap.workspace = true libp2p.workspace = true serde.workspace = true diff --git a/crates/apollo_deployments/resources/app_configs/state_sync_config.json b/crates/apollo_deployments/resources/app_configs/state_sync_config.json index 30aeb1992e2..2ccc480d2ab 100644 --- a/crates/apollo_deployments/resources/app_configs/state_sync_config.json +++ b/crates/apollo_deployments/resources/app_configs/state_sync_config.json @@ -45,7 +45,6 @@ "state_sync_config.rpc_config.max_events_chunk_size": 1000, "state_sync_config.rpc_config.max_events_keys": 100, "state_sync_config.rpc_config.ip": "0.0.0.0", - "state_sync_config.rpc_config.port": 8090, "state_sync_config.should_replay_processed_txs_metric": false, "state_sync_config.storage_config.db_config.enforce_file_exists": false, "state_sync_config.storage_config.db_config.growth_step": 67108864, diff --git a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json index f11523e1a92..83a2ea46bb9 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json @@ -17,5 +17,6 @@ "audited_libfuncs_only": true, "requires_k8s_service_config_params": true, "http_server_port": 8080, - "monitoring_endpoint_config_port": 8082 + "monitoring_endpoint_config_port": 8082, + "state_sync_config_rpc_config_port": 8090 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json index 31715239f4b..6b51afa67ef 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json +++ b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json @@ -42,5 +42,6 @@ "audited_libfuncs_only": true, "requires_k8s_service_config_params": false, "http_server_port": 8080, - "monitoring_endpoint_config_port": 8082 + "monitoring_endpoint_config_port": 8082, + "state_sync_config_rpc_config_port": 8090 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json index 06fb22fa027..073fbb2add2 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json @@ -17,5 +17,6 @@ "audited_libfuncs_only": false, "requires_k8s_service_config_params": false, "http_server_port": 8080, - "monitoring_endpoint_config_port": 8082 + "monitoring_endpoint_config_port": 8082, + "state_sync_config_rpc_config_port": 8090 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json index 87dce68d119..7e16501f75e 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json @@ -17,5 +17,6 @@ "audited_libfuncs_only": true, "requires_k8s_service_config_params": true, "http_server_port": 8080, - "monitoring_endpoint_config_port": 8082 + "monitoring_endpoint_config_port": 8082, + "state_sync_config_rpc_config_port": 8090 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json index c65d0eaa612..885050928b1 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json @@ -17,5 +17,6 @@ "audited_libfuncs_only": false, "requires_k8s_service_config_params": false, "http_server_port": 8080, - "monitoring_endpoint_config_port": 8082 + "monitoring_endpoint_config_port": 8082, + "state_sync_config_rpc_config_port": 8090 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json index 23b4a5b9210..4b82df4ea85 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json @@ -17,5 +17,6 @@ "audited_libfuncs_only": false, "requires_k8s_service_config_params": true, "http_server_port": 8080, - "monitoring_endpoint_config_port": 8082 + "monitoring_endpoint_config_port": 8082, + "state_sync_config_rpc_config_port": 8090 } diff --git a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json index 9f29de84520..748cf651c7c 100644 --- a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json @@ -16,5 +16,6 @@ "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.rpc_config.port": 8090, "strk_fee_token_address": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" } diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json index 65e2c7077e5..f402226dbfe 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json @@ -16,5 +16,6 @@ "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.rpc_config.port": 8090, "strk_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" } diff --git a/crates/apollo_deployments/resources/deployments/replacer_deployment.json b/crates/apollo_deployments/resources/deployments/replacer_deployment.json index 7be13c956e9..245e939b11c 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_deployment.json +++ b/crates/apollo_deployments/resources/deployments/replacer_deployment.json @@ -16,5 +16,6 @@ "state_sync_config.central_sync_client_config.#is_none": "$$$_STATE_SYNC_CONFIG-CENTRAL_SYNC_CLIENT_CONFIG-IS_NONE_$$$", "state_sync_config.network_config.#is_none": "$$$_STATE_SYNC_CONFIG-NETWORK_CONFIG-IS_NONE_$$$", "state_sync_config.p2p_sync_client_config.#is_none": "$$$_STATE_SYNC_CONFIG-P2P_SYNC_CLIENT_CONFIG-IS_NONE_$$$", + "state_sync_config.rpc_config.port": "$$$_STATE_SYNC_CONFIG-RPC_CONFIG-PORT_$$$", "strk_fee_token_address": "$$$_STRK_FEE_TOKEN_ADDRESS_$$$" } diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json index f0dddbd0a4c..50ebb642884 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json @@ -16,5 +16,6 @@ "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.rpc_config.port": 8090, "strk_fee_token_address": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" } diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json index d6a35bbff87..af602503587 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json @@ -16,5 +16,6 @@ "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.rpc_config.port": 8090, "strk_fee_token_address": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" } diff --git a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json index 90aecc11016..47ecc2618d7 100644 --- a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json @@ -16,5 +16,6 @@ "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.rpc_config.port": 8090, "strk_fee_token_address": "0x02208cce4221df1f35943958340abc812aa79a8f6a533bff4ee00416d3d06cd6" } diff --git a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json index 057f30862fd..7e0a66e0326 100644 --- a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json @@ -16,5 +16,6 @@ "state_sync_config.central_sync_client_config.#is_none": true, "state_sync_config.network_config.#is_none": false, "state_sync_config.p2p_sync_client_config.#is_none": false, + "state_sync_config.rpc_config.port": 8090, "strk_fee_token_address": "0x1002" } diff --git a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json index dd82abaee23..7b834a12fb2 100644 --- a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json @@ -16,5 +16,6 @@ "state_sync_config.central_sync_client_config.#is_none": false, "state_sync_config.network_config.#is_none": true, "state_sync_config.p2p_sync_client_config.#is_none": true, + "state_sync_config.rpc_config.port": 8090, "strk_fee_token_address": "0x06cd5b5125491c4bccec3d3b8635cbd98542c1d91a134541eca6e108cf0639f6" } diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index d2655660cf1..aa241096684 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -160,6 +160,8 @@ pub struct DeploymentConfigOverride { http_server_config_port: u16, #[serde(rename = "monitoring_endpoint_config.port")] monitoring_endpoint_config_port: u16, + #[serde(rename = "state_sync_config.rpc_config.port")] + state_sync_config_rpc_config_port: u16, } impl DeploymentConfigOverride { @@ -178,6 +180,7 @@ impl DeploymentConfigOverride { sierra_compiler_config_audited_libfuncs_only: bool, http_server_config_port: u16, monitoring_endpoint_config_port: u16, + state_sync_config_rpc_config_port: u16, ) -> Self { let ( l1_provider_config_provider_startup_height_override, @@ -202,6 +205,7 @@ impl DeploymentConfigOverride { mempool_p2p_bootstrap_config, http_server_config_port, monitoring_endpoint_config_port, + state_sync_config_rpc_config_port, } } } diff --git a/crates/apollo_deployments/src/deployment_definitions.rs b/crates/apollo_deployments/src/deployment_definitions.rs index 6939aba1c64..9b16d23a1fc 100644 --- a/crates/apollo_deployments/src/deployment_definitions.rs +++ b/crates/apollo_deployments/src/deployment_definitions.rs @@ -90,6 +90,7 @@ pub struct DeploymentInputs { pub audited_libfuncs_only: bool, pub http_server_port: u16, pub monitoring_endpoint_config_port: u16, + pub state_sync_config_rpc_config_port: u16, } impl DeploymentInputs { diff --git a/crates/apollo_deployments/src/deployment_definitions/testing.rs b/crates/apollo_deployments/src/deployment_definitions/testing.rs index 9b89fe6287c..7b942363de6 100644 --- a/crates/apollo_deployments/src/deployment_definitions/testing.rs +++ b/crates/apollo_deployments/src/deployment_definitions/testing.rs @@ -1,5 +1,6 @@ use apollo_http_server_config::config::HTTP_SERVER_PORT; use apollo_monitoring_endpoint_config::config::MONITORING_ENDPOINT_DEFAULT_PORT; +use apollo_rpc::RPC_CONFIG_DEFAULT_PORT; use starknet_api::block::BlockNumber; use url::Url; @@ -41,6 +42,7 @@ fn testing_deployment_config_override() -> DeploymentConfigOverride { false, HTTP_SERVER_PORT, MONITORING_ENDPOINT_DEFAULT_PORT, + RPC_CONFIG_DEFAULT_PORT, ) } diff --git a/crates/apollo_deployments/src/deployments/hybrid.rs b/crates/apollo_deployments/src/deployments/hybrid.rs index 4c96db73918..0060bbdb812 100644 --- a/crates/apollo_deployments/src/deployments/hybrid.rs +++ b/crates/apollo_deployments/src/deployments/hybrid.rs @@ -886,6 +886,7 @@ fn hybrid_deployments(inputs: &DeploymentInputs) -> Vec { inputs.audited_libfuncs_only, inputs.http_server_port, inputs.monitoring_endpoint_config_port, + inputs.state_sync_config_rpc_config_port, ), &inputs.node_namespace_format, &inputs.ingress_domain, diff --git a/crates/apollo_rpc/src/lib.rs b/crates/apollo_rpc/src/lib.rs index d20e6700efc..b44e9cbaaf5 100644 --- a/crates/apollo_rpc/src/lib.rs +++ b/crates/apollo_rpc/src/lib.rs @@ -67,6 +67,8 @@ const GENESIS_HASH: &str = "0x0"; /// Maximum size of a supported transaction body - 10MB. pub const SERVER_MAX_BODY_SIZE: u32 = 10 * 1024 * 1024; +pub const RPC_CONFIG_DEFAULT_PORT: u16 = 8090; + #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Validate)] pub struct RpcConfig { #[validate(custom = "validate_ascii")] @@ -87,7 +89,7 @@ impl Default for RpcConfig { RpcConfig { chain_id: ChainId::Mainnet, ip: "0.0.0.0".parse().unwrap(), - port: 8090, + port: RPC_CONFIG_DEFAULT_PORT, max_events_chunk_size: 1000, max_events_keys: 100, collect_metrics: false, From 8d1208a51598a7efd3fd7a824735844f4b1f3922 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Thu, 6 Nov 2025 16:49:45 +0200 Subject: [PATCH 286/313] scripts: make the code more generic so we can support a "only wait for metric" script (#9986) --- scripts/prod/restarter_lib.py | 55 +++++++++++++------ .../update_config_and_restart_nodes_lib.py | 35 +++++++----- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/scripts/prod/restarter_lib.py b/scripts/prod/restarter_lib.py index 7903f6316af..170cf87edb7 100644 --- a/scripts/prod/restarter_lib.py +++ b/scripts/prod/restarter_lib.py @@ -91,16 +91,18 @@ def from_restart_strategy( else wait_until_y_or_n(f"Do you want to restart the next pod?") ) - return ChecksBetweenRestarts( + return ChecksBetweenRestartsCompositeRestarter( namespace_and_instruction_args, service, check_between_restarts, + RestartPodOnlyRestarter(namespace_and_instruction_args, service), ) elif restart_strategy == RestartStrategy.ALL_AT_ONCE: - return ChecksBetweenRestarts( + return ChecksBetweenRestartsCompositeRestarter( namespace_and_instruction_args, service, lambda instance_index: True, + RestartPodOnlyRestarter(namespace_and_instruction_args, service), ) elif restart_strategy == RestartStrategy.NO_RESTART: assert ( @@ -111,31 +113,47 @@ def from_restart_strategy( raise ValueError(f"Invalid restart strategy: {restart_strategy}") -class ChecksBetweenRestarts(ServiceRestarter): - """Checks between restarts.""" +class RestartPodOnlyRestarter(ServiceRestarter): + """Restarter that only restarts the pod and does not check anything else.""" def __init__( - self, - namespace_and_instruction_args: NamespaceAndInstructionArgs, - service: Service, - check_between_restarts: Callable[[int], bool], + self, namespace_and_instruction_args: NamespaceAndInstructionArgs, service: Service ): super().__init__(namespace_and_instruction_args, service) - self.check_between_restarts = check_between_restarts def restart_service(self, instance_index: int) -> bool: - """Restart the instance one by one, running the use code in between each restart.""" + """Restarts the pod and does nothing else.""" self._restart_pod( self.namespace_and_instruction_args.get_namespace(instance_index), self.service, instance_index, self.namespace_and_instruction_args.get_cluster(instance_index), ) + print_colored(f"Restarted pod {instance_index}. ", Colors.YELLOW) + return True + + +class ChecksBetweenRestartsCompositeRestarter(ServiceRestarter): + """Checks between restarts.""" + + def __init__( + self, + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + check_between_restarts: Callable[[int], bool], + base_service_restarter: ServiceRestarter, + ): + super().__init__(namespace_and_instruction_args, service) + self.check_between_restarts = check_between_restarts + self.base_service_restarter = base_service_restarter + + def restart_service(self, instance_index: int) -> bool: + """Call the base restarter on each instance one by one, running the check_between_restarts in between each.""" + self.base_service_restarter.restart_service(instance_index) + instructions = self.namespace_and_instruction_args.get_instruction(instance_index) - print_colored( - f"Restarted pod {instance_index}.\n{instructions if instructions is not None else ''} ", - Colors.YELLOW, - ) + if instructions is not None: + print_colored(f"{instructions} ", Colors.YELLOW) return self.check_between_restarts(instance_index) @@ -148,7 +166,7 @@ def restart_service(self, instance_index: int) -> bool: return True -class WaitOnMetricRestarter(ChecksBetweenRestarts): +class WaitOnMetricRestarter(ChecksBetweenRestartsCompositeRestarter): def __init__( self, namespace_and_instruction_args: NamespaceAndInstructionArgs, @@ -161,13 +179,18 @@ def __init__( self.metrics_port = metrics_port if restart_strategy == RestartStrategy.ONE_BY_ONE: check_function = self._check_between_each_restart + base_restarter = RestartPodOnlyRestarter(namespace_and_instruction_args, service) elif restart_strategy == RestartStrategy.ALL_AT_ONCE: check_function = self._check_all_only_after_last_restart + base_restarter = RestartPodOnlyRestarter(namespace_and_instruction_args, service) + elif restart_strategy == RestartStrategy.NO_RESTART: + check_function = self._check_between_each_restart + base_restarter = NoOpServiceRestarter(namespace_and_instruction_args, service) else: print_error(f"Invalid restart strategy: {restart_strategy} for WaitOnMetricRestarter.") sys.exit(1) - super().__init__(namespace_and_instruction_args, service, check_function) + super().__init__(namespace_and_instruction_args, service, check_function, base_restarter) def _check_between_each_restart(self, instance_index: int) -> bool: self._wait_for_pod_to_satisfy_condition(instance_index) diff --git a/scripts/prod/update_config_and_restart_nodes_lib.py b/scripts/prod/update_config_and_restart_nodes_lib.py index 39885d6a9bb..680ae30ef0b 100755 --- a/scripts/prod/update_config_and_restart_nodes_lib.py +++ b/scripts/prod/update_config_and_restart_nodes_lib.py @@ -392,21 +392,12 @@ def apply_configmap( sys.exit(1) -def update_config_and_restart_nodes( +def _update_config( config_values_updater: ConfigValuesUpdater, namespace_and_instruction_args: NamespaceAndInstructionArgs, service: Service, - restarter: ServiceRestarter, ) -> None: - assert config_values_updater is not None, "config_values_updater must be provided" - assert namespace_and_instruction_args.namespace_list is not None, "namespaces must be provided" - - if not namespace_and_instruction_args.cluster_list: - print_colored( - "cluster-prefix/cluster-list not provided. Assuming all nodes are on the current cluster", - Colors.RED, - ) - + """Update and apply configurations for all nodes.""" # Store original and updated configs for all nodes configs = [] @@ -452,11 +443,27 @@ def update_config_and_restart_nodes( namespace_and_instruction_args.get_cluster(index), ) - for index, config in enumerate(configs): + +def update_config_and_restart_nodes( + config_values_updater: Optional[ConfigValuesUpdater], + namespace_and_instruction_args: NamespaceAndInstructionArgs, + service: Service, + restarter: ServiceRestarter, +) -> None: + assert namespace_and_instruction_args.namespace_list is not None, "namespaces must be provided" + + if not namespace_and_instruction_args.cluster_list: + print_colored( + "cluster-prefix/cluster-list not provided. Assuming all nodes are on the current cluster", + Colors.RED, + ) + + if config_values_updater is not None: + _update_config(config_values_updater, namespace_and_instruction_args, service) + + for index in range(namespace_and_instruction_args.size()): if not restarter.restart_service(index): print_colored("\nAborting restart process.") sys.exit(1) - print_colored("\nAll pods have been successfully restarted!", Colors.GREEN) - print("\nOperation completed successfully!") From ae1f843a0ed9775465c56e2ee77058a43604e8b2 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 6 Nov 2025 17:03:07 +0200 Subject: [PATCH 287/313] apollo_integration_tests: assert_full_blocks_flow assert error (#9957) --- crates/apollo_integration_tests/tests/common/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/apollo_integration_tests/tests/common/mod.rs b/crates/apollo_integration_tests/tests/common/mod.rs index 952238e536f..0ffbcc4f5c9 100644 --- a/crates/apollo_integration_tests/tests/common/mod.rs +++ b/crates/apollo_integration_tests/tests/common/mod.rs @@ -153,9 +153,15 @@ fn assert_full_blocks_flow(recorder_handle: &PrometheusHandle, expecting_full_bl ) .unwrap(); if expecting_full_blocks { - assert!(full_blocks_metric > 0); + assert!( + full_blocks_metric > 0, + "Expected full blocks, but found {full_blocks_metric} full blocks." + ); } else { - assert_eq!(full_blocks_metric, 0); + assert_eq!( + full_blocks_metric, 0, + "Expected no full blocks, but found {full_blocks_metric} full blocks." + ); } } From d978ba3426e4bc2627143244f417c39fe8d7419e Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Thu, 6 Nov 2025 17:43:21 +0200 Subject: [PATCH 288/313] apollo_deployments: move p2p ports to deployment overrides (#9998) --- .../resources/app_configs/consensus_manager_config.json | 1 - .../resources/app_configs/mempool_p2p_config.json | 1 - .../resources/deployment_inputs/mainnet.json | 4 +++- .../resources/deployment_inputs/potc_mock.json | 4 +++- .../resources/deployment_inputs/sepolia_integration.json | 4 +++- .../resources/deployment_inputs/sepolia_testnet.json | 4 +++- .../resources/deployment_inputs/stress_test.json | 4 +++- .../resources/deployment_inputs/upgrade_test.json | 4 +++- .../deployments/mainnet/deployment_config_override.json | 2 ++ .../potc_mock/deployment_config_override.json | 2 ++ .../resources/deployments/replacer_deployment.json | 2 ++ .../sepolia_integration/deployment_config_override.json | 2 ++ .../sepolia_testnet/deployment_config_override.json | 2 ++ .../stress_test/deployment_config_override.json | 2 ++ .../deployments/testing/deployment_config_override.json | 2 ++ .../upgrade_test/deployment_config_override.json | 2 ++ crates/apollo_deployments/src/config_override.rs | 8 ++++++++ crates/apollo_deployments/src/deployment_definitions.rs | 2 ++ .../src/deployment_definitions/testing.rs | 9 ++++++++- crates/apollo_deployments/src/deployments/hybrid.rs | 2 ++ 20 files changed, 54 insertions(+), 9 deletions(-) diff --git a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json index 88461e479b7..7beefb75e59 100644 --- a/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json +++ b/crates/apollo_deployments/resources/app_configs/consensus_manager_config.json @@ -44,7 +44,6 @@ "consensus_manager_config.network_config.idle_connection_timeout": 120, "consensus_manager_config.network_config.peer_manager_config.malicious_timeout_seconds": 0, "consensus_manager_config.network_config.peer_manager_config.unstable_timeout_millis": 0, - "consensus_manager_config.network_config.port": 53080, "consensus_manager_config.network_config.reported_peer_ids_buffer_size": 100000, "consensus_manager_config.network_config.session_timeout": 120, "consensus_manager_config.proposals_topic": "consensus_proposals", diff --git a/crates/apollo_deployments/resources/app_configs/mempool_p2p_config.json b/crates/apollo_deployments/resources/app_configs/mempool_p2p_config.json index ff7b82d276a..a1ea26f6f17 100644 --- a/crates/apollo_deployments/resources/app_configs/mempool_p2p_config.json +++ b/crates/apollo_deployments/resources/app_configs/mempool_p2p_config.json @@ -9,7 +9,6 @@ "mempool_p2p_config.network_config.idle_connection_timeout": 120, "mempool_p2p_config.network_config.peer_manager_config.malicious_timeout_seconds": 0, "mempool_p2p_config.network_config.peer_manager_config.unstable_timeout_millis": 0, - "mempool_p2p_config.network_config.port": 53200, "mempool_p2p_config.network_config.reported_peer_ids_buffer_size": 100000, "mempool_p2p_config.network_config.session_timeout": 120, "mempool_p2p_config.transaction_batch_rate_millis": 100 diff --git a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json index 83a2ea46bb9..7342f3e5936 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/mainnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/mainnet.json @@ -18,5 +18,7 @@ "requires_k8s_service_config_params": true, "http_server_port": 8080, "monitoring_endpoint_config_port": 8082, - "state_sync_config_rpc_config_port": 8090 + "state_sync_config_rpc_config_port": 8090, + "mempool_p2p_config_network_config_port": 53200, + "consensus_manager_config_network_config_port": 53080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json index 6b51afa67ef..aec2e25963e 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json +++ b/crates/apollo_deployments/resources/deployment_inputs/potc_mock.json @@ -43,5 +43,7 @@ "requires_k8s_service_config_params": false, "http_server_port": 8080, "monitoring_endpoint_config_port": 8082, - "state_sync_config_rpc_config_port": 8090 + "state_sync_config_rpc_config_port": 8090, + "mempool_p2p_config_network_config_port": 53200, + "consensus_manager_config_network_config_port": 53080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json index 073fbb2add2..54379e39e8e 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_integration.json @@ -18,5 +18,7 @@ "requires_k8s_service_config_params": false, "http_server_port": 8080, "monitoring_endpoint_config_port": 8082, - "state_sync_config_rpc_config_port": 8090 + "state_sync_config_rpc_config_port": 8090, + "mempool_p2p_config_network_config_port": 53200, + "consensus_manager_config_network_config_port": 53080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json index 7e16501f75e..ea80bb95437 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json +++ b/crates/apollo_deployments/resources/deployment_inputs/sepolia_testnet.json @@ -18,5 +18,7 @@ "requires_k8s_service_config_params": true, "http_server_port": 8080, "monitoring_endpoint_config_port": 8082, - "state_sync_config_rpc_config_port": 8090 + "state_sync_config_rpc_config_port": 8090, + "mempool_p2p_config_network_config_port": 53200, + "consensus_manager_config_network_config_port": 53080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json index 885050928b1..ce883b655f8 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/stress_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/stress_test.json @@ -18,5 +18,7 @@ "requires_k8s_service_config_params": false, "http_server_port": 8080, "monitoring_endpoint_config_port": 8082, - "state_sync_config_rpc_config_port": 8090 + "state_sync_config_rpc_config_port": 8090, + "mempool_p2p_config_network_config_port": 53200, + "consensus_manager_config_network_config_port": 53080 } diff --git a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json index 4b82df4ea85..6a1937c11de 100644 --- a/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json +++ b/crates/apollo_deployments/resources/deployment_inputs/upgrade_test.json @@ -18,5 +18,7 @@ "requires_k8s_service_config_params": true, "http_server_port": 8080, "monitoring_endpoint_config_port": 8082, - "state_sync_config_rpc_config_port": 8090 + "state_sync_config_rpc_config_port": 8090, + "mempool_p2p_config_network_config_port": 53200, + "consensus_manager_config_network_config_port": 53080 } diff --git a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json index 748cf651c7c..b2a0fdbe273 100644 --- a/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/mainnet/deployment_config_override.json @@ -4,12 +4,14 @@ "consensus_manager_config.context_config.num_validators": 3, "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-mainnet-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-mainnet-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-mainnet-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-mainnet-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-mainnet-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-mainnet-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-mainnet-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-mainnet-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-core-service.apollo-mainnet-14.starknet.io/tcp/53080/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-core-service.apollo-mainnet-15.starknet.io/tcp/53080/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "consensus_manager_config.network_config.port": 53080, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-mainnet-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-mainnet-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-mempool-service.apollo-mainnet-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-mempool-service.apollo-mainnet-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.port": 53200, "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-mainnet.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json index f402226dbfe..b81c7446909 100644 --- a/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/potc_mock/deployment_config_override.json @@ -4,12 +4,14 @@ "consensus_manager_config.context_config.num_validators": 3, "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-potc-mock-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-potc-mock-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-potc-mock-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-potc-mock-10.svc.cluster.local/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-potc-mock-11.svc.cluster.local/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-potc-mock-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "consensus_manager_config.network_config.port": 53080, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-potc-mock-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-potc-mock-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-potc-mock-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-potc-mock-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-potc-mock-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-potc-mock-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.port": 53200, "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.potc-testnet-mock-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/replacer_deployment.json b/crates/apollo_deployments/resources/deployments/replacer_deployment.json index 245e939b11c..218e8a6d658 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_deployment.json +++ b/crates/apollo_deployments/resources/deployments/replacer_deployment.json @@ -4,12 +4,14 @@ "consensus_manager_config.context_config.num_validators": "$$$_CONSENSUS_MANAGER_CONFIG-CONTEXT_CONFIG-NUM_VALIDATORS_$$$", "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", + "consensus_manager_config.network_config.port": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-PORT_$$$", "eth_fee_token_address": "$$$_ETH_FEE_TOKEN_ADDRESS_$$$", "http_server_config.port": "$$$_HTTP_SERVER_CONFIG-PORT_$$$", "l1_provider_config.provider_startup_height_override": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE_$$$", "l1_provider_config.provider_startup_height_override.#is_none": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE-IS_NONE_$$$", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", + "mempool_p2p_config.network_config.port": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-PORT_$$$", "monitoring_endpoint_config.port": "$$$_MONITORING_ENDPOINT_CONFIG-PORT_$$$", "sierra_compiler_config.audited_libfuncs_only": "$$$_SIERRA_COMPILER_CONFIG-AUDITED_LIBFUNCS_ONLY_$$$", "starknet_url": "$$$_STARKNET_URL_$$$", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json index 50ebb642884..f30006a31e3 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_integration/deployment_config_override.json @@ -4,12 +4,14 @@ "consensus_manager_config.context_config.num_validators": 3, "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "consensus_manager_config.network_config.port": 53080, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-integration-10.svc.cluster.local/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-integration-11.svc.cluster.local/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-integration-12.svc.cluster.local/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.port": 53200, "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://feeder.integration-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json index af602503587..289419d7945 100644 --- a/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/sepolia_testnet/deployment_config_override.json @@ -4,12 +4,14 @@ "consensus_manager_config.context_config.num_validators": 3, "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-sepolia-alpha-0.starknet.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-sepolia-alpha-1.starknet.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-sepolia-alpha-2.starknet.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-sepolia-alpha-3.starknet.io/tcp/53080/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-core-service.apollo-sepolia-alpha-10.starknet.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-sepolia-alpha-11.starknet.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-sepolia-alpha-12.starknet.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-core-service.apollo-sepolia-alpha-13.starknet.io/tcp/53080/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-core-service.apollo-sepolia-alpha-14.starknet.io/tcp/53080/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-core-service.apollo-sepolia-alpha-15.starknet.io/tcp/53080/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "consensus_manager_config.network_config.port": 53080, "eth_fee_token_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-sepolia-alpha-0.starknet.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-1.starknet.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-sepolia-alpha-2.starknet.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-sepolia-alpha-3.starknet.io/tcp/53200/p2p/12D3KooWFdTjV6DXVJfQFisTXadCsqGzCbEnJJWzc6mXSPwy9g54,/dns/sequencer-mempool-service.apollo-sepolia-alpha-10.starknet.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-11.starknet.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-sepolia-alpha-12.starknet.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9,/dns/sequencer-mempool-service.apollo-sepolia-alpha-13.starknet.io/tcp/53200/p2p/12D3KooWKZu9RjwQfiRu6VxeCUqZr6fah8BeLjKErDEw1bVDL8X5,/dns/sequencer-mempool-service.apollo-sepolia-alpha-14.starknet.io/tcp/53200/p2p/12D3KooWNEQduhMrckKco8bvmPXZvXuGo5RQNdhxL7nr6rwydJ4V,/dns/sequencer-mempool-service.apollo-sepolia-alpha-15.starknet.io/tcp/53200/p2p/12D3KooWEGF9d7XwCFL9mu6co9z7tiDA4whzVHWuZqHAjXRaYTeS", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.port": 53200, "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": true, "starknet_url": "https://feeder.alpha-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json index 47ecc2618d7..251ee3273a1 100644 --- a/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/stress_test/deployment_config_override.json @@ -4,12 +4,14 @@ "consensus_manager_config.context_config.num_validators": 3, "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-stresstest-dev-0.svc.cluster.local/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-stresstest-dev-1.svc.cluster.local/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-stresstest-dev-2.svc.cluster.local/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "consensus_manager_config.network_config.port": 53080, "eth_fee_token_address": "0x07e813ecf3e7b3e14f07bd2f68cb4a3d12110e3c75ec5a63de3d2dacf1852904", "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-stresstest-dev-0.svc.cluster.local/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-stresstest-dev-1.svc.cluster.local/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-stresstest-dev-2.svc.cluster.local/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.port": 53200, "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "http://feeder-gateway.starknet-0-14-0-stress-test-05:9713/", diff --git a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json index 7e0a66e0326..58e66bf8918 100644 --- a/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/testing/deployment_config_override.json @@ -4,12 +4,14 @@ "consensus_manager_config.context_config.num_validators": 1, "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "consensus_manager_config.network_config.port": 53080, "eth_fee_token_address": "0x1001", "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 1, "l1_provider_config.provider_startup_height_override.#is_none": false, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": true, + "mempool_p2p_config.network_config.port": 53200, "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://integration-sepolia.starknet.io/", diff --git a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json index 7b834a12fb2..22979b61438 100644 --- a/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json +++ b/crates/apollo_deployments/resources/deployments/upgrade_test/deployment_config_override.json @@ -4,12 +4,14 @@ "consensus_manager_config.context_config.num_validators": 3, "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-core-service.apollo-mainnet-test-0.sw-dev.io/tcp/53080/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-core-service.apollo-mainnet-test-1.sw-dev.io/tcp/53080/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-core-service.apollo-mainnet-test-2.sw-dev.io/tcp/53080/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-core-service.apollo-mainnet-test-10.sw-dev.io/tcp/53080/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-core-service.apollo-mainnet-test-11.sw-dev.io/tcp/53080/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-core-service.apollo-mainnet-test-12.sw-dev.io/tcp/53080/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "consensus_manager_config.network_config.port": 53080, "eth_fee_token_address": "0x04475715fa6768670bb310eab072171856c94c1a04fa78be2370513aa2a87dc4", "http_server_config.port": 8080, "l1_provider_config.provider_startup_height_override": 0, "l1_provider_config.provider_startup_height_override.#is_none": true, "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "/dns/sequencer-mempool-service.apollo-mainnet-test-0.sw-dev.io/tcp/53200/p2p/12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5,/dns/sequencer-mempool-service.apollo-mainnet-test-1.sw-dev.io/tcp/53200/p2p/12D3KooWCPzcTZ4ymgyveYaFfZ4bfWsBEh2KxuxM3Rmy7MunqHwe,/dns/sequencer-mempool-service.apollo-mainnet-test-2.sw-dev.io/tcp/53200/p2p/12D3KooWT3eoCYeMPrSNnF1eQHimWFDiqPkna7FUD6XKBw8oPiMp,/dns/sequencer-mempool-service.apollo-mainnet-test-10.sw-dev.io/tcp/53200/p2p/12D3KooWHTbjQtxM3nTF85uadLTbDxX9DXjZzzwdtAogdqxGr9t5,/dns/sequencer-mempool-service.apollo-mainnet-test-11.sw-dev.io/tcp/53200/p2p/12D3KooWJ2JJbbMRt1YrERoMPfU4hwTASZkpVqbfGiyu4d3MGGhs,/dns/sequencer-mempool-service.apollo-mainnet-test-12.sw-dev.io/tcp/53200/p2p/12D3KooWLDHhUjWxXrye37UN23QMEiLEyDt9N6ZtSAsEs2guckW9", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": false, + "mempool_p2p_config.network_config.port": 53200, "monitoring_endpoint_config.port": 8082, "sierra_compiler_config.audited_libfuncs_only": false, "starknet_url": "https://feeder.sn-mainnet-test-upgrade.gateway-proxy.sw-dev.io/", diff --git a/crates/apollo_deployments/src/config_override.rs b/crates/apollo_deployments/src/config_override.rs index aa241096684..42f3f43cda1 100644 --- a/crates/apollo_deployments/src/config_override.rs +++ b/crates/apollo_deployments/src/config_override.rs @@ -162,6 +162,10 @@ pub struct DeploymentConfigOverride { monitoring_endpoint_config_port: u16, #[serde(rename = "state_sync_config.rpc_config.port")] state_sync_config_rpc_config_port: u16, + #[serde(rename = "mempool_p2p_config.network_config.port")] + mempool_p2p_config_network_config_port: u16, + #[serde(rename = "consensus_manager_config.network_config.port")] + consensus_manager_config_network_config_port: u16, } impl DeploymentConfigOverride { @@ -181,6 +185,8 @@ impl DeploymentConfigOverride { http_server_config_port: u16, monitoring_endpoint_config_port: u16, state_sync_config_rpc_config_port: u16, + mempool_p2p_config_network_config_port: u16, + consensus_manager_config_network_config_port: u16, ) -> Self { let ( l1_provider_config_provider_startup_height_override, @@ -206,6 +212,8 @@ impl DeploymentConfigOverride { http_server_config_port, monitoring_endpoint_config_port, state_sync_config_rpc_config_port, + mempool_p2p_config_network_config_port, + consensus_manager_config_network_config_port, } } } diff --git a/crates/apollo_deployments/src/deployment_definitions.rs b/crates/apollo_deployments/src/deployment_definitions.rs index 9b16d23a1fc..b7259dc3d10 100644 --- a/crates/apollo_deployments/src/deployment_definitions.rs +++ b/crates/apollo_deployments/src/deployment_definitions.rs @@ -91,6 +91,8 @@ pub struct DeploymentInputs { pub http_server_port: u16, pub monitoring_endpoint_config_port: u16, pub state_sync_config_rpc_config_port: u16, + pub mempool_p2p_config_network_config_port: u16, + pub consensus_manager_config_network_config_port: u16, } impl DeploymentInputs { diff --git a/crates/apollo_deployments/src/deployment_definitions/testing.rs b/crates/apollo_deployments/src/deployment_definitions/testing.rs index 7b942363de6..7270bd31e68 100644 --- a/crates/apollo_deployments/src/deployment_definitions/testing.rs +++ b/crates/apollo_deployments/src/deployment_definitions/testing.rs @@ -12,7 +12,12 @@ use crate::config_override::{ PeerToPeerBootstrapConfig, }; use crate::deployment::Deployment; -use crate::deployment_definitions::{Environment, StateSyncType}; +use crate::deployment_definitions::{ + Environment, + StateSyncType, + CONSENSUS_P2P_PORT, + MEMPOOL_P2P_PORT, +}; use crate::k8s::IngressParams; use crate::service::NodeType; @@ -43,6 +48,8 @@ fn testing_deployment_config_override() -> DeploymentConfigOverride { HTTP_SERVER_PORT, MONITORING_ENDPOINT_DEFAULT_PORT, RPC_CONFIG_DEFAULT_PORT, + MEMPOOL_P2P_PORT, + CONSENSUS_P2P_PORT, ) } diff --git a/crates/apollo_deployments/src/deployments/hybrid.rs b/crates/apollo_deployments/src/deployments/hybrid.rs index 0060bbdb812..f828d1290a0 100644 --- a/crates/apollo_deployments/src/deployments/hybrid.rs +++ b/crates/apollo_deployments/src/deployments/hybrid.rs @@ -887,6 +887,8 @@ fn hybrid_deployments(inputs: &DeploymentInputs) -> Vec { inputs.http_server_port, inputs.monitoring_endpoint_config_port, inputs.state_sync_config_rpc_config_port, + inputs.mempool_p2p_config_network_config_port, + inputs.consensus_manager_config_network_config_port, ), &inputs.node_namespace_format, &inputs.ingress_domain, From 58d043e63056850f45d749dbef2070003e64b4aa Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Thu, 6 Nov 2025 17:50:29 +0200 Subject: [PATCH 289/313] apollo_integration_tests: add end to end flow args (#10002) --- .../tests/bootstrap_declare.rs | 13 ++--- .../tests/common/mod.rs | 47 ++++++++++++++++--- .../tests/end_to_end_flow_test.rs | 10 ++-- .../tests/test_custom_cairo0_txs.rs | 8 ++-- .../tests/test_custom_cairo1_txs.rs | 8 ++-- .../tests/test_many.rs | 13 ++--- 6 files changed, 64 insertions(+), 35 deletions(-) diff --git a/crates/apollo_integration_tests/tests/bootstrap_declare.rs b/crates/apollo_integration_tests/tests/bootstrap_declare.rs index d922825d497..a65ce104c7f 100644 --- a/crates/apollo_integration_tests/tests/bootstrap_declare.rs +++ b/crates/apollo_integration_tests/tests/bootstrap_declare.rs @@ -2,7 +2,7 @@ use apollo_infra_utils::test_utils::TestIdentifier; use mempool_test_utils::starknet_api_test_utils::generate_bootstrap_declare; use starknet_api::execution_resources::GasAmount; -use crate::common::{end_to_end_flow, test_single_tx, TestScenario}; +use crate::common::{end_to_end_flow, test_single_tx, EndToEndFlowArgs, TestScenario}; mod common; @@ -21,11 +21,12 @@ fn create_bootstrap_declare_scenario() -> Vec { #[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn bootstrap_declare() { end_to_end_flow( - TestIdentifier::EndToEndFlowTestBootstrapDeclare, - create_bootstrap_declare_scenario(), - GasAmount(29000000), - false, - true, + EndToEndFlowArgs::new( + TestIdentifier::EndToEndFlowTestBootstrapDeclare, + create_bootstrap_declare_scenario(), + GasAmount(29000000), + ) + .allow_bootstrap_txs(), ) .await } diff --git a/crates/apollo_integration_tests/tests/common/mod.rs b/crates/apollo_integration_tests/tests/common/mod.rs index 0ffbcc4f5c9..037d2d60e22 100644 --- a/crates/apollo_integration_tests/tests/common/mod.rs +++ b/crates/apollo_integration_tests/tests/common/mod.rs @@ -26,16 +26,49 @@ use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::TransactionHash; use tracing::info; +pub struct EndToEndFlowArgs { + pub test_identifier: TestIdentifier, + pub test_blocks_scenarios: Vec, + pub block_max_capacity_gas: GasAmount, // Used to max both sierra and proving gas. + pub expecting_full_blocks: bool, + pub allow_bootstrap_txs: bool, +} + +impl EndToEndFlowArgs { + pub fn new( + test_identifier: TestIdentifier, + test_blocks_scenarios: Vec, + block_max_capacity_gas: GasAmount, + ) -> Self { + Self { + test_identifier, + test_blocks_scenarios, + block_max_capacity_gas, + expecting_full_blocks: false, + allow_bootstrap_txs: false, + } + } + + pub fn expecting_full_blocks(self) -> Self { + Self { expecting_full_blocks: true, ..self } + } + + pub fn allow_bootstrap_txs(self) -> Self { + Self { allow_bootstrap_txs: true, ..self } + } +} + // Note: run integration/flow tests from separate files in `tests/`, which helps cargo ensure // isolation (prevent cross-contamination of services/resources) and that these tests won't be // parallelized (which won't work with fixed ports). -pub async fn end_to_end_flow( - test_identifier: TestIdentifier, - test_blocks_scenarios: Vec, - block_max_capacity_gas: GasAmount, // Used to max both sierra and proving gas. - expecting_full_blocks: bool, - allow_bootstrap_txs: bool, -) { +pub async fn end_to_end_flow(args: EndToEndFlowArgs) { + let EndToEndFlowArgs { + test_identifier, + test_blocks_scenarios, + block_max_capacity_gas, + expecting_full_blocks, + allow_bootstrap_txs, + } = args; configure_tracing().await; let mut tx_generator = create_flow_test_tx_generator(); diff --git a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs index c1ebba1efa8..e2b974310c9 100644 --- a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs +++ b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs @@ -11,7 +11,7 @@ use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerato use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::{L1HandlerTransaction, TransactionHash}; -use crate::common::{end_to_end_flow, test_single_tx, TestScenario}; +use crate::common::{end_to_end_flow, test_single_tx, EndToEndFlowArgs, TestScenario}; mod common; @@ -19,17 +19,15 @@ mod common; /// Number of threads is 3 = Num of sequencer + 1 for the test thread. #[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn test_end_to_end_flow() { - end_to_end_flow( + end_to_end_flow(EndToEndFlowArgs::new( TestIdentifier::EndToEndFlowTest, create_test_scenarios(), BouncerWeights::default().proving_gas, - false, - false, - ) + )) .await } -pub fn create_test_scenarios() -> Vec { +fn create_test_scenarios() -> Vec { vec![ // This block should be the first to be tested, as the addition of L1 handler transaction // does not work smoothly with the current architecture of the test. diff --git a/crates/apollo_integration_tests/tests/test_custom_cairo0_txs.rs b/crates/apollo_integration_tests/tests/test_custom_cairo0_txs.rs index 7fc6e215992..08afd2a3144 100644 --- a/crates/apollo_integration_tests/tests/test_custom_cairo0_txs.rs +++ b/crates/apollo_integration_tests/tests/test_custom_cairo0_txs.rs @@ -14,7 +14,7 @@ use starknet_api::test_utils::invoke::rpc_invoke_tx; use starknet_api::transaction::fields::{ContractAddressSalt, TransactionSignature}; use starknet_api::{calldata, felt}; -use crate::common::{end_to_end_flow, validate_tx_count, TestScenario}; +use crate::common::{end_to_end_flow, validate_tx_count, EndToEndFlowArgs, TestScenario}; mod common; @@ -23,13 +23,11 @@ const CUSTOM_CAIRO_0_INVOKE_TX_COUNT: usize = 9; /// The test uses 3 threads: 1 for the test's main thread and 2 for the sequencers. #[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn custom_cairo0_txs() { - end_to_end_flow( + end_to_end_flow(EndToEndFlowArgs::new( TestIdentifier::EndToEndFlowTestCustomCairo0Txs, create_custom_cairo0_txs_scenario(), GasAmount(110000000), - false, - false, - ) + )) .await } diff --git a/crates/apollo_integration_tests/tests/test_custom_cairo1_txs.rs b/crates/apollo_integration_tests/tests/test_custom_cairo1_txs.rs index 7247ec74fb1..b83a21fb9bd 100644 --- a/crates/apollo_integration_tests/tests/test_custom_cairo1_txs.rs +++ b/crates/apollo_integration_tests/tests/test_custom_cairo1_txs.rs @@ -19,7 +19,7 @@ use starknet_api::transaction::TransactionVersion; use starknet_api::{calldata, felt}; use starknet_types_core::felt::Felt; -use crate::common::{end_to_end_flow, validate_tx_count, TestScenario}; +use crate::common::{end_to_end_flow, validate_tx_count, EndToEndFlowArgs, TestScenario}; mod common; @@ -29,13 +29,11 @@ const CUSTOM_INVOKE_TX_COUNT: usize = 16; /// Number of threads is 3 = Num of sequencer + 1 for the test thread. #[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn custom_cairo1_txs() { - end_to_end_flow( + end_to_end_flow(EndToEndFlowArgs::new( TestIdentifier::EndToEndFlowTestCustomSyscallInvokeTxs, create_custom_cairo1_txs_scenario(), BouncerWeights::default().proving_gas, - false, - false, - ) + )) .await } diff --git a/crates/apollo_integration_tests/tests/test_many.rs b/crates/apollo_integration_tests/tests/test_many.rs index 24612161ef2..989288d8344 100644 --- a/crates/apollo_integration_tests/tests/test_many.rs +++ b/crates/apollo_integration_tests/tests/test_many.rs @@ -5,7 +5,7 @@ use starknet_api::execution_resources::GasAmount; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; -use crate::common::{end_to_end_flow, TestScenario}; +use crate::common::{end_to_end_flow, EndToEndFlowArgs, TestScenario}; mod common; @@ -14,11 +14,12 @@ mod common; #[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn many_txs_fill_at_least_one_block() { end_to_end_flow( - TestIdentifier::EndToEndFlowTestManyTxs, - create_many_txs_scenario(), - GasAmount(40000000), - true, - false, + EndToEndFlowArgs::new( + TestIdentifier::EndToEndFlowTestManyTxs, + create_many_txs_scenario(), + GasAmount(40000000), + ) + .expecting_full_blocks(), ) .await } From b664920d8bd9debd8f5fb3ae8fe638cbcae78086 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:15:29 +0200 Subject: [PATCH 290/313] apollo_deployments: use replacers for multiaddr config values (#9999) * apollo_deployments: move p2p ports to deployment overrides * apollo_deployments: use replacers for multiaddr config values --- .../deployments/replacer_deployment.json | 4 +- .../deployments/replacer_instance.json | 4 +- crates/apollo_deployments/src/replacers.rs | 43 ++++++++++++++++++- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/crates/apollo_deployments/resources/deployments/replacer_deployment.json b/crates/apollo_deployments/resources/deployments/replacer_deployment.json index 218e8a6d658..76530a6eaca 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_deployment.json +++ b/crates/apollo_deployments/resources/deployments/replacer_deployment.json @@ -2,14 +2,14 @@ "base_layer_config.starknet_contract_address": "$$$_BASE_LAYER_CONFIG-STARKNET_CONTRACT_ADDRESS_$$$", "chain_id": "$$$_CHAIN_ID_$$$", "consensus_manager_config.context_config.num_validators": "$$$_CONSENSUS_MANAGER_CONFIG-CONTEXT_CONFIG-NUM_VALIDATORS_$$$", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": [], "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", "consensus_manager_config.network_config.port": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-PORT_$$$", "eth_fee_token_address": "$$$_ETH_FEE_TOKEN_ADDRESS_$$$", "http_server_config.port": "$$$_HTTP_SERVER_CONFIG-PORT_$$$", "l1_provider_config.provider_startup_height_override": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE_$$$", "l1_provider_config.provider_startup_height_override.#is_none": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE-IS_NONE_$$$", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": [], "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", "mempool_p2p_config.network_config.port": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-PORT_$$$", "monitoring_endpoint_config.port": "$$$_MONITORING_ENDPOINT_CONFIG-PORT_$$$", diff --git a/crates/apollo_deployments/resources/deployments/replacer_instance.json b/crates/apollo_deployments/resources/deployments/replacer_instance.json index 93e4ca688d2..cefb64f5e01 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_instance.json +++ b/crates/apollo_deployments/resources/deployments/replacer_instance.json @@ -1,7 +1,7 @@ { - "consensus_manager_config.network_config.advertised_multiaddr": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR_$$$", + "consensus_manager_config.network_config.advertised_multiaddr": [], "consensus_manager_config.network_config.advertised_multiaddr.#is_none": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR-IS_NONE_$$$", - "mempool_p2p_config.network_config.advertised_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR_$$$", + "mempool_p2p_config.network_config.advertised_multiaddr": [], "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR-IS_NONE_$$$", "validator_id": "$$$_VALIDATOR_ID_$$$" } diff --git a/crates/apollo_deployments/src/replacers.rs b/crates/apollo_deployments/src/replacers.rs index 0e2e3edcdb8..7d73f14073d 100644 --- a/crates/apollo_deployments/src/replacers.rs +++ b/crates/apollo_deployments/src/replacers.rs @@ -1,8 +1,16 @@ use apollo_infra_utils::template::Template; use serde_json::Value; - const REPLACER_FORMAT: &str = "$$$_{}_$$$"; +use libp2p::Multiaddr; + +const MULTIADDR_KEYS: [&str; 4] = [ + "consensus_manager_config.network_config.bootstrap_peer_multiaddr", + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr", + "consensus_manager_config.network_config.advertised_multiaddr", + "mempool_p2p_config.network_config.advertised_multiaddr", +]; + pub(crate) fn insert_replacer_annotations(mut json: Value, pred: F) -> Value where F: Fn(&str, &Value) -> bool, @@ -19,7 +27,22 @@ where }; if should_replace { - map.insert(key.clone(), Value::String(format_key(key.clone()))); + if MULTIADDR_KEYS.contains(&key.as_str()) { + let multiaddrs = extract_multiaddrs(map, &key); + if let Some(multiaddrs) = multiaddrs { + map.insert( + key.clone(), + Value::Array( + multiaddrs + .into_iter() + .map(|addr| Value::String(addr.to_string())) + .collect(), + ), + ); + } + } else { + map.insert(key.clone(), Value::String(format_key(key.clone()))); + } } } @@ -29,3 +52,19 @@ where fn format_key(key: String) -> String { Template::new(REPLACER_FORMAT).format(&[&key]).to_uppercase().replace('.', "-").replace('#', "") } + +fn parse_multiaddrs(value: &str) -> Vec { + value + .split(',') + .map(str::trim) + .filter(|s| !s.is_empty()) + .filter_map(|s| s.parse::().ok()) // skip invalid addresses + .collect() +} + +pub fn extract_multiaddrs( + json: &serde_json::Map, + key: &str, +) -> Option> { + json.get(key)?.as_str().map(parse_multiaddrs) +} From d6c277b583c3a3565ffef2fb96872cd7cd58eb46 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 9 Nov 2025 10:59:22 +0200 Subject: [PATCH 291/313] scripts: create a script for simply waiting on the proposal success of a node (#9985) --- .../wait_for_cores_to_succesfully_propose.py | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100755 scripts/prod/wait_for_cores_to_succesfully_propose.py diff --git a/scripts/prod/wait_for_cores_to_succesfully_propose.py b/scripts/prod/wait_for_cores_to_succesfully_propose.py new file mode 100755 index 00000000000..fe56230ec1f --- /dev/null +++ b/scripts/prod/wait_for_cores_to_succesfully_propose.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +import sys + +from common_lib import ( + NamespaceAndInstructionArgs, + RestartStrategy, + Service, + print_error, + wait_until_y_or_n, +) +from metrics_lib import MetricConditionGater +from restarter_lib import WaitOnMetricRestarter +from update_config_and_restart_nodes_lib import ( + ApolloArgsParserBuilder, + update_config_and_restart_nodes, +) + + +class WaitForProposalIncrease: + def __init__(self): + self.last_proposal_count = None + + def check_if_proposal_count_increased(self, proposal_count: int) -> bool: + if self.last_proposal_count is None: + # First time we're checking, so we don't know if the proposal count has increased. + # Save the current count and on the next increase we'll know we had a successful proposal. + self.last_proposal_count = proposal_count + + if proposal_count > self.last_proposal_count: + # Set the last proposal count to None so that next time we check we know we have to + # again first get the current value. + self.last_proposal_count = None + return True + + return False + + +def main(): + args_builder = ApolloArgsParserBuilder( + "Wait for each Core to successfully propose a block", + "python wait_for_cores_to_succesfully_propose.py -n apollo-sepolia-integration -m 3 -t all_at_once", + include_restart_strategy=False, + ) + args = args_builder.build() + + namespace_list = NamespaceAndInstructionArgs.get_namespace_list_from_args(args) + context_list = NamespaceAndInstructionArgs.get_context_list_from_args(args) + instructions = ["Checking node proposed successfully."] * len(namespace_list) + + namespace_and_instruction_args = NamespaceAndInstructionArgs( + namespace_list, + context_list, + instructions, + ) + + if not wait_until_y_or_n( + "Please update and or restart the first core as needed and press 'y' when ready to proceed." + ): + print_error("Operation cancelled by user") + sys.exit(1) + + proposal_increase_checker = WaitForProposalIncrease() + update_config_and_restart_nodes( + None, + namespace_and_instruction_args, + Service.Core, + WaitOnMetricRestarter( + namespace_and_instruction_args, + Service.Core, + [ + MetricConditionGater.Metric( + "consensus_decisions_reached_as_proposer", + proposal_increase_checker.check_if_proposal_count_increased, + ) + ], + 8082, + RestartStrategy.NO_RESTART, + ), + ) + + +if __name__ == "__main__": + main() From 4aadbc8875e28af3257d86aab454adc116940666 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 9 Nov 2025 12:05:27 +0200 Subject: [PATCH 292/313] scripts: fix bugs in revert script (#10006) --- scripts/prod/set_node_revert_mode.py | 41 ++++++++-------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/scripts/prod/set_node_revert_mode.py b/scripts/prod/set_node_revert_mode.py index 7f15a8af612..e7465d1021e 100755 --- a/scripts/prod/set_node_revert_mode.py +++ b/scripts/prod/set_node_revert_mode.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import sys from typing import Optional import urllib.parse @@ -10,7 +9,6 @@ RestartStrategy, Service, print_colored, - print_error, ) from metrics_lib import MetricConditionGater from restarter_lib import ServiceRestarter, WaitOnMetricRestarter @@ -86,7 +84,7 @@ def enable_revert_mode( ) restarter = WaitOnMetricRestarter( namespace_and_instruction_args, - Service.Mempool, + Service.Core, [ MetricConditionGater.Metric( "apollo_consensus_reverted_batcher_up_to_and_including", @@ -165,14 +163,16 @@ def main(): "--disable-revert-only", action="store_true", help="Disable revert mode" ) - args_builder.add_argument( + block_revert_args_group = args_builder.parser.add_mutually_exclusive_group(required=True) + + block_revert_args_group.add_argument( "-b", "--revert-up-to-block", type=int, help="Block number up to which to revert (inclusive). Must be a positive integer.", ) - args_builder.add_argument( + block_revert_args_group.add_argument( "-f", "--feeder-url", type=str, @@ -188,41 +188,24 @@ def main(): args = args_builder.build() - should_revert = not args.disable_revert_only - if should_revert: - if args.feeder_url is None and args.revert_up_to_block is None: - print_error( - "Error: Either --feeder-url or --revert_up_to_block (-b) are required when reverting is requested." - ) - sys.exit(1) - if args.feeder_url is not None and args.revert_up_to_block is not None: - print_error("Error: Cannot specify both --feeder-url and --revert_up_to_block (-b).") - sys.exit(1) - - if args.disable_revert_only: - if args.feeder_url is not None: - print_error("Error: --feeder-url cannot be set when using --disable-revert-only") - sys.exit(1) - if args.revert_up_to_block is not None: - print_error("Error: --revert-up-to-block (-b) cannot be set when disabling revert.") - sys.exit(1) - namespace_list = NamespaceAndInstructionArgs.get_namespace_list_from_args(args) context_list = NamespaceAndInstructionArgs.get_context_list_from_args(args) + should_revert = not args.disable_revert_only should_disable_revert = not args.revert_only + revert_up_to_block = ( + args.revert_up_to_block + if args.revert_up_to_block is not None + else get_current_block_number(args.feeder_url) + ) if should_revert: - revert_up_to_block = ( - args.revert_up_to_block - if args.revert_up_to_block is not None - else get_current_block_number(args.feeder_url) - ) enable_revert_mode( namespace_list, context_list, args.project_name, revert_up_to_block, ) + if should_disable_revert: disable_revert_mode( namespace_list, From 8ef1ab4cc6cb7b90e4058e0b40d1be1430c98f73 Mon Sep 17 00:00:00 2001 From: guyf-starkware Date: Sun, 9 Nov 2025 13:18:35 +0200 Subject: [PATCH 293/313] scripts: if wait for pod failed print an explicit message and not only the underlying errors (#10025) --- scripts/prod/restarter_lib.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/prod/restarter_lib.py b/scripts/prod/restarter_lib.py index 170cf87edb7..e8c7a351a43 100644 --- a/scripts/prod/restarter_lib.py +++ b/scripts/prod/restarter_lib.py @@ -193,7 +193,8 @@ def __init__( super().__init__(namespace_and_instruction_args, service, check_function, base_restarter) def _check_between_each_restart(self, instance_index: int) -> bool: - self._wait_for_pod_to_satisfy_condition(instance_index) + if not self._wait_for_pod_to_satisfy_condition(instance_index): + print_error(f"Failed waiting for condition(s) for Pod {instance_index}.") if instance_index == self.namespace_and_instruction_args.size() - 1: # Last instance, no need to prompt the user about the next restart. return True @@ -206,7 +207,8 @@ def _check_all_only_after_last_restart(self, instance_index: int) -> bool: # After the last node has been restarted, wait for all pods to satisfy the condition. for instance_index in range(self.namespace_and_instruction_args.size()): - self._wait_for_pod_to_satisfy_condition(instance_index) + if not self._wait_for_pod_to_satisfy_condition(instance_index): + print_error(f"Failed waiting for condition(s) for Pod {instance_index}.") return True def _wait_for_pod_to_satisfy_condition(self, instance_index: int) -> bool: From 4e917ddc623eb596f980f238fcffef9e66052b5e Mon Sep 17 00:00:00 2001 From: victorkstarkware <160594433+victorkstarkware@users.noreply.github.com> Date: Sun, 9 Nov 2025 13:37:33 +0200 Subject: [PATCH 294/313] apollo_integration_tests: replace vec of configs with indexmap (#9834) * apollo_integration_tests: replace vec of configs with indexmap * apollo_integration_tests: replace vec of configs with indexmap * apollo_integration_tests: replace vec of configs with indexmap --- .../src/deployment_definitions.rs | 2 +- crates/apollo_deployments/src/service.rs | 2 +- .../src/integration_test_manager.rs | 67 ++++++++++++------- .../src/node_component_configs.rs | 15 +++-- 4 files changed, 56 insertions(+), 30 deletions(-) diff --git a/crates/apollo_deployments/src/deployment_definitions.rs b/crates/apollo_deployments/src/deployment_definitions.rs index b7259dc3d10..600880fe953 100644 --- a/crates/apollo_deployments/src/deployment_definitions.rs +++ b/crates/apollo_deployments/src/deployment_definitions.rs @@ -274,7 +274,7 @@ impl ServicePort { } } -#[derive(Clone, Debug, Display, Serialize, PartialEq, Eq, PartialOrd, Ord, EnumIter)] +#[derive(Hash, Clone, Debug, Display, Serialize, PartialEq, Eq, PartialOrd, Ord, EnumIter)] pub enum ComponentConfigInService { BaseLayer, Batcher, diff --git a/crates/apollo_deployments/src/service.rs b/crates/apollo_deployments/src/service.rs index 19a71bf7cec..f2daecd07b7 100644 --- a/crates/apollo_deployments/src/service.rs +++ b/crates/apollo_deployments/src/service.rs @@ -297,7 +297,7 @@ impl NodeService { .to_string() } - fn get_components_in_service(&self) -> BTreeSet { + pub fn get_components_in_service(&self) -> BTreeSet { self.as_inner().get_components_in_service() } diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index c4739e44ca9..0948535ea0e 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::future::Future; use std::net::{Ipv4Addr, SocketAddr}; use std::panic; @@ -6,6 +6,7 @@ use std::path::PathBuf; use std::time::Duration; use apollo_base_layer_tests::anvil_base_layer::AnvilBaseLayer; +use apollo_deployments::deployment_definitions::ComponentConfigInService; use apollo_http_server::test_utils::HttpTestClient; use apollo_http_server_config::config::HttpServerConfig; use apollo_infra_utils::dumping::serialize_to_file; @@ -25,6 +26,7 @@ use apollo_test_utils::send_request; use blockifier::context::ChainInfo; use futures::future::join_all; use futures::TryFutureExt; +use indexmap::IndexMap; use mempool_test_utils::starknet_api_test_utils::{ contract_class, AccountId, @@ -89,10 +91,13 @@ pub const MONITORING_PORT_ARG: &str = "monitoring-port"; const ALLOW_BOOTSTRAP_TXS: bool = false; pub struct NodeSetup { - executables: Vec, + // TODO(victork): remove indices. + executables: IndexMap, ExecutableSetup>, batcher_index: usize, + #[allow(dead_code)] http_server_index: usize, state_sync_index: usize, + #[allow(dead_code)] consensus_manager_index: usize, // Client for adding transactions to the sequencer node. @@ -107,7 +112,7 @@ pub struct NodeSetup { impl NodeSetup { pub fn new( - executables: Vec, + executables: IndexMap, ExecutableSetup>, batcher_index: usize, http_server_index: usize, state_sync_index: usize, @@ -156,8 +161,12 @@ impl NodeSetup { &self.get_consensus_manager().monitoring_client } - pub fn get_executables(&self) -> &Vec { - &self.executables + pub fn get_executables(&self) -> impl ExactSizeIterator { + self.executables.values() + } + + fn get_executables_mut(&mut self) -> impl ExactSizeIterator { + self.executables.values_mut() } pub fn set_executable_config_path( @@ -165,8 +174,8 @@ impl NodeSetup { index: usize, new_path: PathBuf, ) -> Result<(), &'static str> { - if let Some(exec) = self.executables.get_mut(index) { - exec.node_config_path = new_path; + if let Some(exec) = self.executables.get_index_mut(index) { + exec.1.node_config_path = new_path; Ok(()) } else { panic!("Invalid executable index") @@ -181,26 +190,35 @@ impl NodeSetup { serialize_to_file(&json_data, path); } + fn get_executable_by_component(&self, component: ComponentConfigInService) -> &ExecutableSetup { + self.executables + .iter() + .find(|(components, _)| components.contains(&component)) + .map(|(_, executable)| executable) + .unwrap_or_else(|| { + panic!("Expected at least one executable with component {:?}", component) + }) + } + pub fn get_batcher(&self) -> &ExecutableSetup { - &self.executables[self.batcher_index] + self.get_executable_by_component(ComponentConfigInService::Batcher) } pub fn get_http_server(&self) -> &ExecutableSetup { - &self.executables[self.http_server_index] + self.get_executable_by_component(ComponentConfigInService::HttpServer) } pub fn get_state_sync(&self) -> &ExecutableSetup { - &self.executables[self.state_sync_index] + self.get_executable_by_component(ComponentConfigInService::StateSync) } pub fn get_consensus_manager(&self) -> &ExecutableSetup { - &self.executables[self.consensus_manager_index] + self.get_executable_by_component(ComponentConfigInService::Consensus) } pub fn run(self) -> RunningNode { let executable_handles = self .get_executables() - .iter() .map(|executable| { info!("Running {}.", executable.node_execution_id); spawn_run_node( @@ -213,11 +231,13 @@ impl NodeSetup { RunningNode { node_setup: self, executable_handles } } pub fn get_node_index(&self) -> Option { - self.executables.first().map(|executable| executable.node_execution_id.get_node_index()) + self.get_executables() + .next() + .map(|executable| executable.node_execution_id.get_node_index()) } pub fn get_l1_gas_price_scraper_config(&self) -> L1GasPriceScraperConfig { - for executable_setup in &self.executables { + for executable_setup in self.get_executables() { if let Some(l1_gas_price_scraper_config) = &executable_setup.get_config().l1_gas_price_scraper_config { @@ -236,7 +256,7 @@ pub struct RunningNode { impl RunningNode { async fn await_alive(&self, interval: u64, max_attempts: usize) { self.propagate_executable_panic(); - let await_alive_tasks = self.node_setup.executables.iter().map(|executable| { + let await_alive_tasks = self.node_setup.get_executables().map(|executable| { let result = executable.monitoring_client.await_alive(interval, max_attempts); result.unwrap_or_else(|_| { panic!("Executable {:?} should be alive.", executable.node_execution_id) @@ -364,7 +384,7 @@ impl IntegrationTestManager { .idle_nodes .get_mut(&node_index) .unwrap_or_else(|| panic!("Node {node_index} does not exist in idle_nodes.")); - node_setup.executables.iter_mut().for_each(|executable| { + node_setup.get_executables_mut().for_each(|executable| { info!("Modifying {} config.", executable.node_execution_id); executable.modify_config(modify_config_fn); }); @@ -385,7 +405,7 @@ impl IntegrationTestManager { .idle_nodes .get_mut(&node_index) .unwrap_or_else(|| panic!("Node {node_index} does not exist in idle_nodes.")); - node_setup.executables.iter_mut().for_each(|executable| { + node_setup.get_executables_mut().for_each(|executable| { info!("Modifying {} config pointers.", executable.node_execution_id); executable.modify_config_pointers(modify_config_pointers_fn); }); @@ -515,7 +535,7 @@ impl IntegrationTestManager { .map(|node| &(node.node_setup)) .unwrap_or_else(|| self.idle_nodes.get(&0).expect("Node 0 doesn't exist")); - for executable_setup in &node_0_setup.executables { + for executable_setup in node_0_setup.get_executables() { if let Some(http_server_config) = &executable_setup.get_config().http_server_config { let localhost_url = format!("http://{}", Ipv4Addr::LOCALHOST); let monitoring_port = executable_setup @@ -593,7 +613,7 @@ impl IntegrationTestManager { .or_else(|| self.running_nodes.values().next().map(|node| &node.node_setup)) .expect("There should be at least one running or idle node"); - for executable_setup in &node_setup.executables { + for executable_setup in node_setup.get_executables() { if let Some(state_sync_config) = executable_setup.get_config().clone().state_sync_config { return SocketAddr::from(( @@ -779,7 +799,7 @@ impl IntegrationTestManager { .or_else(|| self.running_nodes.values().next().map(|node| &node.node_setup)) .expect("There should be at least one running or idle node"); - for executable_setup in &node_setup.executables { + for executable_setup in node_setup.get_executables() { if let Some(batcher_config) = &executable_setup.get_config().batcher_config { return batcher_config.block_builder_config.chain_info.chain_id.clone(); } @@ -903,7 +923,7 @@ async fn get_sequencer_setup_configs( // Create nodes. for (node_index, node_component_config) in node_component_configs.into_iter().enumerate() { - let mut executables = Vec::new(); + let mut executables = IndexMap::new(); let batcher_index = node_component_config.get_batcher_index(); let http_server_index = node_component_config.get_http_server_index(); let state_sync_index = node_component_config.get_state_sync_index(); @@ -934,7 +954,7 @@ async fn get_sequencer_setup_configs( ); // Per node, create the executables constituting it. - for (executable_index, executable_component_config) in + for (executable_index, (component_set, executable_component_config)) in node_component_config.into_iter().enumerate() { // Set a monitoring endpoint for each executable. @@ -971,7 +991,8 @@ async fn get_sequencer_setup_configs( let exec_config_path = custom_paths.as_ref().and_then(|paths| paths.get_config_path(&node_execution_id)); - executables.push( + executables.insert( + component_set, ExecutableSetup::new(base_app_config, node_execution_id, exec_config_path).await, ); } diff --git a/crates/apollo_integration_tests/src/node_component_configs.rs b/crates/apollo_integration_tests/src/node_component_configs.rs index 72bc914bf90..c9d10be77f8 100644 --- a/crates/apollo_integration_tests/src/node_component_configs.rs +++ b/crates/apollo_integration_tests/src/node_component_configs.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeSet; + use apollo_deployments::deployment_definitions::ComponentConfigInService; use apollo_deployments::deployments::distributed::DISTRIBUTED_NODE_REQUIRED_PORTS_NUM; use apollo_deployments::deployments::hybrid::HYBRID_NODE_REQUIRED_PORTS_NUM; @@ -8,8 +10,8 @@ use indexmap::IndexMap; /// Holds the component configs for a set of sequencers, composing a single sequencer node. pub struct NodeComponentConfigs { - // TODO(Tsabary): transition to using the map instead of a vector and indices. - component_configs: Vec, + // TODO(victork): remove indices. + component_configs: IndexMap, ComponentConfig>, batcher_index: usize, http_server_index: usize, state_sync_index: usize, @@ -59,7 +61,10 @@ impl NodeComponentConfigs { get_component_index(&component_configs, node_type, ComponentConfigInService::Consensus); Self { - component_configs: component_configs.into_values().collect(), + component_configs: component_configs + .into_iter() + .map(|(service, config)| (service.get_components_in_service(), config)) + .collect(), batcher_index, http_server_index, state_sync_index, @@ -98,11 +103,11 @@ impl NodeComponentConfigs { } impl IntoIterator for NodeComponentConfigs { - type Item = ComponentConfig; + type Item = (BTreeSet, ComponentConfig); type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.component_configs.into_iter() + self.component_configs.into_iter().collect::>().into_iter() } } From fc6f48753d1b3d36bfc5b36fb806d6f1e30691ad Mon Sep 17 00:00:00 2001 From: einat-starkware Date: Sun, 9 Nov 2025 15:11:44 +0200 Subject: [PATCH 295/313] starknet_os: decrypt state diff from blobs (#9910) --- .../state_diff_encryption/utils.rs | 37 ++++++++ .../state_diff_encryption/utils_test.rs | 91 +++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/utils.rs b/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/utils.rs index 623471ebbf5..1854bc3966f 100644 --- a/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/utils.rs +++ b/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/utils.rs @@ -3,6 +3,10 @@ use digest::Digest; use starknet_types_core::curve::AffinePoint; use starknet_types_core::felt::Felt; +use crate::hints::hint_implementation::kzg::utils::{decode_blobs, FftError}; +use crate::io::os_output::OsOutputError; +use crate::io::os_output_types::{PartialOsStateDiff, TryFromOutputIter}; + #[cfg(test)] #[path = "utils_test.rs"] mod utils_test; @@ -146,3 +150,36 @@ pub fn naive_encode_felts_to_u32s(felts: Vec) -> Vec { } unpacked_u32s } + +#[derive(Debug, thiserror::Error)] +pub enum DecryptionError { + #[error(transparent)] + Fft(#[from] FftError), + #[error(transparent)] + Parsing(#[from] OsOutputError), +} + +// TODO(Einat): Test this function in the OS tests. +#[allow(dead_code)] +pub fn decrypt_state_diff_from_blobs( + blobs: Vec>, + private_key: Felt, + committee_index: usize, +) -> Result { + let decoded_blobs = decode_blobs(blobs)?; + + let n_keys: usize = decoded_blobs[0].try_into().expect("n_keys should fit in usize"); + let sn_public_key = decoded_blobs[committee_index + 1]; + let encrypted_symmetric_key = decoded_blobs[n_keys + committee_index + 1]; + + // Decrypt the state diff (may include trailing zeros from blob padding). + let decrypted_da = decrypt_state_diff( + private_key, + sn_public_key, + encrypted_symmetric_key, + &decoded_blobs[2 * n_keys + 1..], + ); + + // The parser will consume only what it needs and ignore trailing padding. + Ok(PartialOsStateDiff::try_from_output_iter(&mut decrypted_da.into_iter())?) +} diff --git a/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/utils_test.rs b/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/utils_test.rs index 315b97fd027..18e464f9a2f 100644 --- a/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/utils_test.rs +++ b/crates/starknet_os/src/hints/hint_implementation/state_diff_encryption/utils_test.rs @@ -1,13 +1,20 @@ +use ark_bls12_381::Fr; use rand::Rng; use starknet_types_core::curve::AffinePoint; use starknet_types_core::felt::Felt; +use crate::hints::hint_implementation::kzg::utils::{ + polynomial_coefficients_to_blob, + FIELD_ELEMENTS_PER_BLOB, +}; use crate::hints::hint_implementation::state_diff_encryption::utils::{ compute_starknet_public_keys, decrypt_state_diff, + decrypt_state_diff_from_blobs, encrypt_state_diff, encrypt_symmetric_key, }; +use crate::io::os_output_types::{PartialOsStateDiff, TryFromOutputIter}; #[test] fn test_encrypt_decrypt_roundtrip_random() { @@ -59,3 +66,87 @@ fn test_encrypt_decrypt_roundtrip_random() { assert_eq!(decrypted, state_diff); } } + +#[test] +fn test_decrypt_state_diff_from_blobs() { + let mut rng = rand::thread_rng(); + + // Unencrypted DA segment of output with `full_output=false` and `use_kzg_da=true`. + let da_segment = vec![ + Felt::from_hex("0x60001400000000010000000001000050002100000").unwrap(), + Felt::from_hex("0x1275130f95dda36bcbb6e9d28796c1d7e10b6e9fd5ed083e0ede4b12f613528") + .unwrap(), + Felt::from_hex("0x3291859abec6454596859fa7f51688b15d4b94d181eab1b0f6c44f070cee406") + .unwrap(), + Felt::from_hex("0x723973208639b7839ce298f7ffea61e3f9533872defd7abdb91023db4658812") + .unwrap(), + Felt::from_hex("0x7368e36c028305eeec3e9c87373deafc49e7fedc20692e8dcfb16f7d409ddf5") + .unwrap(), + Felt::from_hex("0x2833c37e53489206582153747f19c4385079c6a72d8252483c1b6e043ab8b5d") + .unwrap(), + Felt::from_hex("0x1ed09bead87c025bb625d13b19800").unwrap(), + Felt::from_hex("0x11d22c06ec4e6800").unwrap(), + Felt::from_hex("0x112022c046808f011c0240000001200041f4c3e487d20f9000280008005").unwrap(), + Felt::from_hex("0xc2001c801008c").unwrap(), + Felt::from_hex("0x2d756ff").unwrap(), + Felt::from_hex("0x38e90493bb0a8c19447d3f6").unwrap(), + ]; + + let original_state_diff = + PartialOsStateDiff::try_from_output_iter(&mut da_segment.clone().into_iter()) + .expect("Failed to parse DA segment into PartialOsStateDiff"); + + // Random number of keys. + let n_keys: usize = rng.gen_range(1..=5); + + // Generate private keys and corresponding public key x-coordinates. + let mut private_keys: Vec = Vec::with_capacity(n_keys); + let mut public_keys: Vec = Vec::with_capacity(n_keys); + for _ in 0..n_keys { + let private_key = Felt::from(rng.gen_range(1..=1_000_000)); + let public_key_x = (&AffinePoint::generator() * private_key).x(); + private_keys.push(private_key); + public_keys.push(public_key_x); + } + + // Generate SN private keys. + let mut sn_private_keys: Vec = Vec::with_capacity(n_keys); + for _ in 0..n_keys { + let sn_priv_scalar: u64 = rng.gen_range(1..=1_000_000); + sn_private_keys.push(Felt::from(sn_priv_scalar)); + } + + // Random symmetric key. + let symmetric_key = Felt::from_bytes_be(&rng.gen::<[u8; 32]>()); + + // Encrypt the DA segment + let encrypted_state_diff = encrypt_state_diff(symmetric_key, &da_segment); + let encrypted_symmetric_key = + encrypt_symmetric_key(&sn_private_keys, &public_keys, symmetric_key); + let sn_public_keys = compute_starknet_public_keys(&sn_private_keys); + + // Build full encrypted DA segment. + let full_da_segment: Vec = [Felt::from(n_keys)] + .into_iter() + .chain(sn_public_keys) + .chain(encrypted_symmetric_key) + .chain(encrypted_state_diff) + .collect(); + + // Convert to blobs. + let da_segment_fr: Vec = + full_da_segment.into_iter().map(|felt| Fr::from(felt.to_biguint())).collect(); + + let blobs: Vec> = da_segment_fr + .chunks(FIELD_ELEMENTS_PER_BLOB) + .map(|chunk| polynomial_coefficients_to_blob(chunk.to_vec()).unwrap()) + .collect(); + + let decrypted_state_diff = decrypt_state_diff_from_blobs(blobs, private_keys[0], 0) + .expect("Failed to decrypt and parse state diff from blobs"); + + assert_eq!( + decrypted_state_diff, original_state_diff, + "Decrypted state diff should match original" + ); +} From 07f1c390ef8f58454cb1c84b14051e02bb5adb67 Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Sun, 9 Nov 2025 15:17:55 +0200 Subject: [PATCH 296/313] apollo_l1_provider: build infrastructure for scraper+provider flow test (#9868) --- crates/apollo_l1_provider/tests/flow_tests.rs | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 crates/apollo_l1_provider/tests/flow_tests.rs diff --git a/crates/apollo_l1_provider/tests/flow_tests.rs b/crates/apollo_l1_provider/tests/flow_tests.rs new file mode 100644 index 00000000000..21bd5c171b4 --- /dev/null +++ b/crates/apollo_l1_provider/tests/flow_tests.rs @@ -0,0 +1,72 @@ +use std::sync::Arc; + +use apollo_batcher_types::communication::MockBatcherClient; +use apollo_infra::component_client::LocalComponentClient; +use apollo_infra::component_definitions::RequestWrapper; +use apollo_infra::component_server::{LocalComponentServer, LocalServerConfig}; +use apollo_l1_provider::l1_provider::L1ProviderBuilder; +use apollo_l1_provider::l1_scraper::L1Scraper; +use apollo_l1_provider::metrics::L1_PROVIDER_INFRA_METRICS; +use apollo_l1_provider::L1ProviderConfig; +use apollo_l1_provider_types::{L1ProviderRequest, L1ProviderResponse, MockL1ProviderClient}; +use apollo_l1_scraper_config::config::L1ScraperConfig; +use apollo_state_sync_types::communication::MockStateSyncClient; +use papyrus_base_layer::{L1BlockReference, MockBaseLayerContract}; +use starknet_api::block::{BlockHashAndNumber, BlockNumber}; +use tokio::sync::mpsc::channel; + +#[tokio::test] +async fn flow_tests() { + // Setup. + let start_block = L1BlockReference::default(); + let historical_block = BlockHashAndNumber::default(); + + // Setup the base layer. + let mut base_layer = MockBaseLayerContract::default(); // TODO(guyn): replace this with Anvil. + base_layer.expect_latest_l1_block().returning(move |_| Ok(Some(start_block))); + base_layer.expect_latest_proved_block().returning(move |_| Ok(Some(historical_block))); + + // L1 provider setup. + let mut l1_provider = L1ProviderBuilder::new( + L1ProviderConfig::default(), + Arc::new(MockL1ProviderClient::default()), // This isn't right + Arc::new(MockBatcherClient::default()), // Consider saving a copy of this to interact + Arc::new(MockStateSyncClient::default()), /* We'll need a copy of this if we do + * bootstrapping */ + ) + .startup_height(BlockNumber(start_block.number)) + .catchup_height(historical_block.number) + .build(); + + // This channel connects the L1Provider client to the server. + let (tx, rx) = channel::>(32); + + // Create the client. + let l1_provider_client = + LocalComponentClient::new(tx, L1_PROVIDER_INFRA_METRICS.get_local_client_metrics()); + + // Create the server. + l1_provider.initialize(vec![]).await.unwrap(); + let _l1_provider_server = LocalComponentServer::new( + l1_provider, + &LocalServerConfig::default(), + rx, + L1_PROVIDER_INFRA_METRICS.get_local_server_metrics(), + ); + + // Setup the scraper. + let mut scraper = L1Scraper::new( + L1ScraperConfig::default(), + Arc::new(l1_provider_client.clone()), + base_layer, + &[], + start_block, + ) + .await + .expect("Should be able to create the scraper"); + + // Run the scraper in a separate task. + let _scraper_task = tokio::spawn(async move { + scraper.run().await.unwrap_or_else(|e| panic!("Error running scraper: {e:?}")); + }); +} From f26964de985a41e0494f86d954e7d56d9e57764a Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Sun, 9 Nov 2025 15:44:40 +0200 Subject: [PATCH 297/313] apollo_l1_provider: add anvil to flow test (#9871) --- Cargo.lock | 1 + crates/apollo_l1_provider/Cargo.toml | 1 + crates/apollo_l1_provider/tests/flow_tests.rs | 126 +++++++++++++----- 3 files changed, 98 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 393d1524c05..73f66fbf09a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1751,6 +1751,7 @@ name = "apollo_l1_provider" version = "0.16.0-rc.1" dependencies = [ "alloy", + "apollo_base_layer_tests", "apollo_batcher_types", "apollo_infra", "apollo_infra_utils", diff --git a/crates/apollo_l1_provider/Cargo.toml b/crates/apollo_l1_provider/Cargo.toml index 7a12a4f389b..48d24b63343 100644 --- a/crates/apollo_l1_provider/Cargo.toml +++ b/crates/apollo_l1_provider/Cargo.toml @@ -36,6 +36,7 @@ tracing.workspace = true [dev-dependencies] alloy.workspace = true +apollo_base_layer_tests.workspace = true apollo_batcher_types = { workspace = true, features = ["testing"] } apollo_l1_endpoint_monitor_types = { workspace = true, features = ["testing"] } apollo_l1_provider_types = { workspace = true, features = ["testing"] } diff --git a/crates/apollo_l1_provider/tests/flow_tests.rs b/crates/apollo_l1_provider/tests/flow_tests.rs index 21bd5c171b4..ff015341495 100644 --- a/crates/apollo_l1_provider/tests/flow_tests.rs +++ b/crates/apollo_l1_provider/tests/flow_tests.rs @@ -1,72 +1,138 @@ use std::sync::Arc; +use alloy::primitives::U256; +use apollo_base_layer_tests::anvil_base_layer::AnvilBaseLayer; use apollo_batcher_types::communication::MockBatcherClient; use apollo_infra::component_client::LocalComponentClient; -use apollo_infra::component_definitions::RequestWrapper; -use apollo_infra::component_server::{LocalComponentServer, LocalServerConfig}; +use apollo_infra::component_definitions::{ComponentStarter, RequestWrapper}; +use apollo_infra::component_server::{ + ComponentServerStarter, + LocalComponentServer, + LocalServerConfig, +}; use apollo_l1_provider::l1_provider::L1ProviderBuilder; use apollo_l1_provider::l1_scraper::L1Scraper; use apollo_l1_provider::metrics::L1_PROVIDER_INFRA_METRICS; -use apollo_l1_provider::L1ProviderConfig; -use apollo_l1_provider_types::{L1ProviderRequest, L1ProviderResponse, MockL1ProviderClient}; +use apollo_l1_provider::{event_identifiers_to_track, L1ProviderConfig}; +use apollo_l1_provider_types::{L1ProviderRequest, L1ProviderResponse}; use apollo_l1_scraper_config::config::L1ScraperConfig; use apollo_state_sync_types::communication::MockStateSyncClient; -use papyrus_base_layer::{L1BlockReference, MockBaseLayerContract}; -use starknet_api::block::{BlockHashAndNumber, BlockNumber}; +use apollo_state_sync_types::state_sync_types::SyncBlock; +use papyrus_base_layer::test_utils::anvil_mine_blocks; +use papyrus_base_layer::{BaseLayerContract, L1BlockNumber, L1BlockReference}; +use starknet_api::block::{BlockNumber, BlockTimestamp}; +use starknet_api::core::ChainId; use tokio::sync::mpsc::channel; #[tokio::test] async fn flow_tests() { // Setup. - let start_block = L1BlockReference::default(); - let historical_block = BlockHashAndNumber::default(); + const NUMBER_OF_BLOCKS_TO_MINE: u64 = 100; + let chain_id = ChainId::Mainnet; + let start_l1_block = L1BlockReference::default(); + let start_l1_block_number: L1BlockNumber = start_l1_block.number; + let start_l2_height = BlockNumber(0); + let target_l2_height = BlockNumber(1); - // Setup the base layer. - let mut base_layer = MockBaseLayerContract::default(); // TODO(guyn): replace this with Anvil. - base_layer.expect_latest_l1_block().returning(move |_| Ok(Some(start_block))); - base_layer.expect_latest_proved_block().returning(move |_| Ok(Some(historical_block))); + // Setup the state sync client. + let mut state_sync_client = MockStateSyncClient::default(); + state_sync_client.expect_get_block().returning(move |_| Ok(SyncBlock::default())); - // L1 provider setup. - let mut l1_provider = L1ProviderBuilder::new( - L1ProviderConfig::default(), - Arc::new(MockL1ProviderClient::default()), // This isn't right - Arc::new(MockBatcherClient::default()), // Consider saving a copy of this to interact - Arc::new(MockStateSyncClient::default()), /* We'll need a copy of this if we do - * bootstrapping */ + // Setup the base layer. + let base_layer = AnvilBaseLayer::new(None).await; + let contract = &base_layer.ethereum_base_layer.contract; + anvil_mine_blocks( + base_layer.ethereum_base_layer.config.clone(), + NUMBER_OF_BLOCKS_TO_MINE, + &base_layer.ethereum_base_layer.get_url().await.expect("Failed to get anvil url."), ) - .startup_height(BlockNumber(start_block.number)) - .catchup_height(historical_block.number) - .build(); + .await; + + // Send message from L1 to L2. + let l2_contract_address = "0x12"; + let l2_entry_point = "0x34"; + let call_data = vec![U256::from(1_u8), U256::from(2_u8)]; + let fee = 1_u8; + let message_to_l2 = contract + .sendMessageToL2( + l2_contract_address.parse().unwrap(), + l2_entry_point.parse().unwrap(), + call_data, + ) + .value(U256::from(fee)); + message_to_l2.call().await.unwrap(); // Query for errors. + let receipt = message_to_l2.send().await.unwrap().get_receipt().await.unwrap(); + let message_timestamp = base_layer + .get_block_header(receipt.block_number.unwrap()) + .await + .unwrap() + .unwrap() + .timestamp; + assert!(message_timestamp > BlockTimestamp(0)); + + // Make sure the L1 event was posted to Anvil + let finality = 0; + let last_l1_block_number = + base_layer.ethereum_base_layer.latest_l1_block_number(finality).await.unwrap(); + assert!(last_l1_block_number > start_l1_block_number + NUMBER_OF_BLOCKS_TO_MINE); + let event_filter = event_identifiers_to_track(); + let events = base_layer + .ethereum_base_layer + .events( + // Include last block with message. + start_l1_block_number..=last_l1_block_number + 1, + event_filter, + ) + .await + .unwrap(); + assert!(events.len() == 1); + // Set up the L1 provider client and server. // This channel connects the L1Provider client to the server. let (tx, rx) = channel::>(32); - // Create the client. + // Create the provider client. let l1_provider_client = LocalComponentClient::new(tx, L1_PROVIDER_INFRA_METRICS.get_local_client_metrics()); + // L1 provider setup. + let l1_provider = L1ProviderBuilder::new( + L1ProviderConfig::default(), + Arc::new(l1_provider_client.clone()), + Arc::new(MockBatcherClient::default()), // Consider saving a copy of this to interact + Arc::new(state_sync_client), + ) + .startup_height(start_l2_height) + .catchup_height(target_l2_height) + .build(); + // Create the server. - l1_provider.initialize(vec![]).await.unwrap(); - let _l1_provider_server = LocalComponentServer::new( + let mut l1_provider_server = LocalComponentServer::new( l1_provider, &LocalServerConfig::default(), rx, L1_PROVIDER_INFRA_METRICS.get_local_server_metrics(), ); + // Start the server: + tokio::spawn(async move { + l1_provider_server.start().await; + }); - // Setup the scraper. + // Set up the L1 scraper and run it as a server. + let l1_scraper_config = L1ScraperConfig { chain_id, ..Default::default() }; let mut scraper = L1Scraper::new( - L1ScraperConfig::default(), + l1_scraper_config, Arc::new(l1_provider_client.clone()), base_layer, &[], - start_block, + start_l1_block, ) .await .expect("Should be able to create the scraper"); // Run the scraper in a separate task. - let _scraper_task = tokio::spawn(async move { - scraper.run().await.unwrap_or_else(|e| panic!("Error running scraper: {e:?}")); + tokio::spawn(async move { + scraper.start().await; }); + // TODO(guyn): add the actual test here. } From 0ec9b1023b7d70b3419fb7f6c2c0f5752aaaa2e7 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Sun, 9 Nov 2025 16:01:33 +0200 Subject: [PATCH 298/313] apollo_deployments: fix multiaddr empty lists (#10036) --- .../deployments/replacer_deployment.json | 4 +- .../deployments/replacer_instance.json | 4 +- crates/apollo_deployments/src/replacers.rs | 42 +------------------ 3 files changed, 5 insertions(+), 45 deletions(-) diff --git a/crates/apollo_deployments/resources/deployments/replacer_deployment.json b/crates/apollo_deployments/resources/deployments/replacer_deployment.json index 76530a6eaca..218e8a6d658 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_deployment.json +++ b/crates/apollo_deployments/resources/deployments/replacer_deployment.json @@ -2,14 +2,14 @@ "base_layer_config.starknet_contract_address": "$$$_BASE_LAYER_CONFIG-STARKNET_CONTRACT_ADDRESS_$$$", "chain_id": "$$$_CHAIN_ID_$$$", "consensus_manager_config.context_config.num_validators": "$$$_CONSENSUS_MANAGER_CONFIG-CONTEXT_CONFIG-NUM_VALIDATORS_$$$", - "consensus_manager_config.network_config.bootstrap_peer_multiaddr": [], + "consensus_manager_config.network_config.bootstrap_peer_multiaddr": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", "consensus_manager_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", "consensus_manager_config.network_config.port": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-PORT_$$$", "eth_fee_token_address": "$$$_ETH_FEE_TOKEN_ADDRESS_$$$", "http_server_config.port": "$$$_HTTP_SERVER_CONFIG-PORT_$$$", "l1_provider_config.provider_startup_height_override": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE_$$$", "l1_provider_config.provider_startup_height_override.#is_none": "$$$_L1_PROVIDER_CONFIG-PROVIDER_STARTUP_HEIGHT_OVERRIDE-IS_NONE_$$$", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": [], + "mempool_p2p_config.network_config.bootstrap_peer_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR_$$$", "mempool_p2p_config.network_config.bootstrap_peer_multiaddr.#is_none": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-BOOTSTRAP_PEER_MULTIADDR-IS_NONE_$$$", "mempool_p2p_config.network_config.port": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-PORT_$$$", "monitoring_endpoint_config.port": "$$$_MONITORING_ENDPOINT_CONFIG-PORT_$$$", diff --git a/crates/apollo_deployments/resources/deployments/replacer_instance.json b/crates/apollo_deployments/resources/deployments/replacer_instance.json index cefb64f5e01..93e4ca688d2 100644 --- a/crates/apollo_deployments/resources/deployments/replacer_instance.json +++ b/crates/apollo_deployments/resources/deployments/replacer_instance.json @@ -1,7 +1,7 @@ { - "consensus_manager_config.network_config.advertised_multiaddr": [], + "consensus_manager_config.network_config.advertised_multiaddr": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR_$$$", "consensus_manager_config.network_config.advertised_multiaddr.#is_none": "$$$_CONSENSUS_MANAGER_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR-IS_NONE_$$$", - "mempool_p2p_config.network_config.advertised_multiaddr": [], + "mempool_p2p_config.network_config.advertised_multiaddr": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR_$$$", "mempool_p2p_config.network_config.advertised_multiaddr.#is_none": "$$$_MEMPOOL_P2P_CONFIG-NETWORK_CONFIG-ADVERTISED_MULTIADDR-IS_NONE_$$$", "validator_id": "$$$_VALIDATOR_ID_$$$" } diff --git a/crates/apollo_deployments/src/replacers.rs b/crates/apollo_deployments/src/replacers.rs index 7d73f14073d..140c6c19f09 100644 --- a/crates/apollo_deployments/src/replacers.rs +++ b/crates/apollo_deployments/src/replacers.rs @@ -2,15 +2,6 @@ use apollo_infra_utils::template::Template; use serde_json::Value; const REPLACER_FORMAT: &str = "$$$_{}_$$$"; -use libp2p::Multiaddr; - -const MULTIADDR_KEYS: [&str; 4] = [ - "consensus_manager_config.network_config.bootstrap_peer_multiaddr", - "mempool_p2p_config.network_config.bootstrap_peer_multiaddr", - "consensus_manager_config.network_config.advertised_multiaddr", - "mempool_p2p_config.network_config.advertised_multiaddr", -]; - pub(crate) fn insert_replacer_annotations(mut json: Value, pred: F) -> Value where F: Fn(&str, &Value) -> bool, @@ -27,22 +18,7 @@ where }; if should_replace { - if MULTIADDR_KEYS.contains(&key.as_str()) { - let multiaddrs = extract_multiaddrs(map, &key); - if let Some(multiaddrs) = multiaddrs { - map.insert( - key.clone(), - Value::Array( - multiaddrs - .into_iter() - .map(|addr| Value::String(addr.to_string())) - .collect(), - ), - ); - } - } else { - map.insert(key.clone(), Value::String(format_key(key.clone()))); - } + map.insert(key.clone(), Value::String(format_key(key.clone()))); } } @@ -52,19 +28,3 @@ where fn format_key(key: String) -> String { Template::new(REPLACER_FORMAT).format(&[&key]).to_uppercase().replace('.', "-").replace('#', "") } - -fn parse_multiaddrs(value: &str) -> Vec { - value - .split(',') - .map(str::trim) - .filter(|s| !s.is_empty()) - .filter_map(|s| s.parse::().ok()) // skip invalid addresses - .collect() -} - -pub fn extract_multiaddrs( - json: &serde_json::Map, - key: &str, -) -> Option> { - json.get(key)?.as_str().map(parse_multiaddrs) -} From 8ac26fffaceec85cbe0273ed2eed5f6bc9c71660 Mon Sep 17 00:00:00 2001 From: lev-starkware <155880815+lev-starkware@users.noreply.github.com> Date: Sun, 9 Nov 2025 17:48:20 +0200 Subject: [PATCH 299/313] apollo_mempool: adding commit messages to benchmark (#9922) --- crates/apollo_mempool/benches/utils.rs | 39 ++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/crates/apollo_mempool/benches/utils.rs b/crates/apollo_mempool/benches/utils.rs index 1f98ce35b44..6c134d932fd 100644 --- a/crates/apollo_mempool/benches/utils.rs +++ b/crates/apollo_mempool/benches/utils.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::sync::Arc; use apollo_config_manager_types::communication::MockConfigManagerClient; @@ -14,14 +15,15 @@ use apollo_mempool_types::communication::{ LocalMempoolClient, SharedMempoolClient, }; -use apollo_mempool_types::mempool_types::{AccountState, AddTransactionArgs}; +use apollo_mempool_types::mempool_types::{AccountState, AddTransactionArgs, CommitBlockArgs}; use apollo_metrics::metrics::{LabeledMetricHistogram, MetricCounter, MetricGauge, MetricScope}; use apollo_network_types::network_types::BroadcastedMessageMetadata; use async_trait::async_trait; use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1}; use blockifier_test_utils::contracts::FeatureContract; +use indexmap::IndexSet; use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; -use starknet_api::core::ContractAddress; +use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::rpc_transaction::{ InternalRpcTransaction, InternalRpcTransactionWithoutTxHash, @@ -250,15 +252,42 @@ impl BenchTestSetup { /// Task that continuously retrieves transactions from the mempool via client. /// Simulates concurrent consumers in a real system async fn get_txs_task(client: SharedMempoolClient, n_txs: usize, chunk_size: usize) { - let mut txs_received = 0; + let mut n_txs_received = 0; + let mut last_committed_chunk = 0; + let mut address_to_nonce = HashMap::::new(); - while txs_received < n_txs { + while n_txs_received < n_txs { let retrieved_txs = client .get_txs(chunk_size) .await .unwrap_or_else(|e| panic!("Failed to get txs from mempool: {e:?}")); - txs_received += retrieved_txs.len(); + n_txs_received += retrieved_txs.len(); + + // Aggregate the highest nonce for each contract address in this chunk. + retrieved_txs.iter().for_each(|tx| { + let address = tx.contract_address(); + let nonce = tx.nonce(); + address_to_nonce + .entry(address) + .and_modify(|max_nonce| *max_nonce = (*max_nonce).max(nonce)) + .or_insert(nonce); + }); + + // Commit a block when we've accumulated enough transactions for a complete chunk. + // This simulates the block production cycle where transactions are periodically + // committed after being retrieved from the mempool. + if last_committed_chunk < n_txs_received / chunk_size { + last_committed_chunk += 1; + + client + .commit_block(CommitBlockArgs { + address_to_nonce: std::mem::take(&mut address_to_nonce), + rejected_tx_hashes: IndexSet::new(), + }) + .await + .unwrap(); + } // If no txs retrieved, wait a bit for add_tx_task to add more if retrieved_txs.is_empty() { From 4f77508701cb2ccf2e9d578d0764f4eb52d30174 Mon Sep 17 00:00:00 2001 From: lev-starkware <155880815+lev-starkware@users.noreply.github.com> Date: Sun, 9 Nov 2025 18:17:06 +0200 Subject: [PATCH 300/313] apollo_storage: open_storage behaiviour (#9344) --- Cargo.lock | 2 + crates/apollo_storage/Cargo.toml | 2 + crates/apollo_storage/src/db/mod.rs | 2 + crates/apollo_storage/src/lib.rs | 3 + .../apollo_storage/src/open_storage_test.rs | 158 ++++++++++++++++++ .../tests/open_storage_in_processes_test.rs | 158 ++++++++++++++++++ 6 files changed, 325 insertions(+) create mode 100644 crates/apollo_storage/src/open_storage_test.rs create mode 100644 crates/apollo_storage/tests/open_storage_in_processes_test.rs diff --git a/Cargo.lock b/Cargo.lock index 73f66fbf09a..6351be8c2fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2534,6 +2534,7 @@ dependencies = [ "cairo-lang-utils", "camelpaste", "clap", + "futures", "human_bytes", "indexmap 2.11.0", "insta", @@ -2543,6 +2544,7 @@ dependencies = [ "memmap2", "metrics 0.24.2", "metrics-exporter-prometheus", + "nix 0.20.2", "num-bigint 0.4.6", "num-traits", "page_size", diff --git a/crates/apollo_storage/Cargo.toml b/crates/apollo_storage/Cargo.toml index e677a8a0f7e..b70501e2ef1 100644 --- a/crates/apollo_storage/Cargo.toml +++ b/crates/apollo_storage/Cargo.toml @@ -55,8 +55,10 @@ apollo_test_utils.workspace = true assert_matches.workspace = true cairo-lang-casm = { workspace = true, features = ["parity-scale-codec", "schemars"] } camelpaste.workspace = true +futures.workspace = true insta = { workspace = true, features = ["yaml"] } metrics-exporter-prometheus.workspace = true +nix.workspace = true num-traits.workspace = true paste.workspace = true pretty_assertions.workspace = true diff --git a/crates/apollo_storage/src/db/mod.rs b/crates/apollo_storage/src/db/mod.rs index 282a482e4dc..82a04e5840f 100644 --- a/crates/apollo_storage/src/db/mod.rs +++ b/crates/apollo_storage/src/db/mod.rs @@ -222,6 +222,8 @@ pub(crate) fn open_env(config: &DbConfig) -> DbResult<(DbReader, DbWriter)> { no_rdahead: true, // LIFO policy for recycling a Garbage Collection items should be faster. liforeclaim: true, + // Exclusive access - prevent other processes from opening the same database. + exclusive: true, ..Default::default() }) .open(&config.path())?, diff --git a/crates/apollo_storage/src/lib.rs b/crates/apollo_storage/src/lib.rs index c40616c2a06..3011dc2aef7 100644 --- a/crates/apollo_storage/src/lib.rs +++ b/crates/apollo_storage/src/lib.rs @@ -102,6 +102,9 @@ mod deprecated; #[cfg(test)] mod test_instances; +#[cfg(test)] +mod open_storage_test; + #[cfg(any(feature = "testing", test))] pub mod test_utils; diff --git a/crates/apollo_storage/src/open_storage_test.rs b/crates/apollo_storage/src/open_storage_test.rs new file mode 100644 index 00000000000..503d6060644 --- /dev/null +++ b/crates/apollo_storage/src/open_storage_test.rs @@ -0,0 +1,158 @@ +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +use starknet_api::block::BlockNumber; +use tempfile::tempdir; + +use crate::header::HeaderStorageReader; +use crate::test_utils::get_test_config_with_path; +use crate::{open_storage, StorageConfig, StorageError, StorageReader, StorageScope}; + +/// Check that storage reader can access storage +fn check_storage_is_accessible(reader: &StorageReader) -> bool { + reader.begin_ro_txn().unwrap().get_block_signature(BlockNumber(0)).unwrap().is_none() +} + +/// Test that opening storage twice in the same thread fails. +/// +/// This test verifies that attempting to open the same storage database twice +/// within a single thread results in an libmdbx error. +/// +/// # Test Flow +/// 1. Opens storage successfully the first time +/// 2. Verifies the storage is accessible and empty +/// 3. Attempts to open the same storage again (should fail) +/// 4. Asserts that the second attempt returns `StorageError::InnerError` +#[test] +fn get_storage_twice_should_fail() { + let temp_dir = tempdir().expect("Failed to create temp directory"); + let config = + get_test_config_with_path(Some(StorageScope::StateOnly), temp_dir.path().to_path_buf()); + + // Get storage first time + let (reader, mut _writer) = open_storage(config.clone()).unwrap(); + assert!(check_storage_is_accessible(&reader)); + + // Get the same storage second time should fail because tables already exist + let result = open_storage(config); + assert!( + matches!(result, Err(StorageError::InnerError(_))), + "Opening storage twice should fail" + ); +} + +/// Test that opening storage from two threads fails. +/// +/// This test verifies that when two threads attempt to open the same storage +/// database concurrently, only one succeeds while the other fails with an error. +/// Uses thread synchronization via barriers to ensure both threads attempt +/// storage access simultaneously. +/// +/// # Test Flow +/// 1. Creates two threads that will attempt to open storage +/// 2. Uses `std::sync::Barrier` to synchronize thread execution +/// 3. First thread opens storage immediately +/// 4. Second thread waits 100 milliseconds then attempts to open storage +/// 5. Both threads synchronize at barrier after their attempts +/// 6. Verifies that first thread succeeds and second thread fails +#[test] +fn get_storage_from_two_threads_should_fail() { + let temp_dir = tempdir().expect("Failed to create temp directory"); + let config = + get_test_config_with_path(Some(StorageScope::StateOnly), temp_dir.path().to_path_buf()); + let barrier = Arc::new(std::sync::Barrier::new(2)); + + // Start both threads + let config1 = config.clone(); + let barrier1 = barrier.clone(); + let handle1 = thread::spawn(move || open_storage_with_barrier(config1, barrier1)); + + let handle2 = { + thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + open_storage_with_barrier(config, barrier) + }) + }; + + // Wait for both threads to complete + let result1 = handle1.join().unwrap(); + let result2 = handle2.join().unwrap(); + assert!( + result1.is_ok() && matches!(result2, Err(StorageError::InnerError(_))), + "Opening storage from two threads should fail" + ); +} + +/// Function to handle storage opening with barrier synchronization. +fn open_storage_with_barrier( + config: StorageConfig, + barrier: Arc, +) -> Result<(), StorageError> { + let result = open_storage(config); + barrier.wait(); // Synchronize with other thread. + match result { + Ok((reader, _writer)) => { + assert!(check_storage_is_accessible(&reader)); + Ok(()) + } + Err(e) => Err(e), + } +} + +/// Test that opening storage from two async tokio tasks fails. +/// +/// This test verifies that when two async tasks attempt to open the same storage +/// database concurrently, only one succeeds while the other fails with an error. +/// Uses tokio's async barrier synchronization to coordinate task execution. +/// +/// # Test Flow +/// 1. Creates two async tasks that will attempt to open storage +/// 2. Uses `tokio::sync::Barrier` to synchronize task execution +/// 3. First task opens storage immediately +/// 4. Second task waits 100 milliseconds then attempts to open storage +/// 5. Both tasks synchronize at barrier after their attempts +/// 6. Verifies that first task succeeds and second task fails +#[tokio::test] +async fn get_storage_from_two_tokio_tasks_should_fail() { + let temp_dir = tempdir().expect("Failed to create temp directory"); + let config = + get_test_config_with_path(Some(StorageScope::StateOnly), temp_dir.path().to_path_buf()); + + let barrier = Arc::new(tokio::sync::Barrier::new(2)); + + let config1 = config.clone(); + let barrier1 = barrier.clone(); + let task1 = + tokio::spawn(async move { async_open_storage_with_barrier(config1, barrier1).await }); + + let task2 = tokio::spawn(async move { + tokio::time::sleep(Duration::from_millis(100)).await; + async_open_storage_with_barrier(config, barrier).await + }); + + let results = tokio::join!(task1, task2); + + let task1_result = results.0.unwrap(); + let task2_result = results.1.unwrap(); + assert!( + task1_result.is_ok() && matches!(task2_result, Err(StorageError::InnerError(_))), + "Opening storage from two tokio tasks should fail" + ); +} + +/// Function to handle storage opening with barrier synchronization +async fn async_open_storage_with_barrier( + config: StorageConfig, + barrier: Arc, +) -> Result<(), StorageError> { + let result = open_storage(config); + barrier.wait().await; // Synchronize with other thread + match result { + Ok((reader, _writer)) => { + assert!(check_storage_is_accessible(&reader)); + Ok(()) + } + Err(e) => Err(e), + } +} diff --git a/crates/apollo_storage/tests/open_storage_in_processes_test.rs b/crates/apollo_storage/tests/open_storage_in_processes_test.rs new file mode 100644 index 00000000000..1207e96f30d --- /dev/null +++ b/crates/apollo_storage/tests/open_storage_in_processes_test.rs @@ -0,0 +1,158 @@ +// This test is used to test the storage opening in two separate processes. +// It runs as an integration test because forking a process within a unit test acts unexpectedly. + +use std::fs::{self, create_dir_all}; +use std::path::PathBuf; +use std::thread; +use std::time::{Duration, Instant}; + +use apollo_storage::db::DbConfig; +use apollo_storage::header::HeaderStorageReader; +use apollo_storage::mmap_file::MmapFileConfig; +use apollo_storage::{open_storage, StorageConfig, StorageError, StorageReader, StorageScope}; +use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; +use nix::unistd::{fork, ForkResult}; +use starknet_api::block::BlockNumber; +use starknet_api::test_utils::CHAIN_ID_FOR_TESTS; +use tempfile::tempdir; + +/// Returns a db config for a given path. +/// This function ensures that the specified directory exists by creating it if necessary. +/// Note: This function is a copy from the private test_utils.rs module. +fn get_test_config_with_path(storage_scope: Option, path: PathBuf) -> StorageConfig { + let storage_scope = storage_scope.unwrap_or_default(); + create_dir_all(&path).expect("Failed to create directory"); + + StorageConfig { + db_config: DbConfig { + path_prefix: path, + chain_id: CHAIN_ID_FOR_TESTS.clone(), + enforce_file_exists: false, + min_size: 1 << 20, // 1MB + max_size: 1 << 35, // 32GB + growth_step: 1 << 26, // 64MB + max_readers: 1 << 13, // 8K readers + }, + scope: storage_scope, + mmap_file_config: MmapFileConfig { + max_size: 1 << 24, // 16MB + growth_step: 1 << 20, // 1MB + max_object_size: 1 << 16, // 64KB + }, + } +} + +/// Check that storage reader can access storage +fn check_storage_is_accessible(reader: &StorageReader) -> bool { + reader.begin_ro_txn().unwrap().get_block_signature(BlockNumber(0)).unwrap().is_none() +} + +/// Helper function to wait for a child process with a timeout. +/// +/// Polls `waitpid` with `WNOHANG` flag until either: +/// - The child exits (returns exit status) +/// - The timeout is reached (returns None) +fn waitpid_with_timeout(pid: nix::unistd::Pid, timeout: Duration) -> Option { + let start = Instant::now(); + loop { + match waitpid(pid, Some(WaitPidFlag::WNOHANG)) { + Ok(WaitStatus::Exited(_, exit_code)) => return Some(exit_code), + Ok(WaitStatus::StillAlive) => { + if start.elapsed() >= timeout { + return None; + } + thread::sleep(Duration::from_millis(10)); + } + Ok(_) => return None, // Other status like signaled, stopped, etc. + Err(_) => return None, + } + } +} + +/// Test that opening storage from two separate processes fails. +/// +/// This test verifies that the libmdbx database exclusive locking mechanism works correctly +/// across process boundaries. When one process has opened the storage with exclusive access, +/// any subsequent attempt by another process to open the same storage should fail. +/// +/// # Test Flow +/// 1. **Fork Process**: Creates a parent and child process using `fork()` +/// 2. **Parent Process**: +/// - Opens storage successfully (gets exclusive lock) +/// - Verifies storage is accessible and empty +/// - Signals child process to proceed +/// - Waits for child to complete its attempt +/// - Verifies child process exited with error code 1 +/// 3. **Child Process**: +/// - Waits for parent to signal readiness +/// - Attempts to open the same storage (should fail) +/// - Expects `StorageError::InnerError` due to MDBX exclusive lock +/// - Exits with code 1 (indicating expected failure) +/// +/// # Synchronization +/// Uses file-based synchronization between processes: +/// - `parent_ready`: Created when parent has opened storage +#[test] +fn get_storage_from_two_processes_with_fork_should_fail() { + let temp_dir = tempdir().expect("Failed to create temp directory"); + let config = + get_test_config_with_path(Some(StorageScope::StateOnly), temp_dir.path().to_path_buf()); + + // Use regular files for synchronization between processes + let parent_ready_path = temp_dir.path().join("parent_ready"); + + match unsafe { fork() } { + Ok(ForkResult::Parent { child }) => { + // Parent process + let (reader, _writer) = open_storage(config.clone()).unwrap(); + assert!(check_storage_is_accessible(&reader)); + + // Signal child that parent has opened storage + fs::write(&parent_ready_path, b"1").unwrap(); + + // Wait for child process to complete with timeout + match waitpid_with_timeout(child, Duration::from_secs(5)) { + Some(exit_code) => { + assert!( + exit_code == 1, + "Parent: Child process should exit with exit code 1, received: {exit_code}" + ); + } + None => { + panic!("Parent: Timeout or error waiting for child process to exit"); + } + } + + // Clean up + let _ = fs::remove_file(&parent_ready_path); + } + Ok(ForkResult::Child) => { + // Wait for parent to signal that it has opened storage + let timeout = Instant::now() + Duration::from_secs(5); + while !parent_ready_path.exists() { + if Instant::now() >= timeout { + println!("Child: Timeout waiting for parent to be ready"); + std::process::exit(2); + } + thread::sleep(Duration::from_millis(10)); + } + + // Child process - try to open storage + let result = open_storage(config); + let exit_code = match result { + Ok((_reader, _writer)) => { + println!("Child: Unexpected success opening storage"); + 0 + } + Err(StorageError::InnerError(_)) => 1, + Err(e) => { + println!("Child: Storage opening failed with unexpected error: {e:?}"); + 2 + } + }; + + std::process::exit(exit_code); + } + Err(_) => panic!("Fork failed"), + } +} From a5742857542aa10247d283fd965d0178b5c484f4 Mon Sep 17 00:00:00 2001 From: Itay-Tsabary-Starkware <106665835+Itay-Tsabary-Starkware@users.noreply.github.com> Date: Mon, 10 Nov 2025 07:54:42 +0200 Subject: [PATCH 301/313] apollo_dashboard: fix tokio panel labels (#10037) --- .../resources/dev_grafana.json | 42 +++++++++++++++---- crates/apollo_dashboard/src/panels/tokio.rs | 11 ++++- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 23fce01d3ad..35f9e4f9127 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -1314,7 +1314,11 @@ "exprs": [ "tokio_min_busy_duration{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "legends": [ + "{{pod}}" + ] + } }, { "title": "tokio_max_busy_duration", @@ -1323,7 +1327,11 @@ "exprs": [ "tokio_max_busy_duration{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "legends": [ + "{{pod}}" + ] + } }, { "title": "tokio_total_park_count", @@ -1332,7 +1340,11 @@ "exprs": [ "tokio_total_park_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "legends": [ + "{{pod}}" + ] + } }, { "title": "tokio_min_park_count", @@ -1341,7 +1353,11 @@ "exprs": [ "tokio_min_park_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "legends": [ + "{{pod}}" + ] + } }, { "title": "tokio_max_park_count", @@ -1350,7 +1366,11 @@ "exprs": [ "tokio_max_park_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "legends": [ + "{{pod}}" + ] + } }, { "title": "tokio_global_queue_depth", @@ -1359,7 +1379,11 @@ "exprs": [ "tokio_global_queue_depth{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "legends": [ + "{{pod}}" + ] + } }, { "title": "tokio_workers_count", @@ -1368,7 +1392,11 @@ "exprs": [ "tokio_workers_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], - "extra_params": {} + "extra_params": { + "legends": [ + "{{pod}}" + ] + } } ], "collapsed": true diff --git a/crates/apollo_dashboard/src/panels/tokio.rs b/crates/apollo_dashboard/src/panels/tokio.rs index 55a9de6d385..87094d84358 100644 --- a/crates/apollo_dashboard/src/panels/tokio.rs +++ b/crates/apollo_dashboard/src/panels/tokio.rs @@ -11,31 +11,40 @@ use apollo_monitoring_endpoint::tokio_metrics::{ use crate::dashboard::{Panel, PanelType, Row}; +const TOKIO_PANEL_LEGENDS: &[&str] = &["{{pod}}"]; + fn get_panel_tokio_total_busy_duration_micros() -> Panel { Panel::from_counter(&TOKIO_TOTAL_BUSY_DURATION_MICROS, PanelType::TimeSeries) - .with_legends(vec!["{{pod}}"]) + .with_legends(TOKIO_PANEL_LEGENDS.to_vec()) } fn get_panel_tokio_min_busy_duration_micros() -> Panel { Panel::from_counter(&TOKIO_MIN_BUSY_DURATION_MICROS, PanelType::TimeSeries) + .with_legends(TOKIO_PANEL_LEGENDS.to_vec()) } fn get_panel_tokio_max_busy_duration_micros() -> Panel { Panel::from_counter(&TOKIO_MAX_BUSY_DURATION_MICROS, PanelType::TimeSeries) + .with_legends(TOKIO_PANEL_LEGENDS.to_vec()) } fn get_panel_tokio_total_park_count() -> Panel { Panel::from_gauge(&TOKIO_TOTAL_PARK_COUNT, PanelType::TimeSeries) + .with_legends(TOKIO_PANEL_LEGENDS.to_vec()) } fn get_panel_tokio_min_park_count() -> Panel { Panel::from_gauge(&TOKIO_MIN_PARK_COUNT, PanelType::TimeSeries) + .with_legends(TOKIO_PANEL_LEGENDS.to_vec()) } fn get_panel_tokio_max_park_count() -> Panel { Panel::from_gauge(&TOKIO_MAX_PARK_COUNT, PanelType::TimeSeries) + .with_legends(TOKIO_PANEL_LEGENDS.to_vec()) } fn get_panel_tokio_global_queue_depth() -> Panel { Panel::from_gauge(&TOKIO_GLOBAL_QUEUE_DEPTH, PanelType::TimeSeries) + .with_legends(TOKIO_PANEL_LEGENDS.to_vec()) } fn get_panel_tokio_workers_count() -> Panel { Panel::from_gauge(&TOKIO_WORKERS_COUNT, PanelType::TimeSeries) + .with_legends(TOKIO_PANEL_LEGENDS.to_vec()) } pub(crate) fn get_tokio_row() -> Row { From 779308c2d3b854c53dbbd2ea8dbe4e4193972231 Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Mon, 10 Nov 2025 09:56:09 +0200 Subject: [PATCH 302/313] apollo_l1_provider: add basic flow test Anvil->Scraper->Provider (#9902) --- crates/apollo_l1_provider/tests/flow_tests.rs | 77 +++++++++++++++++-- .../src/ethereum_base_layer_contract.rs | 2 - 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/crates/apollo_l1_provider/tests/flow_tests.rs b/crates/apollo_l1_provider/tests/flow_tests.rs index ff015341495..5858cee157a 100644 --- a/crates/apollo_l1_provider/tests/flow_tests.rs +++ b/crates/apollo_l1_provider/tests/flow_tests.rs @@ -1,4 +1,5 @@ use std::sync::Arc; +use std::time::Duration; use alloy::primitives::U256; use apollo_base_layer_tests::anvil_base_layer::AnvilBaseLayer; @@ -14,7 +15,14 @@ use apollo_l1_provider::l1_provider::L1ProviderBuilder; use apollo_l1_provider::l1_scraper::L1Scraper; use apollo_l1_provider::metrics::L1_PROVIDER_INFRA_METRICS; use apollo_l1_provider::{event_identifiers_to_track, L1ProviderConfig}; -use apollo_l1_provider_types::{L1ProviderRequest, L1ProviderResponse}; +use apollo_l1_provider_types::{ + Event, + L1ProviderClient, + L1ProviderRequest, + L1ProviderResponse, + SessionState, + ValidationStatus, +}; use apollo_l1_scraper_config::config::L1ScraperConfig; use apollo_state_sync_types::communication::MockStateSyncClient; use apollo_state_sync_types::state_sync_types::SyncBlock; @@ -27,8 +35,12 @@ use tokio::sync::mpsc::channel; #[tokio::test] async fn flow_tests() { // Setup. + // Must wait at least 1 second, as timestamps are integer seconds. + const COOLDOWN_DURATION: Duration = Duration::from_millis(1000); + const WAIT_FOR_L1_DURATION: Duration = Duration::from_millis(10); const NUMBER_OF_BLOCKS_TO_MINE: u64 = 100; let chain_id = ChainId::Mainnet; + let start_l1_block = L1BlockReference::default(); let start_l1_block_number: L1BlockNumber = start_l1_block.number; let start_l2_height = BlockNumber(0); @@ -48,6 +60,11 @@ async fn flow_tests() { ) .await; + let finality = 0; + let last_l1_block_number = + base_layer.ethereum_base_layer.latest_l1_block_number(finality).await.unwrap(); + assert!(last_l1_block_number > start_l1_block_number + NUMBER_OF_BLOCKS_TO_MINE); + // Send message from L1 to L2. let l2_contract_address = "0x12"; let l2_entry_point = "0x34"; @@ -76,7 +93,7 @@ async fn flow_tests() { base_layer.ethereum_base_layer.latest_l1_block_number(finality).await.unwrap(); assert!(last_l1_block_number > start_l1_block_number + NUMBER_OF_BLOCKS_TO_MINE); let event_filter = event_identifiers_to_track(); - let events = base_layer + let mut events = base_layer .ethereum_base_layer .events( // Include last block with message. @@ -86,6 +103,16 @@ async fn flow_tests() { .await .unwrap(); assert!(events.len() == 1); + let l1_event = events.pop().unwrap(); + + // Convert the L1 event to an Apollo event, so we can get the L2 hash. + let l1_event_converted = + apollo_l1_provider_types::Event::from_l1_event(&chain_id, l1_event, message_timestamp.0) + .unwrap(); + let Event::L1HandlerTransaction { l1_handler_tx, .. } = l1_event_converted else { + panic!("L1 event converted is not a L1 handler transaction"); + }; + let l2_hash = l1_handler_tx.tx_hash; // Set up the L1 provider client and server. // This channel connects the L1Provider client to the server. @@ -96,8 +123,12 @@ async fn flow_tests() { LocalComponentClient::new(tx, L1_PROVIDER_INFRA_METRICS.get_local_client_metrics()); // L1 provider setup. + let l1_provider_config = L1ProviderConfig { + new_l1_handler_cooldown_seconds: COOLDOWN_DURATION, + ..Default::default() + }; let l1_provider = L1ProviderBuilder::new( - L1ProviderConfig::default(), + l1_provider_config, Arc::new(l1_provider_client.clone()), Arc::new(MockBatcherClient::default()), // Consider saving a copy of this to interact Arc::new(state_sync_client), @@ -119,7 +150,11 @@ async fn flow_tests() { }); // Set up the L1 scraper and run it as a server. - let l1_scraper_config = L1ScraperConfig { chain_id, ..Default::default() }; + let l1_scraper_config = L1ScraperConfig { + polling_interval_seconds: COOLDOWN_DURATION, + chain_id, + ..Default::default() + }; let mut scraper = L1Scraper::new( l1_scraper_config, Arc::new(l1_provider_client.clone()), @@ -134,5 +169,37 @@ async fn flow_tests() { tokio::spawn(async move { scraper.start().await; }); - // TODO(guyn): add the actual test here. + tokio::time::sleep(WAIT_FOR_L1_DURATION).await; + + // Test. + let next_block_height = BlockNumber(target_l2_height.0 + 1); + + // Check that we can validate this message even though no time has passed. + l1_provider_client.start_block(SessionState::Validate, next_block_height).await.unwrap(); + assert_eq!( + l1_provider_client.validate(l2_hash, next_block_height).await.unwrap(), + ValidationStatus::Validated + ); + + // Test that we do not propose anything before the cooldown is over. + l1_provider_client.start_block(SessionState::Propose, next_block_height).await.unwrap(); + let n_txs = 1; + let txs = l1_provider_client.get_txs(n_txs, next_block_height).await.unwrap(); + assert!(txs.is_empty()); + + // Sleep at least one second more than the cooldown to make sure we are not failing due to + // fractional seconds. + tokio::time::sleep(COOLDOWN_DURATION + Duration::from_secs(1)).await; + + // Test that we propose after the cooldown is over. + l1_provider_client.start_block(SessionState::Propose, next_block_height).await.unwrap(); + let txs = l1_provider_client.get_txs(n_txs, next_block_height).await.unwrap(); + assert!(!txs.is_empty()); + + // Check that we can validate this message after the cooldown, too. + l1_provider_client.start_block(SessionState::Validate, next_block_height).await.unwrap(); + assert_eq!( + l1_provider_client.validate(l2_hash, next_block_height).await.unwrap(), + ValidationStatus::Validated + ); } diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index f165ba32ede..4d1ec515563 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -125,13 +125,11 @@ impl BaseLayerContract for EthereumBaseLayerContract { .select(block_range.clone()) .events(events) .address(self.config.starknet_contract_address); - let matching_logs = tokio::time::timeout( self.config.timeout_millis, self.contract.provider().get_logs(&filter), ) .await??; - // Debugging. let hashes: Vec<_> = matching_logs.iter().filter_map(|log| log.transaction_hash).collect(); debug!("Got events in {:?}, L1 tx hashes: {:?}", block_range, hashes); From adecfa039a30c609489e8381cf71da54a6bd5d54 Mon Sep 17 00:00:00 2001 From: guy-starkware Date: Mon, 10 Nov 2025 10:48:49 +0200 Subject: [PATCH 303/313] apollo_l1_provider: separate out some constants from the flow test (#9906) --- crates/apollo_l1_provider/tests/flow_tests.rs | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/crates/apollo_l1_provider/tests/flow_tests.rs b/crates/apollo_l1_provider/tests/flow_tests.rs index 5858cee157a..e3c5e70edb9 100644 --- a/crates/apollo_l1_provider/tests/flow_tests.rs +++ b/crates/apollo_l1_provider/tests/flow_tests.rs @@ -27,25 +27,25 @@ use apollo_l1_scraper_config::config::L1ScraperConfig; use apollo_state_sync_types::communication::MockStateSyncClient; use apollo_state_sync_types::state_sync_types::SyncBlock; use papyrus_base_layer::test_utils::anvil_mine_blocks; -use papyrus_base_layer::{BaseLayerContract, L1BlockNumber, L1BlockReference}; +use papyrus_base_layer::{BaseLayerContract, L1BlockHash, L1BlockNumber, L1BlockReference}; use starknet_api::block::{BlockNumber, BlockTimestamp}; use starknet_api::core::ChainId; use tokio::sync::mpsc::channel; +// Must wait at least 1 second, as timestamps are integer seconds. +const COOLDOWN_DURATION: Duration = Duration::from_millis(1000); +const WAIT_FOR_L1_DURATION: Duration = Duration::from_millis(10); +const NUMBER_OF_BLOCKS_TO_MINE: u64 = 100; +const CHAIN_ID: ChainId = ChainId::Mainnet; + +const START_L1_BLOCK: L1BlockReference = L1BlockReference { number: 0, hash: L1BlockHash([0; 32]) }; +const START_L1_BLOCK_NUMBER: L1BlockNumber = START_L1_BLOCK.number; +const START_L2_HEIGHT: BlockNumber = BlockNumber(0); +const TARGET_L2_HEIGHT: BlockNumber = BlockNumber(1); + #[tokio::test] async fn flow_tests() { // Setup. - // Must wait at least 1 second, as timestamps are integer seconds. - const COOLDOWN_DURATION: Duration = Duration::from_millis(1000); - const WAIT_FOR_L1_DURATION: Duration = Duration::from_millis(10); - const NUMBER_OF_BLOCKS_TO_MINE: u64 = 100; - let chain_id = ChainId::Mainnet; - - let start_l1_block = L1BlockReference::default(); - let start_l1_block_number: L1BlockNumber = start_l1_block.number; - let start_l2_height = BlockNumber(0); - let target_l2_height = BlockNumber(1); - // Setup the state sync client. let mut state_sync_client = MockStateSyncClient::default(); state_sync_client.expect_get_block().returning(move |_| Ok(SyncBlock::default())); @@ -63,7 +63,7 @@ async fn flow_tests() { let finality = 0; let last_l1_block_number = base_layer.ethereum_base_layer.latest_l1_block_number(finality).await.unwrap(); - assert!(last_l1_block_number > start_l1_block_number + NUMBER_OF_BLOCKS_TO_MINE); + assert!(last_l1_block_number > START_L1_BLOCK_NUMBER + NUMBER_OF_BLOCKS_TO_MINE); // Send message from L1 to L2. let l2_contract_address = "0x12"; @@ -91,13 +91,13 @@ async fn flow_tests() { let finality = 0; let last_l1_block_number = base_layer.ethereum_base_layer.latest_l1_block_number(finality).await.unwrap(); - assert!(last_l1_block_number > start_l1_block_number + NUMBER_OF_BLOCKS_TO_MINE); + assert!(last_l1_block_number > START_L1_BLOCK_NUMBER + NUMBER_OF_BLOCKS_TO_MINE); let event_filter = event_identifiers_to_track(); let mut events = base_layer .ethereum_base_layer .events( // Include last block with message. - start_l1_block_number..=last_l1_block_number + 1, + START_L1_BLOCK_NUMBER..=last_l1_block_number + 1, event_filter, ) .await @@ -107,7 +107,7 @@ async fn flow_tests() { // Convert the L1 event to an Apollo event, so we can get the L2 hash. let l1_event_converted = - apollo_l1_provider_types::Event::from_l1_event(&chain_id, l1_event, message_timestamp.0) + apollo_l1_provider_types::Event::from_l1_event(&CHAIN_ID, l1_event, message_timestamp.0) .unwrap(); let Event::L1HandlerTransaction { l1_handler_tx, .. } = l1_event_converted else { panic!("L1 event converted is not a L1 handler transaction"); @@ -133,8 +133,8 @@ async fn flow_tests() { Arc::new(MockBatcherClient::default()), // Consider saving a copy of this to interact Arc::new(state_sync_client), ) - .startup_height(start_l2_height) - .catchup_height(target_l2_height) + .startup_height(START_L2_HEIGHT) + .catchup_height(TARGET_L2_HEIGHT) .build(); // Create the server. @@ -152,7 +152,7 @@ async fn flow_tests() { // Set up the L1 scraper and run it as a server. let l1_scraper_config = L1ScraperConfig { polling_interval_seconds: COOLDOWN_DURATION, - chain_id, + chain_id: CHAIN_ID, ..Default::default() }; let mut scraper = L1Scraper::new( @@ -160,7 +160,7 @@ async fn flow_tests() { Arc::new(l1_provider_client.clone()), base_layer, &[], - start_l1_block, + START_L1_BLOCK, ) .await .expect("Should be able to create the scraper"); @@ -172,7 +172,7 @@ async fn flow_tests() { tokio::time::sleep(WAIT_FOR_L1_DURATION).await; // Test. - let next_block_height = BlockNumber(target_l2_height.0 + 1); + let next_block_height = BlockNumber(TARGET_L2_HEIGHT.0 + 1); // Check that we can validate this message even though no time has passed. l1_provider_client.start_block(SessionState::Validate, next_block_height).await.unwrap(); From e89ba433bbba4754a13edb16b327615bd1a7869d Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Mon, 10 Nov 2025 10:53:25 +0200 Subject: [PATCH 304/313] apollo_integration_tests: generate l1 handler tx that reverts (#9958) --- crates/apollo_integration_tests/src/utils.rs | 6 ++++-- .../tests/end_to_end_flow_test.rs | 3 ++- .../src/starknet_api_test_utils.rs | 19 +++++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/crates/apollo_integration_tests/src/utils.rs b/crates/apollo_integration_tests/src/utils.rs index 82aeabde434..4eb06ae4da6 100644 --- a/crates/apollo_integration_tests/src/utils.rs +++ b/crates/apollo_integration_tests/src/utils.rs @@ -117,9 +117,10 @@ impl TestScenario for ConsensusTxs { tx_generator: &mut MultiAccountTransactionGenerator, account_id: AccountId, ) -> (Vec, Vec) { + const SHOULD_REVERT: bool = false; ( create_invoke_txs(tx_generator, account_id, self.n_invoke_txs), - create_l1_to_l2_messages_args(tx_generator, self.n_l1_handler_txs), + create_l1_to_l2_messages_args(tx_generator, self.n_l1_handler_txs, SHOULD_REVERT), ) } @@ -529,8 +530,9 @@ pub fn create_invoke_txs( pub fn create_l1_to_l2_messages_args( tx_generator: &mut MultiAccountTransactionGenerator, n_txs: usize, + should_revert: bool, ) -> Vec { - (0..n_txs).map(|_| tx_generator.create_l1_to_l2_message_args()).collect() + (0..n_txs).map(|_| tx_generator.create_l1_to_l2_message_args(should_revert)).collect() } pub async fn send_message_to_l2_and_calculate_tx_hash( diff --git a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs index e2b974310c9..826cb113cc7 100644 --- a/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs +++ b/crates/apollo_integration_tests/tests/end_to_end_flow_test.rs @@ -64,7 +64,8 @@ fn create_l1_to_l2_message_args( tx_generator: &mut MultiAccountTransactionGenerator, ) -> Vec { const N_TXS: usize = 1; - create_l1_to_l2_messages_args(tx_generator, N_TXS) + const SHOULD_REVERT: bool = false; + create_l1_to_l2_messages_args(tx_generator, N_TXS, SHOULD_REVERT) } fn create_multiple_account_txs( diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index 9c548d55a15..926346ad06a 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -178,19 +178,26 @@ struct L1HandlerTransactionGenerator { impl L1HandlerTransactionGenerator { const L1_ACCOUNT_ADDRESS: StarkHash = DEFAULT_ANVIL_L1_ACCOUNT_ADDRESS; - /// Creates an L1 handler transaction calling the "l1_handler_set_value" entry point in + /// Creates an L1 handler transaction calling either "l1_handler_set_value" or + /// "l1_handler_set_value_and_revert" entry point in /// [TestContract](FeatureContract::TestContract). - fn create_l1_to_l2_message_args(&mut self) -> L1HandlerTransaction { + fn create_l1_to_l2_message_args(&mut self, should_revert: bool) -> L1HandlerTransaction { self.n_generated_txs += 1; // TODO(Arni): Get test contract from test setup. let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm)); + // TODO(Arni): Consider saving this value as a lazy constant. + let entry_point_selector = if should_revert { + selector_from_name("l1_handler_set_value_and_revert") + } else { + selector_from_name("l1_handler_set_value") + }; + L1HandlerTransaction { contract_address: test_contract.get_instance_address(0), - // TODO(Arni): Consider saving this value as a lazy constant. - entry_point_selector: selector_from_name("l1_handler_set_value"), + entry_point_selector, calldata: calldata![ Self::L1_ACCOUNT_ADDRESS, // Arbitrary key and value. @@ -360,8 +367,8 @@ impl MultiAccountTransactionGenerator { .collect() } - pub fn create_l1_to_l2_message_args(&mut self) -> L1HandlerTransaction { - self.l1_handler_tx_generator.create_l1_to_l2_message_args() + pub fn create_l1_to_l2_message_args(&mut self, should_revert: bool) -> L1HandlerTransaction { + self.l1_handler_tx_generator.create_l1_to_l2_message_args(should_revert) } pub fn n_l1_txs(&self) -> usize { From bf6e30a430c839b1f2a9856f6b508ada7a506402 Mon Sep 17 00:00:00 2001 From: victorkstarkware <160594433+victorkstarkware@users.noreply.github.com> Date: Mon, 10 Nov 2025 14:01:11 +0200 Subject: [PATCH 305/313] apollo_integration_tests: remove executable index from storage path (#10038) --- .github/workflows/hybrid_system_test.yaml | 2 +- .../src/executable_setup.rs | 6 +- .../src/integration_test_manager.rs | 5 +- .../apollo_integration_tests/src/storage.rs | 61 ++++++------------- .../apollo_node/src/test_utils/node_runner.rs | 10 ++- 5 files changed, 26 insertions(+), 58 deletions(-) diff --git a/.github/workflows/hybrid_system_test.yaml b/.github/workflows/hybrid_system_test.yaml index 17ff3780e31..a35619d7a35 100644 --- a/.github/workflows/hybrid_system_test.yaml +++ b/.github/workflows/hybrid_system_test.yaml @@ -364,7 +364,7 @@ jobs: --interval ${{ env.check_interval_sec }} - name: Copy state and restart pod - run: pipenv run python ./scripts/system_tests/copy_state_and_restart.py --deployment_config_path ${{ env.deployment_config_path }} --data-dir "./output/data/node_0/executable_0" + run: pipenv run python ./scripts/system_tests/copy_state_and_restart.py --deployment_config_path ${{ env.deployment_config_path }} --data-dir "./output/data/node_0" - name: Port-forward Anvil pod to localhost:${{ env.anvil_port }} run: | diff --git a/crates/apollo_integration_tests/src/executable_setup.rs b/crates/apollo_integration_tests/src/executable_setup.rs index 293a625fa14..f41371d659a 100644 --- a/crates/apollo_integration_tests/src/executable_setup.rs +++ b/crates/apollo_integration_tests/src/executable_setup.rs @@ -29,22 +29,20 @@ impl NodeExecutionId { self.executable_index } - // TODO(victork): remove path dependency on executable index pub fn build_path(&self, base: &Path) -> PathBuf { base.join(format!("node_{}", self.node_index)) - .join(format!("executable_{}", self.executable_index)) } } impl std::fmt::Display for NodeExecutionId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Node id {} part {}", self.node_index, self.executable_index) + write!(f, "Node id {}", self.node_index) } } impl From for NodeRunner { fn from(val: NodeExecutionId) -> Self { - NodeRunner::new(val.node_index, val.executable_index) + NodeRunner::new(val.node_index) } } diff --git a/crates/apollo_integration_tests/src/integration_test_manager.rs b/crates/apollo_integration_tests/src/integration_test_manager.rs index 0948535ea0e..479f3acbe11 100644 --- a/crates/apollo_integration_tests/src/integration_test_manager.rs +++ b/crates/apollo_integration_tests/src/integration_test_manager.rs @@ -927,7 +927,7 @@ async fn get_sequencer_setup_configs( let batcher_index = node_component_config.get_batcher_index(); let http_server_index = node_component_config.get_http_server_index(); let state_sync_index = node_component_config.get_state_sync_index(); - let class_manager_index = node_component_config.get_class_manager_index(); + let _ = node_component_config.get_class_manager_index(); let consensus_manager_index = node_component_config.get_consensus_manager_index(); let mut consensus_manager_config = consensus_manager_configs.remove(0); @@ -945,9 +945,6 @@ async fn get_sequencer_setup_configs( let storage_setup = get_integration_test_storage( node_index, - batcher_index, - state_sync_index, - class_manager_index, custom_paths.clone(), accounts.to_vec(), &chain_info, diff --git a/crates/apollo_integration_tests/src/storage.rs b/crates/apollo_integration_tests/src/storage.rs index b9c2d3068c6..5880d3b25f5 100644 --- a/crates/apollo_integration_tests/src/storage.rs +++ b/crates/apollo_integration_tests/src/storage.rs @@ -16,52 +16,40 @@ use crate::state_reader::{ #[derive(Debug)] pub struct StorageExecutablePaths { - batcher_path: PathBuf, - state_sync_path: PathBuf, - class_manager_path: PathBuf, + path: PathBuf, } impl StorageExecutablePaths { - pub fn new( - db_base: &Path, - node_index: usize, - batcher_index: usize, - state_sync_index: usize, - class_manager_index: usize, - ) -> Self { - let batcher_node_index = NodeExecutionId::new(node_index, batcher_index); - let state_sync_node_index = NodeExecutionId::new(node_index, state_sync_index); - let class_manager_node_index = NodeExecutionId::new(node_index, class_manager_index); + pub fn new(db_base: &Path, node_index: usize) -> Self { + let node_index = NodeExecutionId::new(node_index, 0); - let batcher_path = batcher_node_index.build_path(db_base); - let state_sync_path = state_sync_node_index.build_path(db_base); - let class_manager_path = class_manager_node_index.build_path(db_base); + let path = node_index.build_path(db_base); - Self { batcher_path, state_sync_path, class_manager_path } + Self { path } } pub fn get_batcher_exec_path(&self) -> &PathBuf { - &self.batcher_path + &self.path } pub fn get_state_sync_exec_path(&self) -> &PathBuf { - &self.state_sync_path + &self.path } pub fn get_class_manager_exec_path(&self) -> &PathBuf { - &self.class_manager_path + &self.path } pub fn get_batcher_path_with_db_suffix(&self) -> PathBuf { - self.batcher_path.join(BATCHER_DB_PATH_SUFFIX) + self.path.join(BATCHER_DB_PATH_SUFFIX) } pub fn get_state_sync_path_with_db_suffix(&self) -> PathBuf { - self.state_sync_path.join(STATE_SYNC_DB_PATH_SUFFIX) + self.path.join(STATE_SYNC_DB_PATH_SUFFIX) } pub fn get_class_manager_path_with_db_suffix(&self) -> PathBuf { - self.class_manager_path.join(CLASS_MANAGER_DB_PATH_SUFFIX) + self.path.join(CLASS_MANAGER_DB_PATH_SUFFIX) } } @@ -86,7 +74,11 @@ impl CustomPaths { } pub fn get_config_path(&self, node_execution_id: &NodeExecutionId) -> Option { - self.config_base.as_ref().map(|p| node_execution_id.build_path(p)) + self.config_base.as_ref().map(|p| { + node_execution_id + .build_path(p) + .join(format!("executable_{}", node_execution_id.get_executable_index())) + }) } pub fn get_data_prefix_path(&self) -> Option<&PathBuf> { @@ -96,23 +88,12 @@ impl CustomPaths { pub fn get_integration_test_storage( node_index: usize, - batcher_index: usize, - state_sync_index: usize, - class_manager_index: usize, custom_paths: Option, accounts: Vec, chain_info: &ChainInfo, ) -> StorageTestSetup { let storage_exec_paths = custom_paths.as_ref().and_then(|paths| { - paths.get_db_base().map(|db_base| { - StorageExecutablePaths::new( - db_base, - node_index, - batcher_index, - state_sync_index, - class_manager_index, - ) - }) + paths.get_db_base().map(|db_base| StorageExecutablePaths::new(db_base, node_index)) }); let StorageTestSetup { mut storage_config, storage_handles } = @@ -121,13 +102,7 @@ pub fn get_integration_test_storage( // Allow overriding the path with a custom prefix for Docker mode in system tests. if let Some(paths) = custom_paths { if let Some(prefix) = paths.get_data_prefix_path() { - let custom_storage_exec_paths = StorageExecutablePaths::new( - prefix, - node_index, - batcher_index, - state_sync_index, - class_manager_index, - ); + let custom_storage_exec_paths = StorageExecutablePaths::new(prefix, node_index); storage_config.batcher_storage_config.db_config.path_prefix = custom_storage_exec_paths.get_batcher_exec_path().join(BATCHER_DB_PATH_SUFFIX); storage_config.state_sync_storage_config.db_config.path_prefix = diff --git a/crates/apollo_node/src/test_utils/node_runner.rs b/crates/apollo_node/src/test_utils/node_runner.rs index 1455e963285..8da58ab9746 100644 --- a/crates/apollo_node/src/test_utils/node_runner.rs +++ b/crates/apollo_node/src/test_utils/node_runner.rs @@ -18,22 +18,20 @@ const TEMP_LOGS_DIR: &str = "integration_test_temporary_logs"; #[derive(Debug, Clone)] pub struct NodeRunner { node_index: usize, - executable_index: usize, } impl NodeRunner { - pub fn new(node_index: usize, executable_index: usize) -> Self { + pub fn new(node_index: usize) -> Self { create_dir_all(TEMP_LOGS_DIR).unwrap(); - Self { node_index, executable_index } + Self { node_index } } pub fn get_description(&self) -> String { - format!("Node id {} part {}:", self.node_index, self.executable_index) + format!("Node id {}:", self.node_index) } pub fn logs_file_path(&self) -> PathBuf { - PathBuf::from(TEMP_LOGS_DIR) - .join(format!("node_{}_part_{}.log", self.node_index, self.executable_index)) + PathBuf::from(TEMP_LOGS_DIR).join(format!("node_{}.log", self.node_index)) } } From 8a88aba78a62b9d8ffa2be85e823d821f9805fdd Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Mon, 10 Nov 2025 14:21:20 +0200 Subject: [PATCH 306/313] apollo_integration_tests: assert on number of reverted transaction flow (#9959) --- .../tests/common/mod.rs | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/crates/apollo_integration_tests/tests/common/mod.rs b/crates/apollo_integration_tests/tests/common/mod.rs index 037d2d60e22..0967f543974 100644 --- a/crates/apollo_integration_tests/tests/common/mod.rs +++ b/crates/apollo_integration_tests/tests/common/mod.rs @@ -31,6 +31,7 @@ pub struct EndToEndFlowArgs { pub test_blocks_scenarios: Vec, pub block_max_capacity_gas: GasAmount, // Used to max both sierra and proving gas. pub expecting_full_blocks: bool, + pub expecting_reverted_transactions: bool, pub allow_bootstrap_txs: bool, } @@ -45,6 +46,7 @@ impl EndToEndFlowArgs { test_blocks_scenarios, block_max_capacity_gas, expecting_full_blocks: false, + expecting_reverted_transactions: false, allow_bootstrap_txs: false, } } @@ -53,6 +55,10 @@ impl EndToEndFlowArgs { Self { expecting_full_blocks: true, ..self } } + pub fn expecting_reverted_transactions(self) -> Self { + Self { expecting_reverted_transactions: true, ..self } + } + pub fn allow_bootstrap_txs(self) -> Self { Self { allow_bootstrap_txs: true, ..self } } @@ -67,6 +73,7 @@ pub async fn end_to_end_flow(args: EndToEndFlowArgs) { test_blocks_scenarios, block_max_capacity_gas, expecting_full_blocks, + expecting_reverted_transactions, allow_bootstrap_txs, } = args; configure_tracing().await; @@ -160,7 +167,12 @@ pub async fn end_to_end_flow(args: EndToEndFlowArgs) { } assert_full_blocks_flow(&global_recorder_handle, expecting_full_blocks); - assert_no_reverted_transactions_flow(&global_recorder_handle); + // TODO(Arni): Remove this once we have a test that expects reverted transactions. + assert!(!expecting_reverted_transactions, "No test should expect reverted transactions."); + assert_on_number_of_reverted_transactions_flow( + &global_recorder_handle, + expecting_reverted_transactions, + ); } pub struct TestScenario { @@ -198,11 +210,27 @@ fn assert_full_blocks_flow(recorder_handle: &PrometheusHandle, expecting_full_bl } } -fn assert_no_reverted_transactions_flow(recorder_handle: &PrometheusHandle) { +fn assert_on_number_of_reverted_transactions_flow( + recorder_handle: &PrometheusHandle, + expecting_reverted_transactions: bool, +) { let metrics = recorder_handle.render(); let reverted_transactions_metric = REVERTED_TRANSACTIONS.parse_numeric_metric::(&metrics).unwrap(); - assert_eq!(reverted_transactions_metric, 0); + + if expecting_reverted_transactions { + assert!( + reverted_transactions_metric > 0, + "Expected reverted transactions, but found {reverted_transactions_metric} reverted \ + transactions." + ); + } else { + assert_eq!( + reverted_transactions_metric, 0, + "Expected no reverted transactions, but found {reverted_transactions_metric} reverted \ + transactions." + ); + } } async fn wait_for_sequencer_node(sequencer: &FlowSequencerSetup) { From 8618b843aa1c2fa467f75b7fd602cb02d5f43d3c Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Mon, 10 Nov 2025 14:50:14 +0200 Subject: [PATCH 307/313] papyrus_base_layer: move latest_proved_block to integration tests (#10043) --- .../tests/latest_proved_block_ethereum.rs | 163 ++++++++++++++++++ .../papyrus_base_layer/src/base_layer_test.rs | 49 +----- 2 files changed, 164 insertions(+), 48 deletions(-) create mode 100644 crates/apollo_integration_tests/tests/latest_proved_block_ethereum.rs diff --git a/crates/apollo_integration_tests/tests/latest_proved_block_ethereum.rs b/crates/apollo_integration_tests/tests/latest_proved_block_ethereum.rs new file mode 100644 index 00000000000..46294fee714 --- /dev/null +++ b/crates/apollo_integration_tests/tests/latest_proved_block_ethereum.rs @@ -0,0 +1,163 @@ +use alloy::providers::Provider; +use apollo_base_layer_tests::anvil_base_layer::{AnvilBaseLayer, MockedStateUpdate}; +use assert_matches::assert_matches; +use papyrus_base_layer::ethereum_base_layer_contract::EthereumBaseLayerError; +use papyrus_base_layer::BaseLayerContract; +use pretty_assertions::assert_eq; +use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; +use starknet_api::hash::StarkHash; + +#[tokio::test] +async fn latest_proved_block_ethereum() { + // State update constants. + const FIRST_ETHEREUM_BLOCK: u64 = 6; + const FIRST_STARKNET_BLOCK_NUMBER: u64 = 2; + const FIRST_STARKNET_BLOCK_HASH: u64 = 0x2; + + const SECOND_ETHEREUM_BLOCK: u64 = 16; + const SECOND_STARKNET_BLOCK_NUMBER: u64 = 3; + const SECOND_STARKNET_BLOCK_HASH: u64 = 0x3; + + const THIRD_ETHEREUM_BLOCK: u64 = 26; + const THIRD_STARKNET_BLOCK_NUMBER: u64 = 4; + const THIRD_STARKNET_BLOCK_HASH: u64 = 0x4; + + const FINAL_ETHEREUM_BLOCK: u64 = 31; + const INITIAL_STARKNET_BLOCK_NUMBER: u64 = 1; + + let initial_state = BlockHashAndNumber { + number: BlockNumber(INITIAL_STARKNET_BLOCK_NUMBER), + hash: BlockHash(StarkHash::from_hex_unchecked("0x0")), + }; + let first_sn_state_update = BlockHashAndNumber { + number: BlockNumber(FIRST_STARKNET_BLOCK_NUMBER), + hash: BlockHash(StarkHash::from_hex_unchecked(&format!( + "{:#x}", + FIRST_STARKNET_BLOCK_HASH + ))), + }; + let second_sn_state_update = BlockHashAndNumber { + number: BlockNumber(SECOND_STARKNET_BLOCK_NUMBER), + hash: BlockHash(StarkHash::from_hex_unchecked(&format!( + "{:#x}", + SECOND_STARKNET_BLOCK_HASH + ))), + }; + let third_sn_state_update = BlockHashAndNumber { + number: BlockNumber(THIRD_STARKNET_BLOCK_NUMBER), + hash: BlockHash(StarkHash::from_hex_unchecked(&format!( + "{:#x}", + THIRD_STARKNET_BLOCK_HASH + ))), + }; + + let base_layer = AnvilBaseLayer::new(None).await; + let provider = &base_layer.anvil_provider; + + let mut current_block = provider.get_block_number().await.expect("Failed to get block number"); + let mut prev_starknet_block_hash = 0u64; + + // Apply state updates. + if current_block < FIRST_ETHEREUM_BLOCK - 1 { + let blocks_to_mine = FIRST_ETHEREUM_BLOCK - 1 - current_block; + let _result: Option = provider + .raw_request("anvil_mine".into(), [blocks_to_mine]) + .await + .expect("Failed to mine blocks on Anvil"); + } + base_layer + .update_mocked_starknet_contract_state(MockedStateUpdate { + new_block_number: FIRST_STARKNET_BLOCK_NUMBER, + new_block_hash: FIRST_STARKNET_BLOCK_HASH, + prev_block_hash: prev_starknet_block_hash, + }) + .await + .expect("Failed to update state"); + current_block = FIRST_ETHEREUM_BLOCK; + prev_starknet_block_hash = FIRST_STARKNET_BLOCK_HASH; + + if current_block < SECOND_ETHEREUM_BLOCK - 1 { + let blocks_to_mine = SECOND_ETHEREUM_BLOCK - 1 - current_block; + let _result: Option = provider + .raw_request("anvil_mine".into(), [blocks_to_mine]) + .await + .expect("Failed to mine blocks on Anvil"); + } + base_layer + .update_mocked_starknet_contract_state(MockedStateUpdate { + new_block_number: SECOND_STARKNET_BLOCK_NUMBER, + new_block_hash: SECOND_STARKNET_BLOCK_HASH, + prev_block_hash: prev_starknet_block_hash, + }) + .await + .expect("Failed to update state"); + current_block = SECOND_ETHEREUM_BLOCK; + prev_starknet_block_hash = SECOND_STARKNET_BLOCK_HASH; + + if current_block < THIRD_ETHEREUM_BLOCK - 1 { + let blocks_to_mine = THIRD_ETHEREUM_BLOCK - 1 - current_block; + let _result: Option = provider + .raw_request("anvil_mine".into(), [blocks_to_mine]) + .await + .expect("Failed to mine blocks on Anvil"); + } + base_layer + .update_mocked_starknet_contract_state(MockedStateUpdate { + new_block_number: THIRD_STARKNET_BLOCK_NUMBER, + new_block_hash: THIRD_STARKNET_BLOCK_HASH, + prev_block_hash: prev_starknet_block_hash, + }) + .await + .expect("Failed to update state"); + current_block = THIRD_ETHEREUM_BLOCK; + + // Mine to the final Ethereum block. + if current_block < FINAL_ETHEREUM_BLOCK { + let blocks_to_mine = FINAL_ETHEREUM_BLOCK - current_block; + let _result: Option = provider + .raw_request("anvil_mine".into(), [blocks_to_mine]) + .await + .expect("Failed to mine blocks on Anvil"); + } + + // Finality constants: finality = FINAL_ETHEREUM_BLOCK - target_block + const FINALITY_LATEST_ETHEREUM_BLOCK: u64 = 0; + const FINALITY_AT_THIRD_UPDATE: u64 = FINAL_ETHEREUM_BLOCK - THIRD_ETHEREUM_BLOCK; + const FINALITY_AFTER_SECOND_BEFORE_THIRD: u64 = FINAL_ETHEREUM_BLOCK - THIRD_ETHEREUM_BLOCK + 1; + const FINALITY_AT_SECOND_UPDATE: u64 = FINAL_ETHEREUM_BLOCK - SECOND_ETHEREUM_BLOCK; + const FINALITY_AFTER_FIRST_BEFORE_SECOND: u64 = + FINAL_ETHEREUM_BLOCK - SECOND_ETHEREUM_BLOCK + 1; + const FINALITY_AT_FIRST_UPDATE: u64 = FINAL_ETHEREUM_BLOCK - FIRST_ETHEREUM_BLOCK; + const FINALITY_BEFORE_FIRST_UPDATE: u64 = FINAL_ETHEREUM_BLOCK - FIRST_ETHEREUM_BLOCK + 1; + const FINALITY_ERROR_CASE: u64 = FINAL_ETHEREUM_BLOCK + 10; // Error: finality too high + + type Scenario = (u64, Option); + let scenarios: Vec = vec![ + (FINALITY_LATEST_ETHEREUM_BLOCK, Some(third_sn_state_update)), + (FINALITY_AT_THIRD_UPDATE, Some(third_sn_state_update)), + (FINALITY_AFTER_SECOND_BEFORE_THIRD, Some(second_sn_state_update)), + (FINALITY_AT_SECOND_UPDATE, Some(second_sn_state_update)), + (FINALITY_AFTER_FIRST_BEFORE_SECOND, Some(first_sn_state_update)), + (FINALITY_AT_FIRST_UPDATE, Some(first_sn_state_update)), + (FINALITY_BEFORE_FIRST_UPDATE, Some(initial_state)), + (FINALITY_ERROR_CASE, None), + ]; + + for (finality, expected) in scenarios { + let latest_block = base_layer.latest_proved_block(finality).await; + match latest_block { + Ok(latest_block) => { + assert_eq!(latest_block, expected, "Failed at finality {}", finality) + } + Err(e) => { + assert_matches!( + e, + EthereumBaseLayerError::LatestBlockNumberReturnedTooLow(_, _), + "Expected error at finality {} but got: {:?}", + finality, + e + ); + } + } + } +} diff --git a/crates/papyrus_base_layer/src/base_layer_test.rs b/crates/papyrus_base_layer/src/base_layer_test.rs index e7271f7e46c..23970b42624 100644 --- a/crates/papyrus_base_layer/src/base_layer_test.rs +++ b/crates/papyrus_base_layer/src/base_layer_test.rs @@ -3,18 +3,10 @@ use alloy::primitives::B256; use alloy::providers::mock::Asserter; use alloy::providers::{Provider, ProviderBuilder}; use alloy::rpc::types::{Block, BlockTransactions, Header as AlloyRpcHeader}; -use assert_matches::assert_matches; use pretty_assertions::assert_eq; -use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockNumber}; -use starknet_api::felt; use url::Url; -use crate::ethereum_base_layer_contract::{ - EthereumBaseLayerConfig, - EthereumBaseLayerContract, - EthereumBaseLayerError, - Starknet, -}; +use crate::ethereum_base_layer_contract::{EthereumBaseLayerContract, Starknet}; use crate::BaseLayerContract; // TODO(Gilad): Use everywhere instead of relying on the confusing `#[ignore]` api to mark slow @@ -38,45 +30,6 @@ fn base_layer_with_mocked_provider() -> (EthereumBaseLayerContract, Asserter) { (base_layer, asserter) } -#[tokio::test] -// Note: the test requires ganache-cli installed, otherwise it is ignored. -async fn latest_proved_block_ethereum() { - if !in_ci() { - return; - } - #[allow(deprecated)] // Legacy code, will be removed soon, don't add new instances if this. - let (node_handle, starknet_contract_address) = crate::test_utils::get_test_ethereum_node(); - let contract = EthereumBaseLayerContract::new( - EthereumBaseLayerConfig { starknet_contract_address, ..Default::default() }, - node_handle.0.endpoint().parse().unwrap(), - ); - - let first_sn_state_update = - BlockHashAndNumber { number: BlockNumber(100), hash: BlockHash(felt!("0x100")) }; - let second_sn_state_update = - BlockHashAndNumber { number: BlockNumber(200), hash: BlockHash(felt!("0x200")) }; - let third_sn_state_update = - BlockHashAndNumber { number: BlockNumber(300), hash: BlockHash(felt!("0x300")) }; - - type Scenario = (u64, Option); - let scenarios: Vec = vec![ - (0, Some(third_sn_state_update)), - (5, Some(third_sn_state_update)), - (15, Some(second_sn_state_update)), - (25, Some(first_sn_state_update)), - (1000, None), - ]; - for (scenario, expected) in scenarios { - let latest_block = contract.latest_proved_block(scenario).await; - match latest_block { - Ok(latest_block) => assert_eq!(latest_block, expected), - Err(e) => { - assert_matches!(e, EthereumBaseLayerError::LatestBlockNumberReturnedTooLow(_, _)) - } - } - } -} - #[tokio::test] async fn get_gas_price_and_timestamps() { if !in_ci() { From 5e910a90c4e11c46825c23e31339509253b8a15d Mon Sep 17 00:00:00 2001 From: ShahakShama <70578257+ShahakShama@users.noreply.github.com> Date: Mon, 10 Nov 2025 14:51:33 +0200 Subject: [PATCH 308/313] apollo_dashboard: remove p2p sync row (#10061) --- .../resources/dev_grafana.json | 138 +++++++----------- .../src/dashboard_definitions.rs | 5 +- .../apollo_dashboard/src/panels/state_sync.rs | 28 ---- 3 files changed, 55 insertions(+), 116 deletions(-) diff --git a/crates/apollo_dashboard/resources/dev_grafana.json b/crates/apollo_dashboard/resources/dev_grafana.json index 35f9e4f9127..74e1c5ce3e7 100644 --- a/crates/apollo_dashboard/resources/dev_grafana.json +++ b/crates/apollo_dashboard/resources/dev_grafana.json @@ -1121,55 +1121,83 @@ ], "collapsed": true }, - "Reverts": { + "MempoolP2p": { "panels": [ { - "title": "apollo_consensus_reverted_batcher_up_to_and_including", - "description": "The block number up to which the batcher has reverted", - "type": "stat", + "title": "apollo_mempool_p2p_num_connected_peers", + "description": "The number of connected peers to the mempool p2p component", + "type": "timeseries", "exprs": [ - "apollo_consensus_reverted_batcher_up_to_and_including{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + "apollo_mempool_p2p_num_connected_peers{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], "extra_params": {} }, { - "title": "apollo_state_sync_reverted_up_to_and_including", - "description": "The block number up to which the state sync has reverted", - "type": "stat", + "title": "apollo_mempool_p2p_num_sent_messages", + "description": "The number of messages sent by the mempool p2p component", + "type": "timeseries", "exprs": [ - "apollo_state_sync_reverted_up_to_and_including{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + "apollo_mempool_p2p_num_sent_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], "extra_params": {} - } - ], - "collapsed": true - }, - "StateSyncP2p": { - "panels": [ + }, { - "title": "apollo_p2p_sync_num_connected_peers", - "description": "The number of connected peers to the p2p sync component", - "type": "stat", + "title": "apollo_mempool_p2p_num_received_messages", + "description": "The number of messages received by the mempool p2p component", + "type": "timeseries", + "exprs": [ + "apollo_mempool_p2p_num_received_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + ], + "extra_params": {} + }, + { + "title": "Mempool P2p Broadcasted Transaction Batch Size", + "description": "The number of transactions in batches broadcast by the mempool p2p component", + "type": "timeseries", + "exprs": [ + "histogram_quantile(0.50, sum by (le) (rate(apollo_mempool_p2p_broadcasted_transaction_batch_size_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))", + "histogram_quantile(0.95, sum by (le) (rate(apollo_mempool_p2p_broadcasted_transaction_batch_size_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))" + ], + "extra_params": {} + }, + { + "title": "apollo_mempool_p2p_network_events", + "description": "Network events counter by event type for mempool p2p", + "type": "timeseries", "exprs": [ - "apollo_p2p_sync_num_connected_peers{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + "sum by (event_type) (apollo_mempool_p2p_network_events{cluster=~\"$cluster\", namespace=~\"$namespace\"})" ], "extra_params": {} }, { - "title": "apollo_p2p_sync_num_active_inbound_sessions", - "description": "The number of inbound sessions to the p2p sync component", + "title": "apollo_mempool_p2p_num_dropped_messages", + "description": "The number of messages dropped by the mempool p2p component", + "type": "timeseries", + "exprs": [ + "sum by (drop_reason) (apollo_mempool_p2p_num_dropped_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"})" + ], + "extra_params": {} + } + ], + "collapsed": true + }, + "Reverts": { + "panels": [ + { + "title": "apollo_consensus_reverted_batcher_up_to_and_including", + "description": "The block number up to which the batcher has reverted", "type": "stat", "exprs": [ - "apollo_p2p_sync_num_active_inbound_sessions{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + "apollo_consensus_reverted_batcher_up_to_and_including{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], "extra_params": {} }, { - "title": "apollo_p2p_sync_num_active_outbound_sessions", - "description": "The number of outbound sessions to the p2p sync component", + "title": "apollo_state_sync_reverted_up_to_and_including", + "description": "The block number up to which the state sync has reverted", "type": "stat", "exprs": [ - "apollo_p2p_sync_num_active_outbound_sessions{cluster=~\"$cluster\", namespace=~\"$namespace\"}" + "apollo_state_sync_reverted_up_to_and_including{cluster=~\"$cluster\", namespace=~\"$namespace\"}" ], "extra_params": {} } @@ -1232,66 +1260,6 @@ ], "collapsed": true }, - "MempoolP2p": { - "panels": [ - { - "title": "apollo_mempool_p2p_num_connected_peers", - "description": "The number of connected peers to the mempool p2p component", - "type": "timeseries", - "exprs": [ - "apollo_mempool_p2p_num_connected_peers{cluster=~\"$cluster\", namespace=~\"$namespace\"}" - ], - "extra_params": {} - }, - { - "title": "apollo_mempool_p2p_num_sent_messages", - "description": "The number of messages sent by the mempool p2p component", - "type": "timeseries", - "exprs": [ - "apollo_mempool_p2p_num_sent_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}" - ], - "extra_params": {} - }, - { - "title": "apollo_mempool_p2p_num_received_messages", - "description": "The number of messages received by the mempool p2p component", - "type": "timeseries", - "exprs": [ - "apollo_mempool_p2p_num_received_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"}" - ], - "extra_params": {} - }, - { - "title": "Mempool P2p Broadcasted Transaction Batch Size", - "description": "The number of transactions in batches broadcast by the mempool p2p component", - "type": "timeseries", - "exprs": [ - "histogram_quantile(0.50, sum by (le) (rate(apollo_mempool_p2p_broadcasted_transaction_batch_size_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))", - "histogram_quantile(0.95, sum by (le) (rate(apollo_mempool_p2p_broadcasted_transaction_batch_size_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\"}[5m])))" - ], - "extra_params": {} - }, - { - "title": "apollo_mempool_p2p_network_events", - "description": "Network events counter by event type for mempool p2p", - "type": "timeseries", - "exprs": [ - "sum by (event_type) (apollo_mempool_p2p_network_events{cluster=~\"$cluster\", namespace=~\"$namespace\"})" - ], - "extra_params": {} - }, - { - "title": "apollo_mempool_p2p_num_dropped_messages", - "description": "The number of messages dropped by the mempool p2p component", - "type": "timeseries", - "exprs": [ - "sum by (drop_reason) (apollo_mempool_p2p_num_dropped_messages{cluster=~\"$cluster\", namespace=~\"$namespace\"})" - ], - "extra_params": {} - } - ], - "collapsed": true - }, "Tokio Runtime Metrics": { "panels": [ { diff --git a/crates/apollo_dashboard/src/dashboard_definitions.rs b/crates/apollo_dashboard/src/dashboard_definitions.rs index e642e51056f..192942e54c4 100644 --- a/crates/apollo_dashboard/src/dashboard_definitions.rs +++ b/crates/apollo_dashboard/src/dashboard_definitions.rs @@ -32,7 +32,7 @@ use crate::panels::mempool_p2p::get_mempool_p2p_row; use crate::panels::pod_metrics::get_pod_metrics_row; use crate::panels::reverts::get_reverts_row; use crate::panels::sierra_compiler::get_compile_to_casm_row; -use crate::panels::state_sync::{get_state_sync_p2p_row, get_state_sync_row}; +use crate::panels::state_sync::get_state_sync_row; use crate::panels::storage::get_storage_row; use crate::panels::tokio::get_tokio_row; @@ -74,10 +74,9 @@ pub fn get_apollo_dashboard() -> Dashboard { get_blockifier_row(), get_compile_to_casm_row(), get_consensus_p2p_row(), + get_mempool_p2p_row(), get_reverts_row(), - get_state_sync_p2p_row(), get_storage_row(), - get_mempool_p2p_row(), get_tokio_row(), get_component_infra_row("Batcher Infra", &BATCHER_INFRA_METRICS), get_component_infra_row("State Sync Infra", &STATE_SYNC_INFRA_METRICS), diff --git a/crates/apollo_dashboard/src/panels/state_sync.rs b/crates/apollo_dashboard/src/panels/state_sync.rs index b306ba42e5a..c54397a7b2f 100644 --- a/crates/apollo_dashboard/src/panels/state_sync.rs +++ b/crates/apollo_dashboard/src/panels/state_sync.rs @@ -1,9 +1,6 @@ use apollo_metrics::MetricCommon; use apollo_state_sync_metrics::metrics::{ CENTRAL_SYNC_CENTRAL_BLOCK_MARKER, - P2P_SYNC_NUM_ACTIVE_INBOUND_SESSIONS, - P2P_SYNC_NUM_ACTIVE_OUTBOUND_SESSIONS, - P2P_SYNC_NUM_CONNECTED_PEERS, STATE_SYNC_BODY_MARKER, STATE_SYNC_CLASS_MANAGER_MARKER, STATE_SYNC_HEADER_LATENCY_SEC, @@ -11,20 +8,6 @@ use apollo_state_sync_metrics::metrics::{ use crate::dashboard::{Panel, PanelType, Row, Unit}; -// P2P panels - -fn get_panel_p2p_sync_num_connected_peers() -> Panel { - Panel::from_gauge(&P2P_SYNC_NUM_CONNECTED_PEERS, PanelType::Stat) -} -fn get_panel_p2p_sync_num_active_inbound_sessions() -> Panel { - Panel::from_gauge(&P2P_SYNC_NUM_ACTIVE_INBOUND_SESSIONS, PanelType::Stat) -} -fn get_panel_p2p_sync_num_active_outbound_sessions() -> Panel { - Panel::from_gauge(&P2P_SYNC_NUM_ACTIVE_OUTBOUND_SESSIONS, PanelType::Stat) -} - -// State Sync panels - fn get_panel_central_sync_central_block_marker() -> Panel { Panel::new( "Central Block Marker", @@ -74,14 +57,3 @@ pub(crate) fn get_state_sync_row() -> Row { ], ) } - -pub(crate) fn get_state_sync_p2p_row() -> Row { - Row::new( - "StateSyncP2p", - vec![ - get_panel_p2p_sync_num_connected_peers(), - get_panel_p2p_sync_num_active_inbound_sessions(), - get_panel_p2p_sync_num_active_outbound_sessions(), - ], - ) -} From b4bbba14ea00f1b88cac45a1b8cf7ba80d0f12f7 Mon Sep 17 00:00:00 2001 From: dan-starkware <56217775+dan-starkware@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:22:44 +0200 Subject: [PATCH 309/313] papyrus_base_layer: remove ganache (#10049) --- .github/workflows/main.yml | 8 --- .github/workflows/main_nightly.yml | 5 -- .github/workflows/papyrus_nightly-tests.yml | 1 - .github/workflows/verify-deps.yml | 1 - Cargo.lock | 38 ---------- Cargo.toml | 2 - crates/papyrus_base_layer/Cargo.toml | 8 +-- .../resources/ganache-db.tar | Bin 307200 -> 0 bytes crates/papyrus_base_layer/src/test_utils.rs | 68 ------------------ docs/papyrus/CONTRIBUTING.md | 3 - 10 files changed, 1 insertion(+), 133 deletions(-) delete mode 100644 crates/papyrus_base_layer/resources/ganache-db.tar diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9e32359d70c..0827de2038b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -129,10 +129,6 @@ jobs: run: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV - run: pip install -r scripts/requirements.txt - # TODO(Gilad): only one test needs this (base_layer_test.rs), once it migrates to - # anvil, remove. - - run: npm install -g ganache@7.4.3 - - name: "Run tests pull request" if: github.event_name == 'pull_request' run: | @@ -171,10 +167,6 @@ jobs: run: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV - run: pip install -r scripts/requirements.txt - # TODO(Gilad): only one test needs this (base_layer_test.rs), once it migrates to - # anvil, remove. - - run: npm install -g ganache@7.4.3 - - name: "Run integration tests pull request" if: github.event_name == 'pull_request' run: | diff --git a/.github/workflows/main_nightly.yml b/.github/workflows/main_nightly.yml index 49fa0c43ca4..444e5ce1a8c 100644 --- a/.github/workflows/main_nightly.yml +++ b/.github/workflows/main_nightly.yml @@ -30,7 +30,6 @@ jobs: - uses: ./.github/actions/bootstrap with: github_token: ${{ secrets.GITHUB_TOKEN }} - - run: npm install -g ganache@7.4.3 - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov @@ -115,10 +114,6 @@ jobs: LD_LIBRARY_PATH: ${{ env.Python3_ROOT_DIR }}/bin run: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV - run: pip install -r scripts/requirements.txt - # TODO(Gilad): only one test needs this (base_layer_test.rs), once it migrates to - # anvil, remove. - - run: npm install -g ganache@7.4.3 - - name: "Run integration tests pull request" run: | scripts/run_tests.py --command integration --is_nightly diff --git a/.github/workflows/papyrus_nightly-tests.yml b/.github/workflows/papyrus_nightly-tests.yml index 93c96a99c6d..b29c033f7a8 100644 --- a/.github/workflows/papyrus_nightly-tests.yml +++ b/.github/workflows/papyrus_nightly-tests.yml @@ -59,7 +59,6 @@ jobs: - uses: ./.github/actions/bootstrap with: github_token: ${{ secrets.GITHUB_TOKEN }} - - run: npm install -g ganache@7.4.3 - run: | cargo test -p papyrus_node diff --git a/.github/workflows/verify-deps.yml b/.github/workflows/verify-deps.yml index 6e21c1e4488..1e166f3a0e7 100644 --- a/.github/workflows/verify-deps.yml +++ b/.github/workflows/verify-deps.yml @@ -16,7 +16,6 @@ jobs: - uses: ./.github/actions/bootstrap with: github_token: ${{ secrets.GITHUB_TOKEN }} - - run: npm install -g ganache@7.4.3 - name: Update Dependencies run: cargo update --verbose - name: Build diff --git a/Cargo.lock b/Cargo.lock index 6351be8c2fa..bc9564e81ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6201,18 +6201,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "filetime" -version = "0.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.60.2", -] - [[package]] name = "fixed-hash" version = "0.8.0" @@ -8606,7 +8594,6 @@ checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ "bitflags 2.9.3", "libc", - "redox_syscall 0.5.17", ] [[package]] @@ -9731,8 +9718,6 @@ dependencies = [ "apollo_l1_endpoint_monitor_types", "assert_matches", "async-trait", - "ethers", - "ethers-core", "futures", "hex", "mockall", @@ -9740,8 +9725,6 @@ dependencies = [ "serde", "starknet-types-core", "starknet_api", - "tar", - "tempfile", "thiserror 1.0.69", "tokio", "tracing", @@ -12990,17 +12973,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "tar" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "target-lexicon" version = "0.12.16" @@ -14826,16 +14798,6 @@ dependencies = [ "time", ] -[[package]] -name = "xattr" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" -dependencies = [ - "libc", - "rustix 1.0.8", -] - [[package]] name = "xml-rs" version = "0.8.27" diff --git a/Cargo.toml b/Cargo.toml index a73a7070f39..c432c73006f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -250,7 +250,6 @@ enum-as-inner = "0.6.1" enum-assoc = "1.1.0" enum-iterator = "1.4.1" ethers = "2.0.3" -ethers-core = "2.0.3" ethnum = "1.5.0" expect-test = "1.5.1" flate2 = "1.0.24" @@ -361,7 +360,6 @@ statistical = "1.0.0" strum = "0.25.0" strum_macros = "0.25.2" syn = "2.0.39" -tar = "0.4.38" tempfile = "3.7.0" test-case = "3.2.1" test-log = "0.2.14" diff --git a/crates/papyrus_base_layer/Cargo.toml b/crates/papyrus_base_layer/Cargo.toml index 4b8a088cff7..be307a0fb89 100644 --- a/crates/papyrus_base_layer/Cargo.toml +++ b/crates/papyrus_base_layer/Cargo.toml @@ -9,22 +9,19 @@ license-file.workspace = true workspace = true [features] -testing = ["alloy/node-bindings", "tar", "tempfile"] +testing = ["alloy/node-bindings"] [dependencies] alloy = { workspace = true, features = ["contract", "json-rpc", "node-bindings", "rpc-types"] } apollo_config.workspace = true apollo_l1_endpoint_monitor_types.workspace = true async-trait.workspace = true -ethers.workspace = true futures.workspace = true hex.workspace = true mockall.workspace = true serde.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true -tar = { workspace = true, optional = true } -tempfile = { workspace = true, optional = true } thiserror.workspace = true tokio = { workspace = true, features = ["full", "sync"] } tracing.workspace = true @@ -34,9 +31,6 @@ validator.workspace = true [dev-dependencies] apollo_l1_endpoint_monitor_types = { workspace = true, features = ["testing"] } assert_matches.workspace = true -ethers-core.workspace = true pretty_assertions.workspace = true starknet-types-core.workspace = true starknet_api = { workspace = true, features = ["testing"] } -tar.workspace = true -tempfile.workspace = true diff --git a/crates/papyrus_base_layer/resources/ganache-db.tar b/crates/papyrus_base_layer/resources/ganache-db.tar deleted file mode 100644 index f9a64daef4310ff834b7b56664b3fdd1c707e91c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 307200 zcmeEv1zc3w_xQXSI;25BU#R4Uj7=}_&nI|@`0b(mtgaHmAwhn^W-G$h(wy3O) zD<}UAs>jH+aJE^uaww|1t(o z!^e$ID_=aTQiXz1X{r>Og2MMPN#^_yVxSrS6TIlTRvyQH;(rf!KQC_|ZwdeV z`S~LG@8#~{PV#>%PlL?nZuHPFTMGOy&P3mswPl#6qZdQ4?6=mP3#U)p za^pCys*bWF_7vBy)0B5L3jMRn$Gj+dUb+&)sA3>#5+K*kzRsS_qwU4thus}-Ipxs= ztyNvmbrUpLN5TD>T1)vXLg;>+TC5h&`{HD&CR~4E81S-V~d8R&5R!S3L&S{n1_lT)?M3= z`}uUzT9T)~EOJl5!%EjlA@@`dT)&^SyH$}h#4*poyYv1~bxQ8**R`&P%{)fE`+Z^J zz&oFh%wTV}$x3e=`$NbP${U#&e?Nk}f!jJ>PsA|guaTF6ZC&KLsywoBlMhb6K4@p| z0}E#D)e83|nyyLNpC0^*kk?`SwV0V5yX;q*cHHrRFfVk#m7vU1CBL~IZhG)!1??2x zs>lmC7vx^QCfzURLPbnm+3x4tStt81_3UZAJ5xz@dq=%aMOb4&>tRnQZ~Scbk6<^e zw(iCR3{(9YyTg`zT`kze5^eHG_bYqR|C3>ZG5s$}($!h!0G_7o%_?0TBLc-Owr z^1NgD+)QUdcqJ(N@{%F1dbFoMDXG(4 zJ0rnos3m)hW1M%>R;+RJk6>3QZ)872yRC$MgQac5=3$un*VsRFe8CPijVtS_owW^O z?9(2OY@2${cvO~>`FOrtr>TuBg0|;VuRJxe-xU6+`ctg;QGwfU`zS~3El;>{pShH( zKT>H`?A!KP=A?di=r6V-?|rJw=$BPLr>LUFNasoFPNwrE?=k#KSmTACgMFbq+<<6l zrP&!9acb^P4AcC2c3d^H4_AIP%1rD@UzfrT_RJMbcogrcQG}n--g$a-Z&frqo&7h> zQ%|3fGN?mo5u_(zj+w_wA0}ZH}y?M;f>4>~uV-_WI2x)sd?|)+8wnP3p3~ z&h|ikL3rWlZ2H!)?d$ViVvR5UF0&()hrQOCy@%u5xE!QnTH@J5%QQmic33$33{9m^ zh1a;AU1pk?bgZ}VeG_$RiRRQ@%qcYe$^mHh=s#1k(dH_x?pjcKyOdGJdonp^?f&HL z<`rE&R~qN<>c3MxIh+8ExJc`!2qiJ3m!1q|20v-3O}#^;JM75?d$_k4VJ}<&8~j2e8@1 z)I5()?7ZT)-)lNPvuxk}sU7l%LGZekUk*sD{Ats&id{6R<|U%{4+d;B*p z=o;i-+w=K{pmTW(JXS8+@Y_3mvo^s>wH~cXHokoI>_I{1^Il(l_M6R=i>G)K4vuRd zH~aANXUg4umMGU2Q=2fI9}+|VnCTPBnOb3N##wE;wX;*dZ=Ml`r;RN2&wQh7fu}}_WHF`V^QDWw$WCWF%Ob{xtpeL=zqZ> z^xVY(3hCo)2!NjYWZ5zr@+QwoKfWh?-&L1+PaCg#Oq$-;&OUxoc099H>Fqa_g~zMQ z^%S&%&AiXK^h{3p-MinE7&_BXF==Xd)jbY`m_kBG9x728d7~2xDnd-z7Hh^Wwy7{S zwRN#(=pGxoX49t58%IwVzAkEwW4p?2PyT^~E)Ul~K-Tr=V#Oa?mC$cx zKaTfs&lsv_8+Q5l+>tv}T!ztJUO!oz>T*%tQ)9J1v1K6-YN@6b%0oC&k|1>TJqk|6 z?@J>>=X5pjS8Gc@n{xl&?X=GOLe0D6xRzG*YehnrH^!f(kXwP!uQa&&1EHIJP3TVR zdb?(8RWI)5eamt5vXx4YO|EJM7L~5%`rkbNo0C!!L03OhVb9bYpX0dqM6X%-d(KbU zaQyxyg^nNG2Iks!C>f#Ul&*Z20I2%6LAQ+$_Q~t~&?jjAt3OU%?|7B6(O}Pr?u~DP zBJ9q$Dxt5we_Au9@K@SMo4DiWj6cV&eUWX-Q1GAPr?-#d-*;NBM542W@^Fc0SSW9N zUkIJj-#yvRWNFm)L7%-os_9>+tgqai;XkO&h^65H`PWKy{*8n#Z!*|yWtVpM8ZpfB zYs*wWIN;JK_brTzNtX{ta^`jz=W;ZHZgk{{#oAr>lG8E@5M6b9*Jgt)yTiHF{6Uk= zlzb|8jk>mM=XT1lIUX~Z8t<0YwJKc=*nZ_ew}Le+*8x-G`t?2dtgYw#Wqr^7VtHgc zbJ6xms(%|p}bjSV+Zy}6i_j1@$^g2AZkYqP2Z8+Ftz(E<$%d9 zuA%dE4F?;Pmv=qgIVkArv}kWatc)6c>iOYiigg8aebsIq3Ww+HouWG+X4{h6+ZNG& zAIWId>0hyK(B1_XS0e9TIi0O8~XQc1l=ac}*_b)g}Z+YZ;0{c_)s2qLwYCR&$^CYql~F^J^jjl_;RPzKk9Af`4*389JZ{>Pu$Ut z$nQP0mv>lUS?2J%j{Rp?esZzdkmz~kkMfhhnR$$#9*yAf?tee4OTbXxj_n$Lv)9~xkfR;7ic5_gSA03WRFH1@;OPds&oiebS{7$j z2s2Y25(!2km`UF7h?2y_+_L@EH2Sy2kzKF$?>V%{ymNb7#p74KY)i$QzBUU4iRnJdoQ*VvcC_m+m4_%6nJn4=IPORZUOKYvo!cK4A-&+f z>EevXmS(5&sTzw<9KEu~EpT*gaz){`vHbGgAzLgXTb1C~^sJuuI^Sf-9M_IlV@^gF zY|M^HSlQTbxqH~tJMTJ~j;sc=Am)e6g1^J`3+3VWM@~h40(tcA8ufbzD(3Pvc{r#{ z>9p#o?ovZ@=iLc|v?B98%96Y3bv7SD3u&JCTJV}mmv zobDfO-hE_Y?fB`tvV^Tl9t-=$c4K5euI7Yapygi*N~)jn+(!M*txXSN`}aMyXi>;3 zAdj*CCh`!_3WdcS?^RG4yEdCs6!C40M< z?LX6g(5~plNcIe0pOfp4-V#zM|Nrm15q9El-O|S|_0OE~M)7yIi}?kkPt--#_8If$ z(%9#08;5P&hr~Lr_3T8UJWL=SAOL&!+4jP4t(h0@&DJ=vq=&-*w(*N;qvx2~tDPA) zZEeuX*dHfwc|-gecBJqhLf{=V=dbET!+gaAF4YvQiAOJ)&MZ6nD6Q|NfG$^K`HsBP zuML9o+$!&_oX&bOn-I)D)6h^-8q&kQBldLBn|7Qd4=SrYg5m=X|1mPa+U(ttw&(A7 z5FB^wJ)OG!#PnOL%Z7Eh+Yq>fxqsLEI=?P$_iLPvJ$3%gU&C>Z2aSIz-gK(N?h{LP z?mf+4-Q(0zkBS&}sp?~caR+SPxgwPz51lPkhEU#E#T=!*Z-7GC`OX?6)Tz@qQ94hp zzd7iPO4aFSrGrx+ggnXg`1f&?ys7vZw%5kA#RGw({J-WXm7of4)Tf+Y_z`wvo~csD ziE5=Ip6|IlXdLas^om2{wh$ckGdFxy51)IZ7q_NyrsC0cj!xZ66K$4<>n|PXbt208 zd2NVOM}ni8;xxwQ9xr@0s(Zo91HT^G{%)U1)w#4rN4+(?%Wiv){WTo5KTpYWNMgSO z8w&d@xqLX_?Z8)a6*OXCa%DB1SyK_9Q5;D(`3)9-Y-;J8ebk`(cQHeeQTpa-R8k-=&M2Cm#9mi_Wr+ z6NJ$;rRYUIsoNF?nY{dK2>791(A19;?=IQcyR*{7Uq2mVbGNb57sX6hKA^ekvfg#K zVp1?9kkWcTZSb&($q{jZW*(1)TM&& zE0m9x_{BLidTz6?(|hvaB_Sv)&X}u?+uQHj?S(!MZH}zd^whs#NHw#5RlZ=sf(aet z{u(;lXqmM|Gi^!!#8nK6){JgtO}oPe^cb;r)rK=?YkcP}Jt{f0X|=Opp*&oOO_N8P zkJmVA-|K6nvgG1`$N;r~d9zm1m>k8uz3i&0H^2BmGC)f|47Tw9p8@0%gHSF5`0dqj z0|w~vH3QV_a4o)GcXRKod#?&!^r#>0bWnNDqVU1P9;vrgXvY&~5DZ}Tb|3rBik_KQ z_U077;q2q|t}ZyBJ)kW5LiYZi>cKgG4Fl-SsOWZg$-&JO+LcPhyb^DxJs+lB9QC%| zTzyXFhu%fcfdPKV_7=(;qQsK;QQMq$Ds-}cLGW388Gq7*X94lquPAM1Vw`K67@PHP zan!bv4DdAr$eT*}md5`-1E{_ae!GQ+g@_qIdMf%nA<8VT+k{*8QH#&tJ>z-9#M=7A z)Ppx;PQDno;LyVIo#+&@!_RSQB=%C0Z*0|B#$7(Y`>kHN$~(@@P%eLdjcIjqO}Enu zk=_eRtAOm6`Bgnizj}XDzut>74<6rd9`PLe5M(gV$>5;>xT_v?{IB818Shu`y?Lv6 zlS28~CpGDV(^dAIW={^Q46#tW85MFn=Z?g3XA9+_6s&uBqZIQbfsx&_C+Sn#pX;su z)VJ3M?#Z0uTR}GA#RXFyP)?idcTiEazN;^k2OQCm+vU9xOUK<_cBb1o`}uz?$vio? zd&Y>@E|ozY!j^71bT?ScxbpgA|9ecgzXRi*uHTytnyc5>nrq9lAnyCyyIwxpHlatV z>*(oM4TcTe5UoD_<>2U&{P6vh>zCCv*O3hHU(j6gsD*vQ_jF|{ z4T};pfOH?XVC<&J28Hc=4LUjG>AMSo!k$UD?}ePCeb~EUR)<6F{hf(jr=RHnY*-L~ z>AH`;qQmNnIloQ0X0hjUl(YZ1Q$5ERZjMgXP1#Ctq`ED|_>;H!6uY5K8Ooch=_Nz5 zt#e+`dnR?BRh~d&{WTmpC$F}j_Tnx46Ya9{4F^#UH*8_Ax}*EJ|J(FO{foBh)DpT& zC=Y&u*M#!WE-@zwm7}7fy^6ul2<~{MVd|6_+`FC6GUi99(l~qiEl}P#$v*Di#&Pl{ zf-U?BDn~BI^`16n9*2rC#T+NymD&}dpSFJaos5lZQca_m$1AJ*PAb~ff9QH!fr8~D zyLoW)SoA+1lV3G+4|a(qjU7N3G<6^8fijnKZ@ziKf_? z_Gc_X(+vMw)5trDB{U6r;4FIOo!oVm;bHg>F~y9JF6;zvWQ_cpLFApE5)AV1I{zg# z#6M9(*dIDk51U4##SB264}WpY_#g3F_-7n{x#tEP^P*s5#dIjXs$;n2l&P1VGY6P* zbyH`0ADmbpg})72b|Gcvh_`DrFRU{Z24a+xw>Ep5P%+8jja=?0q?&m5=sM``zu0o6sJ#j>gjP8M*C=VC8k^=lr3r|t1s<0|96&tXyV*g8HYPvX23BJj5 z^lxKE{6j1{Vru32n-M2(|Bdhhf8W<#{cFmK7Mm5oWGVP+JQ`SQA zru)Y+kQ^;e>f?&_kgR=S^ou^OghBH6%=-3_G=${C>FJ)3bb{owo%TZ@*((uxNJtX3 z2z3)7t9;bEmynzQ$vu6vGa)$-l9g>=Q6aewk|&pRL{Cpk>K0UtumunrAPXh+afLIG zEV`lW3(2RDEKdFXDOAvez6TaH$XB&oYco@XCXOia1As=dj`n~@wS0bw+%`j zzq%Tdu8^EOe~3CHqnft}6@nnE*OrNZ1==7;#?}8?4#`Q7#K(L#g=9V?hi=^o7^H2G z)b*)+*B?M=ge;WQ$EiCZ>B}u=K=L#sJGk(Eha`fgi}F^$4UGoLuKpEAA!#jX2Ah5Q zHk5LNEKFzsL#M_=(s{|{DoAo6>Gf=LC?uCBCb1~&k4fHa1Dxs$L;`6BPVI&({gRNx z3W&j}5d{L=HkA0mE}#isii+aWq8T`Kj4w+8x4fE=gez@nUaND0sBpfta5tQ~1QoWP zh6*1R=WmeaXW+^e;)jQ&54+*YYsC+1qz~(H>H}%F%9RO86j5LAq$RrHD#@a1G%e}F zdYopCs#y&O094Z856u^+c@QuiM~{w522hB`%@8-hXx>0F(EtZZs~!;Nk7<^#t}K3- zC4JZpS6?Q6xUktn+G^C2ODr*HIGXD;hV;*D(@5bd^5rhU-|0ANG(wtj86Z(w=lY#Q7=G{BF2n+LxYyiV!m? z@|x!te#yTe&M#}0uXA1eaF_HUbb4G`NmoUj-<jFtSFJyZ($(!F?0N{NzuB^It{BHO9m|Z33uN|+3XV(maCJ|Pj13Ks3Qdmih>MQ!Opc0<>JiLgGH|_^gd_n&AZlbk z7uU;5NGdE~0Q*6MEQ)|5z?EtR*#a;4pDW-Bpk2H@kTlArb9giwhbcgP#-JR!fB~>5 z({R0Qs6ieAqd-u=WCaN5aXPqi$3&<$FvRo>tIibi6fj)bU4T1l5zQeP_c6(fg~30e zDa|k|bF$LWv1=y0jGU)*)Vx2(YI~o)PacMuLL)m`q0LY#-O!Dz{IH z`38rcjOtz4VJhcA=YzFleC$WX9bA|wz*S-eJQy9wJQyoNQE3tZIIc2W1T$3vv&v+G zSq*TNd9q=qAy9?lfvN11T?h?Kr5^{^4?^f+<0|Jx5>yA;eJ-<#{X$d{S7{1bO8Ip)$t)YX>l@%|Dl!q{FoZyinl7PQS#$x1 zTEO7I@=+VAbdp)c36v24trpJZXXoNBGZK!CZP8r;`A+6Wcm z-<2G(xDeFP{=-qHJl=27?5;IAIXQ^j)aymmwwmY{F(#rm4H{(U|W?M+?n!RO$i`j&H8`@5xG?uf1!_K)SgFJV z8Hx~ZqlO!Og61XqEM-Jd)=*TRoAMbxhO9ec9oWVP>G4n~N{3uFkH*PncQODjY!fNg z`hDLKKk>vaAd3wg~$Zb z(VdtYEih3C$(Q*Mv(npJWY+ba+T4iuno}|wR^0WOwc_oir|+@2HxE_}Jg*;H-V!9=WwuPW@rQA3(Z1fdw*W)+3 z>c(@|aC1#ZzkaiQWru{?$Gi?@m104mZ6HffXghx;D6~6#S5RmVl?g2p6y0&{F|y=D zJfmc;h(C!DiLFDi>~s;yPS?FGmx7Lj0Z3^4c2zRUT8qohXIYEO0)kpL*FqG3Y0hjB z(VUL9m{deOu493l11d#XPDGa2{?vsz8F?r z>UUvfup9}R!F6?sVX~;0M9}Hli1nRrpzP{M-|6<0^f5$sA&I4CUPoY4cd}S|>XyhX zkEADqWg~*At(j;M1cBQ462@v>_QSyEoK6!0qhty zXeU?|7;~7JvE%Tx)I>aOa59k^HF#XIr@NASsr@MS>!UPJ$#8$xv9DNR?7cyoib4 zO_d;ii`PVpNJO*5oMb0P+*pn!3_92Q?jN5eL;*shANvYF^j+9eOnRG zZq6)Q3D5@WJPEQ5ak@PW!@y1^RoD{phQ$K84FAxIF9mG~f?CYVLXg;CxB-I@;-F9v z)qI(1)GH{w7^3DKs3}Pp3yKY4UX8%q5X9gH`4YrX5F$abX7zmqYuhet76lZK!AS&H z0RySfZe5TH1r6GT%LM((qVut?xWQTIm{q_?0xKIVcUTG=yp%B%=mf388SEI2zyLQi z{0~JK#bx97w>42fvKdhmZfK7qv%pn#ab)0?6>CnA140A_c6XITa`XYZ>51u;(FT;cthQ zY8b4DfB~VfF`7o9sgWQaDBlaGk01uzk|o{6ToTA~7ZV&yk)s1^7?~Y7!lDn65(U=K zTmf#hM35uk6I&QI=S4ZPw=g)oY%nHba=_Ay$p)$*Og^I;(E`&3$y+4Ecr>7#mXZg| zi+Lqza^WKbdMgq1E^k>@VnNHocxe0}wFL1T4vUH`*tY&(ELh+rWU#bNkvTqRSb9S( z8c}Nu)B>v)lnmy>qGn<7#A31SEIuEn|B;YHEEU@>fW?}n1}w2rqp;^CYgWd>9Jf7$ z3OWK=6(iX}42BIRHihWw`WFBNjFbQn)d04!vdrcjV5td{%)wZcT-?|s5%w*O&EOH0 zu&a}}d{~3D(@NxVv0T(hgv>^4>k&3*&g7x)jr+>%K3ir@2VaCDkTBRx4(wqVuajBI z@pMAcYy;c`_=hrk_6z~P5H~(X*loy~6%&B*RV0o66XndF&B7p98G`ZC7Z?fQgydUZ z9*Z)I$Tl(ilAYOo&^r38PY}m)70(^jd0ZbsQ`cW1D0?&9n$YXQ)egGLCVkym3lCRwspujJ?5lF@3?IK~4iN!tqBD7de-xp|Kr5*tBa`C$kc=%BA3P4Pi6Ptc}cq&L@X} zGi%XiGj7&Rc7-=kL2MatB{mzEAZ+PYssOf7uO=6B2TV|(731{qL1>@5%=MI7>hE(H zr|-T!);MhW+yw&MYz_#0y!jR?l4rPCxp-)1RWboULqias5<~n27~HHuc8zS*?0eC; z3~=+dGE3Q^l|E=aU{3glOn-d1nH~aGrB`_@Wi(-w8 zA$2Wcuj2hq3LdEOt)CqihzXG0^%=L03mBw?Fd2B z@(d+3Iw6=D6$nQs$>C8U(P)VRn?z6xiP0~HKSjD!p{pVR{U4Sp;+0A#FaW=Sv4yq3 z#VtF6goxqB!?6nnmM;&3*@pxb^gWscdOC+VvM|8u0-3}_&>aP*OXgohP|_vySFFXt zfV^Tr*k_*GmVUpg+d_w%8yB=mA6<4UCReyW>k9w%j@m&_-hY05u{nMD!X#Q!SX6FS z4zUk}jEB|7P1^H>&qOc%GTNaS!~FOB0f6m7|&4>A%g_Y;p< zbRJf~08PW@fjNbt3`LO6a88dF2wXl*7oI#!WOF_yaeQ#gmmJ)s7EEdB+7l5JD=P;T zv(ifB@;)ZPg4GS;0hk7YLad}vp*dk=0yIu;4BlRs!$&>iE}LN)0^&-<@kDkumzjn5jL9de;_bV#SUgPJ zL5rnSE|&@GF(?U!7W~aZ<)9WD{^IS&v4qlE3+5x1AwB>A2LC|ELbrxMGISA8Ks8Jl z2x<;>1q&WPS^zw2zaKRY!V5hUFt|jAl5s*A7AjMVx`yL9q8>B>1};(p7*j0C0@z$8 zFGj${IAE<%1h6Lsn;e(`D2t!OMMpBWE{U8NKC=+v3^Kq-$8B|pC3+!&MKOMWzr_#} z=g0_j!n8)%4frw;5s+L!ARqJN@IZTkxeVh4s~GqbOk+a~eiHnE#?1v42eZY*ZP#&F zK)2GFVObD`(F8&B;<3}Ne3{^-O>`zMc79EY<~zgJj0R=;Gp0j1RC-A20jy_T6k1KU_^LOa!7a-%wPA2=pMb2qv9jG2Q$A@O&?WD zkBwM7E#5+hbm7I%v& zC@w6R*^Go3!9Yx3rs>=1ZOJ_n1ja=t_lS;)jgJf#q5d2AMWE@#>l$6w7sM7{D2SVP zLBNdFktujI5i&>Gt+aLCxN?=%YWf-wlncHcu83r8RyxruY?ix~+S-+_*tpWMqSR_N z3;$ke35z7h21kS>GlL^Rl*!^>4Fp1}o!uHYsi-dfwoNNkDpP`lZ$uq4I3_+g7EW}b z6b?geXd&n*?5r%Xaa?{OEF)evN>36Ql3<$gs8~^fppaHT=st1L`Gj>NDq2pY84Pao za!EX-qFqiWa$uPSyOKx+<1X+%8xPraF4tiNzz6k79Ke6EFF1x^ixX#(?2n&-F2B5Y zN60u3_TeGnKqg|+Yf*w39T6Ox9L)%32F67*W0NBT84UEQUR+>ki*haB;A?>@R0Y*( zQJ&~o`UDcdEV013J>sMf(TjmZG2om~W?*D;SYT{ea(sAH%Od}w=b+$-z&nv_0k{wAU)yom@}M;7QUJCqbjPVgieN(^LzR*a4U&WEvxWOi^A2qQuhh4&5Y z9uZ8u^9UGRK4|!uA?dxXbm_YadkSxcwX6EAjoGu3&K(Mtj8>VsE@_zit9v*1DfW%X z8Kv$l-0ly|8%3TrH!9NllFa?I1zS8Eq*dB%-gdeqwI<&-tYD*9AE zbxzo=XSXB6MrsEIrdDoksJClEFPrJGP}^ zlf=@O2HylMZR{J`eQ5v4t^AqA>+r$~&EdP=yo=8GbyP}6&wGJ-gCC|fjuFz?$9Hbv ztjOP;w|L^Mo)%X>&h_~)x9i19mdl!QqoE#-yCNHVv2&;$t}0yOJd*DTcJyKhmi^Yc zbK&%9TW%buRn<{;#Gc~Xb(-?7MxlRJ`4|E&mDlgRT|*NJ+pcG&#+E5=U;F;(%K9=r zYpaXSI;#AM^N?4Id>jeo4Nr{4AHyL5SYh9V7ftCaCpttdi2Pu8?t_wE@Kq0d!hs1_ z;-gC7Z4hIh_Hbm|)N{t8vXson^W8d4ZDg^9uA140 zD?b`#CibMSOJN6l<_ab}iucqg!p~^$JUzO%s{Bhe{~0csFZ^hA5Ikb)*X$7!cTGjh zs6J<1@k+n;!cN(}N~)6YcBIv9+!mT~%;{J;;T!)0A$u{nRrY{UD(&XbtF6Q!P3I`j zoTp4~nEiU>fsHn&u4qyl_39jZuFIa-%b)>w&}wbBFL{_ioJ254-Px1gLSL;j58`{T zXFd+P9{H&vDr#%QfI42_fJxy?5?hZ!59%ni7@j(6U zs&f~uDb^b7u&?ZLcO#<>p-q#|Hu9e2yFGjpwi<78uV`}bL8Y?^2XB6N?D1BfV@WKV zz1!^(O9;o-$R~-SEjl=0xWn$Yz?8*i;%>WeiU*6*k&UY!gcpt7cCjcgKe5hH7ztO*)->BG@Z1E*I zk0$*_NxxC_wi)R+3U7L8kba|I0w|Dvqj1(n`iLz{7EEP_EF1S^z>2;bFKS0Tr}IxK&T%b1`A#@|A>)qktt*#wos6yDTkOd1TAkfa zcw)7tjp1_JtnR;X8wV7Ztu!mlTgn(cs)PO5HQTT3O|zT&R4C5{LFn4ueqNQJBy`G- zUTJ^yr42LYyDxlP&q!sadFU^85&B_l!Ycv%ZqnrXGpwLCVOAK=L2D~{(;uY@;h|X8 z^$(bWqA0iRBJ%^2}<&J_zOAG5LSIA5xz0l2A|)@1>bx z-+RZZLFq%bOf7kmWV?JW=V^n_Yu96{F?ngiwf#OUd+0t(rK0{<-}CCj=51X)I%SQm zg8oG7v7_3ZxfDZE4F$u{{g8-s&=rwe{>&AT-gaZEn%qN3eS3wl3waM+ z5>DPjN4WkdkoV9@9plJ*=wOc$1z(kMX92t_MczY)A|FZvyb>V+AvPd+51pJl5xFQJ zq(4#13t35jBGR7-j3m;Zh`7Rt^e1AG z_s|hHT#@(CiSJz?{fUS-UH)D7(2@Q`=;nFy0y?-LfxLi@ynv3pfR4O?j=X^G469Cj zB|B0M&ZIvP=}#oOJqT{-BmIfU3+TuT=!kpd$P4Jm3+TuT=*SD`h;0+(AVl1fM_xeJ z>=wN5UO>0^z>R&IR20a2=-^(ZX80oAib%I2(ygc&Ly-5-k@wJ%_t5>@@1biAx1uWQ z+c*C=$0Dw01h}OPw*-#{$KdzZ5-3=%_^mSxzQM62&QfV@-K?hAs14!2en@CkGMaeg zH>c8(=_(CRlN2unWsT3X`Ms2WW0n@%!}3VRm5vTi-<^*0tXr_9rr=4FGeT+eH0c5aMJ682#QX6eb8te((7XepOc5X41kL=w3Kl@((8lt`oMLx zNv{tA1EkjnhxGb@z|ZtT((409Z+F^OkzOB31_lC#0Ps-7(Z>y=6G34N3^8r_7OWj? zmY{2A2B2`!*|^J$gd`3ozztKu{InXLkR)KRal@H1t2&%XND^OL!$wUk#x2KzayDF* zm4oHrR?iZWiWs7QxZ!R-!JfF`As$Y5MWw1axZznsb_sAgn0dJ2O)jnyA1(DA z>GdHXy*@~<4-9vC%d#ry$R)i#NUsml>w^`*WUxrD57O&{^!h-HZrBSTy*^A?0o;~e z4Bz$oAl*G$B8qhPAl*GkcMsCt!--yDv)rxJ)~<8~>Fz#O)1&bg1f5jZ5haV%RnIlA9U<(Q|b zuhuTs@{Aj~^r*GZ%PDJ)RrINT>YT7!$(1dXH$1lJBfM{(kmk2-aZpW@(%Hx1)HK#M zOhbD`=+?YhdZtS{jph@@2*5ZKHmWVtxxw!7Ymx1v=wkQUPbZ$|-L6ualF?@E^ABrE zw$Ylf&1~WB*^~4s?a%dAf9l)o1NUT3@vR`6@Zy3g4=ATi_B*JkvV~!KSKl`cJ@zbQ zb5g{JhuEG3hS{%29@uDe>WU_{QLoOi=eq2P zy$l*~2Q8sI90?B{U$8?>jEp*k)K3w_H zC^NAqeO(GW*fUo!;ZeM&MiG8Sd*|uVy;X&WZQqz(co0RK7P-^^Y26?z)`7xo0Vku= zp0n|4>GKyp70$`4?WetX3;#sBtbD^kl*0{M*sJd7KJNcE{Zap-tva>BT@m_e>zCij z*tjOuG0e9TIi0O8~XQc1l=ac}=cxqh;0>&9o)? z6IU@PS~I$pHSG=?&|}2fRU6Knt?`|^^r&#t(3)+uf`#3;%$imm!7s?MU948!sbOJv zhtl?YZTs`Cu^G$#i%e*k;A{5S{~>$k0Bha*Z|+R-{^MkFiC~^e`}%!tQsS<#uc_VF zIX12_O-Nt9W>kOw)LFj-jtxune*4y`Fy*rHoI$Hf_I5AZf2RGQUD1t^)ET}$mGy_F zKe?LNN(@rJy?Su)+p7m_t~@UvHL}!BJ8Z;|a4VtXlc#ll`ghvJAqHU!m-TR0eUPIa zwTerP99Mify;P8H`QYgWy3aGGC0Z6|RS;bZX>*lUcP%KrUCJoqJ(--dc7O7A^NKE? zD~Q+1=qn9b0{z2PzkIA1Q)%hFX>#EF z)?*NPC?FZ6^%z9OSNH}^J(Ggh!gpDT{r%ZH&ldHWyWYid zw}x73<8UEeiSD?cTJNa4`0#T2`hz8wc?sdGCM_SEKY8qi#b<}z+ZECngt3M49R7sz zyweEs3wSbLf5wo6fqWhN-CmDxMg=W?R!tjkrSI$b>aJT#K*Q-P}9t-m8KaJ?ck09aNsP zD17j+N9t`A+VO-Lh$GNPsH8NchkZxv>7qC7I7c2-R(k}+2OR!mWPr8VyCZGS-|-ML z&Qyouj$T$;CBN97E!Cwj!}{6f=J~HT^X#a*pf3N|i_awE{8`N+j~0H0W>FbCKI)1h zRw8B`Ws%`E&T{1N6T4j}=cktbp?hcfus;Mo@w*pR@)ku7Wt?{lyBM$X3Ttd=6j13H zzth4~6n?j;jjBAV7hUF+aqRL@gKN%+d-&ehlq$9`dao|`ZgAPlii^|isIDHao{E~s zCucrfG-=W1-WOT6`9k|waVri!>ib~hmEVg-^y^w@mStHqbNiJlT8}Kfv(;UjzI&0N zoY4qV`WPC~aF@k`jZ3v@o8BHAwy3V@(Z2jEkAL4?cQU55|q=}9JokO z1LLk^lQ+UqssIg0@1|SI^M$65UG>~lcd*Zr3G+Jp*lb*9)lW^6yHGQ7#i_$vgFUfj zPl<~Msc`Y2yt%4^{)Su1D}_;siwCI}6`QE%ny~kB?=$>AUOXsIYzptcv+FhKvf{q= zr;5$m73!)Q9i0}eV;`dGlHYfaizDNN(3-W^o!0Q;+ztzl_2u8nFK;{$KZ#oNIb-(O zlFjC|YR5=2qhM5Y@gUF|x_9u!pSgF?Q!(^;W8vRVl2y^Z8@oV`_~BAZ#IXyg>_mPS z6AW7-mbubZwZf!|&)sa&*759DVvW_rlDDho9?e<QOPwlNV`E6d{XaDDKPKzAj< zhp36G?Zgeu6Oy3J?L?5)YS(1Cm^r9`pPJfx^yd*7s)7tvK@bpnbCL{IL58Zp+k7TN zRlM20vO_}cV_t`{%AA}WGE@Z_ssh*5B|}w!#h}uU3{^oVLsf93%RVwx#ZEA|$xszS zQ)5G7jbbE-2Pxr&(?<{yFqGD#_?2*-26(BlS?)kMbPRV5WVsh~#4TP!5k-y;EM8=-tW#h+6$H3OBe{E1K%;T3jg zXB=!LPyCa*yzczVx}S$>-yEfquJ^Q#u6CrYkL%J(>BRlkj#x27 z4ki#o5sq+y*^6bMN^X|<3p zW6w{W1raOOf6XWK>;=o&X^&{G${jp61oJ9xwHtm%ab?$Khc6e69+{WG{1Xu?5<#_rr&iBKP2p5 z^7cXRm;0=O$8)rf`!c$19=A?;+WmpUKdg_Z*i7hS_PvM|@W zj=XnCYMB3g;H(>MtacrIxIAm|NN*aOkA?^uB+XJ@W0Hs!yU0)iC}PDfQN#)-IiBnC zB33*jB397AnO@#pi6U0WD}~XBh!r$x#0q&KF8+@ZE98ky;l!GLPlN{7y?3s{YtOy; zrHfzA+Vtm-BG0DmbM)$dRLNM#czL}1jQQdb{BwRI#+-R)J5p=AM}XSm<2w5qX&p|E z>qL?n1*3@~R_ua^6*u+%OvDPOD?NV|MXdOHNwO-1??tSTCw{&}tf0NPIB(wz3bs=$ zbCC!pY+zQ3^ZKa|FQv`gs$BM>{Pcw6DhsXGX;(hHb=@OquxnfmfhIgcHD3(grK8ky z)`C0L{cfM(nWV4ZmE}}Ea`&3?j-DwidE70dh_+k@u{|dr>@jD(%ggLLLyd2)*vLy= zzr6P!T2)J)?2KN3LemN5_1D^gC@l1h+rhYZ|J%mBcA0iDjC=3DZQNsQ<~Bgsi2dSm zlVKwg*(q~#>zC`}idK*;(MdW4Nxwv#+CCwPox-E-pQ(>4jDjpOY=k3Vfeaf#(`pth zfM)K?QXnp6#8uMZO){D2jXMQ!Opc0<>JiLgG6)w2(IuAy1?v!e9U+-umREU39a>U|7P(%9V0TCPM`h;Qdx%;)Cx$<}IT-Pbg8B2rPIAO67vMvH2Kxcmw}g~9Qc0np z&=Am#Dnb%2s6$!+F1{vkj%zxIys0q^G(iP#}X@*cpyU&;%(G$qfcM3VVE+aC~GLH&rSIZA4Aq1 zF^RYFL3%tCiqa7fJQ^pP-N^v7ew#?K*6;g{_=zWW0n?!?`~fo*K2W*~I54s-xR@aq zW1}~#(cR~5vY#=;R3K;CS`f*s##R07Q@x2%4D8`s9)R1*Ok7HJs_I+Y?F$cQt0&i~Zui^2)Om7kJ3B1g|{Mw-Q~Xp8=#-zbmq4e!Q|%5vXuaBpw5#R0ERf- z9%kOaP9~F(VI#<}5g?o)rX3kJf<;B9Yg_*>rYkTJ7N?K5O_9kv&I=QgI2;y@s5J&^ zfw>Dh5A$JBv#@v~xM15^d_GS9BO!?hE!cJeg!!}7fRK!+(OohdwHph}+V&7C=m=JC zF%lX`YEal!g)jUdBDkYOXfY;Lv)G6mYWBW%^haO1(Y$6_Gd6b3;cVcjR8&<$W+93Xlsdr(Bo#6W z1%v^?<%;YFOVj4|gJdBDxnL$}<3uiMCx|DGtR;e!3>(2G!$y!{Bgn83tNKADQ7%34syeLCKN9v9W=n!O3ya$vvW@V&fx&MK!;v zCIU?-Uf1Zdz96>vLP6ZT3j$`WPK+$jG*KTT?N-`4Z(O;`YBhb0-D=i?Z%3eyily7E zB*R9KVIxABfsx5!fw5u9@&ER)5#xiIw;^mqrI?4Mcd>rd$e3uvRonM!U)Zm+soG`n zb(enUFkd~=|J8d^an1SG+Dzyx{wVRgI&P!tR(Z7`eU* z8|b$E_mpjx!lM^MuI&+v$vF zU4Q#F3nsN2^5)5+LHVm2DqD|1@6(`DBGCtw(Zfo-v+Qw z_3(elt$9N-&Yz7JA&(Y*M!bmGdQWaayolps#!-fEFmT3MdYw$&9($d&!<|-L)x5pz`o%4_zH29?oB27-6OO;qz+C&j=fMdvZTXh`tTuOy z4lh*gNad}F9Nb?waP5-s#fy+P8sW%w8x1*?$wRoWnP-do>>gWjhvCUTma^f=b-|r7 zlOrVxY(5$ype9W&Y9#R@vPnmN6fYuM6fXjkQP-(H=LC<^EH|>fR9i_6>w{T*LOn-TMHY?VwY2^Q7?>*p} zNdEu-EWLL^hfo9&yJA;F35rre2%sWn*N$D#vr8I9up}VX^J8pa@4cMy>|N}4p1q-B z*Hf|m-?O_3EndVgzx&+hf6F~ihMlrAlh=E8W;5^SbnssERr!4Kn(lplo`pO-G3r$N zoh8qI@r>&5ldt#u-|j1KIj&qHWMsy|3@BbiCgMfZuL&>0f2cm2;zj(kMlzM*w|Eh{ z#5?j=Jo>}<2mZp0G|Jmi6Xkh~JyWJq8COuA zQRnu%^+0)-t18bJl=tNBfcmfP4?PV&)H2E{unYTSq+r_O?Rg{LUGQ+8J>`vnQl73< zm@%n5V~z53NtIFFKTvXXl`vzC^1jqWc`ipC-Bc=*3d%EX;xj7%l=pj8<(Yu;Z1%k9 zn9?q)r}7U+{Ue^6uZjv9yf;c=eeBxpPLlVd?cFHl=}Lu}kjgXBC{LGE8Rh+hm1m+> z-c7TbD33j}>3EgOw1V@2ArG3$u*8O} zKTZ!Gd0Eoo=pP;I;w7sk*=`I2jdWgS7-#_fVi;)U3{!@IrjYX)23lp-3By2R7-$Rw zO@Ybdfo8@q&?2=?$^1*vyelV1iXbU2y(%J9Gzhj#tvLf*AWR(Kn6VtOts~*GR%@zy zrxKE;I})xrKpUPueVSaBN4Ojz>DGwkLP8-i!sQB@OZuIoFKD4mPM?lrIV8x%)x!u>dn`E|dqH5206YN{(?!$|-hR$3F*KZY!r@Ngz6S3oWI@TE@LAUr~} zXZRB`fZZZclSBln3;cQ8tapt+PK_w5n^t{7g$GWX|cNXu|op(px4_;a@ zzapXu^&eUTBBmqZv7Bz2he~S&P}5M2PtY|kuMFYwN_&n>RP0BpU5H|10L6er`gpz$CV*{iL8k9~945&XNM3^X-ypoJ&ZyMcXy^Fi~C7fSKk88UGawVa%Q6=aq>y{H(el%a~WA= ziGL(YWuKE|!TC^P28Igm2)`;7?8l-C_Or;6WK$&;%$q%zSD^k>p@yiEqRebmq+g>% zk@#~`M(}JX650eMcZ6S+i;PPYOFkztC^QCz2GB|p>BOMWfbb)(PWW*|gr6~XaRu@? zyI7}-4vP4^xJ!a77xOP%!h2OuPC5B*kRn>Ysr zFP5En9-v8fyg0iAg;pYwJ4rnPOj2iVq%brxGA5B5CKN9EDtlz8AR;Cj4zCla3nH`ib7D|v6xxhIp^;oG`}`{xVg(n^#TEm{>k1&@60EkSj(Q*ENPOp!d91lO~l-z>kma4BW4Bk{2(uXJkxh*tfEo zqPq>Y&5HwzM7FZKdWEb}k`W}Dt_!k`Xk;~bcJ+i*6{4Y{0)!qD@I#~HB1q%l@nd4b zzf}cuRQ`}op<%+%urNLV$ncfb%Vtn$8;a@`F7a7~6V*G10;f?QP7Gfd$BhgZ^0`s) zVc~f7)E20}hXw?!ZnUgujnAq87^;_4PvwJBrGIm%<8x!DkORrK2eoQ1cP8h@E@?<#ajuH)h<@#*ExVjJAFMJ638-X>t`sjZIh4xPX)^u*OemS7f9#=JwLoEl-o1pNV zIQHc1w>uIe({mS?FZtRg`ud5}$A&*0{oLhyQD}w;h4yoYcTuNpYso;aw0yJb(9)4h zIhSrdycd2Hn^_dowDpLC7DEGflr8E<&~){L28Fg^bV|eJmaFvoU#b&y&rLqD zsMX8eQzP`I2h8nn_{)U)Q)|yabajD}F_2nAq0M{Nn!GkB^FHB))vww4qPt z$c4SHwrwIF`uk#+jdl2)F7!Hk>CZqr=}=0U0V1%P-vfel?4C_?FDT(8Wh^lM)jt5|Kq%KQQu)Jb6QD@eqUCW z-*7|N($HU8CA=#!yrf2<8Bi!R=d$s4rPvF>H&AFJ23$Q&-{D)o`l~Qym^WYeJ&se|^KJq=a5^mo`En>eatL7aL2tR4;4j&Ag3N~ig) z42}DqJJyA}sPDH>Xu4XXJlQNyA1Cg;ZYZDk(@gi5iH*dkr>#`X`Ms`D_J9Fg*W;!l z8EPVlLeo_kjY3P=%FuNHg_g2a1ihB#{f7>pdtE5Br$B)i=4}ez`?@|W3M-*26=q6e zB}_FaG+i8uAH+)N8a9=N0g-FxM%nA%+IV$E1{T2%S!J^H{EOU#v`%3o_FLVZtDM*@ zWKuf&b~nN0XJfB4w7K3b@RDAWPIoZ*;`NWCE}l5e$c%-VBCG^x4KPkOyVV3NVZV1+ zAcaEvXN_bkvu~l$bPYe{C^XY8>jW2Gvaombn5#i#3>wuX;5T2p_V@d4wVM6Jx67Q% zTtVGWXSys4PHpsOYTrKo_mypr3fp;_8T4qo_2h**yv5Dl{5f^*`lCLll>WVLjwBj6w)yEtyK{fSdYC-_xU#!}?~w~~pzA0a zXlPJ&c4l+fyiAx*olUxX)Hw}b=2E-Fm&4|7(}HaH$s`Q;QQ-eM(v3W zY7|s=>!OZMhe9S5jeWV)f;iCO@$}yh*piM*R_CB7e{}RZ?RP_1m1boTR`&^enEgYX zvp2*U64n+tMp%8FCKJyfPfjPSjR||$YC|}mOi02AYkyF*wP&ShL}tJ;VY7{OxYkP6 zYmC%SSo6qR$$9A|n2-IQe2)%gW(AQ9HbPF+8i$))eXgCk|RkWs@IjR=dgi6wgk2j%{FxUuiJY%pC3^pPbMrW~1 z9~1K#Y(%wL9fOTvun`P4g26^euxx~cV6YLFFLqx3dfdYO*(r5)g%8-?#%I{8 z&&nfQdsReP5Uzs}$D$6r(xB(%%W#$)O~Z2K;87;$Aa8TPkr3{NXi7)pFkJsru?#e; zbKOvm!vLs}=2<1?i(_$4o)qH%oj}abn#+_#s1_b)VCd~Hi?{#%t{;cTVZ!`~lD~BO*37B3Lwne1{EycD# z4%}#Y+>sn>aCdT`Nw4HuQ|`wGUN+$|=(RAsu!dY{7DPm&FP!kDLs_fQPd(CHxGy6~>p5S&2Fwa9oPfH<&wzoXAmcFS8~5EHWib zv><&3N(Z?_@Gntk46fAVnm>=uMdqXZIpMZ!azH2V3a}AAGz1lgZZ#U!1ZJyH&^}an zMizNZ4qrt=3ck9XkOoI-ZlhagW>fhf0ZeewLjdDb?ZP{XBz$Qs_`!-{4$P9nH-0!S z!{m}IOqL`;&Zzzk62-AHeje&Gh(KRP`rE>*LO`C7y-4?uqocaUZ~CJc{=4viFcij3*pT^Jo7)rrd|zb{7?g$4uCvzx3EGz z&F#VCc1ExP(p5PuR1m7o-<;w*8{iWhqoL@aX)pn9k0KV5@5l|1VQ0)v)wE+ID)(AV)_R-#)rHz&s`K|U- z7W%E@toAD^!bexX1%(Sy_mkQwK91WZiW@Bu#zpkvqWe_4g)`Z`nwe(>ltW}pbQg8i zs%4|Pm*GWF9aOD*7+yqmfl`w3D+=Ni`Ymm=#6Muk3WgWK@FF6jDUZpOlV3Llo-nA3ZZl$ z#Q^()8ne04@H`=(L=nA0J4JHI4Q4>xSlT~j)WEbJK6ad)dEJ!PySl4>v+{U0r(G+> zqLC&!Ym){yesk~oUc+9IGy11#coCzm7KZ~b;tM_0YIqSY1@{+QpA8qaFt-UV)ZcnI z`}L?}`!1Z%UE#Mu)m1;Yum-#c!JLm9E^nwMclczlP7hqT+);~_1yT=ck&{1HLvEp2y0%HeA7a~i)1I3P5$-#)edw1=yzl$ zvQzCDh^{VBG6qs>ya>yQPtF4`!l0UgIKEhIt{37g@td}@pl^qDy{Emh8$avK)XY7i z4x@OT(rdtr(B&BUeY^-R__hZPOnX?Sw{t*>T~@E`!q^vvD_$!1&Uth-!{D^yyLl0P zbhND2c@d#_zryV&TV0)WqUGui_Y-DjwjG+)rS03|te4((Zq3**h%ua+@*;F;;qTx@ zD7;7Z0bYbLZ8#cU#Js0xX082mY`w$B_KeT#>Yu%Aefr9Jxm}Ok`pGf1E$dOPnipY6 z@gf{=kbJ(wowqG9m^UvPj;zj6cjdIwR zq?FAI6vw^{ynCv_=2aQ786{R%y2X969W+EACBIfIz>aD9VH80{8#bX~lNXCyDe40sW`J}ZhBp(_<;M)D%eG`t91fQcXEMd%tfm9tw8zpzH| z=Hs#kw||y2FHjoY@NV(s=esLD+#l!`^NUJvzG=8+JtuN=&(!>ry-)V>AJX|vK}53uePxp_mM;hF zv^DCMJO9?j-ZxK6UDMX>%m`XOY}e|a>NV|GB$XIYyoe1`Vz0HfF*bkKWV-1*g{*WM z`(DqjjhrK2h%Nkj7)%L5ya-+Q6Dez#7ZJ5^@n&eZ&A+YPyPR^`K)db!ZS8*d3Og$H z(sQ8OjefzCTHxLBm%P1$Ub+Q5-+AR;re~kD{ii+?^y+{ceK3B@UDQvizc0s@zp+kV!IG(IO(7Tr!Dl<_4uoL$M7RT-Q$&^sc@rUO`G~UD5F7`=-92s6 zAvhO;Xs!gowGceMs5QEJN}X3xIK&^S@Cu?((19>G4Z-|Bj9WnPDFkN^z55h0SVFKM zyL2f8eIPi;HtAOgwp15`+6Ng%K$Pr*_h|@9A(*r9g&cy*AUGqsqZEQW)fqZ3UZa2x z*#uF;N4;AQ!LfAEfzUq#LBs=t;4=u0i}w$OyjCc9^vWs-HiY2Bc>~QM7+tYM$Pflm z-8YYiUeNCkK|$%sFM{DkFuVvi*bZla5yp+>1UhDrFmF!S{GO2HNSMcJb*Tu_M~TLeo4Ub~0~|>3 zN>0i+g&BeP^ufLx(=N^!(Pm1kK2LB5{$0LyT}ug23g+P zzNM%?i$(4tlx0@nljQ7c`0K4D7LvEyt&|4wWpfUB6^Fg5^XYKV4C!w%q7GNHva;Yt zgn23H-%@84Y&k5alUV3OG&s~#bQ0KPX<@C6O+sNGI%sVyasx*h8D2zqRY#IEvS%#& zk^}+RYzf^+Sf*xV5KjFPl4LU60G&l_nO^SoLs-rvIZY0P9iXI&Je7&Oeqhl? zswh@x-OVVQmyko^SfF z%w$iqBaa>o{a|Xn&baBzfScFevd{HRmJ=p%aw&KKiJ@QsmK>yk94LesC~(d80eyI` zou1ZV1wGXmUPR@Gyh(2{;gtj32M$ys35FYJ9+PG;m zVKDur9(kN7`IOf9V%ZOX@sjk<`i3u-fOf`$!IH3-(+3!XM&LLo@Pbfl1cH1xjSAdr z!E2pO-l7Uvh4w9LWJ z)8OA6xda>=Frp6dg~%3Y$zPzxsDbn=qi6i7IyI_~`>QMMXf9QoBb(sVg=RPgXf+as z7s2o%7+wU!i(q&W?M`28Xl-|p;YG+v*c`))&}XA(JK-J$^Bi|H>wv$|x-cWF*ULP3 zl(!cFE&~V@Iq1Qv;2~;8NPEN#gm)wDC45*QB0tU!g!?SWj4OEHk%&N(?i;l}i0g;L zY&D6em^WALZwU`=_v7>w*ZscMOlXR$d21qJ12xsdN^8RU$4~*G#+AOz+fYiM6r^1nBrrxI3~s7;dNCkt_ObD@nB7y zG%;ybjs!=p)vf~28zvUPSx{*~q**dcNYs#K#f)Q4^7vR_1f`$dn)W~yvLNvKhWS=$ zBbVKX%~tNqxGa0S{dWH+AHTjmFDE=^$z{}fxdq(7n}zF1GP1~_T)~6ECy$p$xtvQR zFl@mqI&Zh~S9EfodOZZOB({f)MdgG^8EgcDjbN}5@Uj@4aP1dI9-vM539}{BFp_OC zXMVvv-W>4E4pyTL#8My?kn8V{Zu(M`YZ`f$Ht-LC0)gNSBnSdl{1sUcl``zEkb%KQ zFxUt_PI=1P@_AP-YZR0qlSVAwas*#C|CyA2uFJ3zs4{A=6kQd@Z)f?{lZ6ZC!J$=gaTKMi?V( zL~g{9WbYZZWFTd>3td0;Z+7hGTYdvpo+Ui7Tpi-k9nOmw6?Jkx_Ux` zjaWCSmDi-t8*bd3d8EZJKE*|gPHv3J`O~<_E4s)~QOB&T_6$T<7bqD6sWoiGk+UDR z05-y{s)4khu6OmYdC7p_5pxcoy$u`YmjPuGT2SPCKvk$^12rlNZz|JB;O9XLst( z!9k%j8{0i;Yi6-BXn^leh?d>YuHr!&AMRmr^R?D*AI1VUu+&SK0UK6;DohvzI@Wx z$+HJE`Klb0%V}(9TNZ>*3^Tm>_|!AjuuDBhvL*)KI{EU8PvjrV8JV##a|#==9$_Q; z)dU-1?YlpT!bbeFMlzMfx3CeqhM#h5gn7cEwxiPYusZbMZUEyfX+;)bMN=$W?qg?0 zv^_g6d0{_`IsLgslYI)#G=ASYzg_*XvOA@e73oTaS&&v_k!kQjPyYk)UAC-F{oWbuMcdD`H_5$cjYBh8EVuhAcbH z3|FZvRT4c6)R5v01sVUclLyKRtg1XqP~NJz_2v;DXC^xrT5h@+EwppIH|l2RXYZHI z+F!b~aY4snl=5_?!YoPUS!$H0OR9|W{(1)X-;Bj9e@uDi3))RpsjMm}&vMne9;ZNg z4XP^73Y2Hsq;6+H$rM53m)ya|MjuKBEm`jWsNw!0%AiZXAATgVqLimA6<~M_y!(1v zX_Ti+s*Ljfo7(#8dt+8VraUwMH_ufn>k7)VN;R4^50uxWs`9Ksd7l-(n7-(_c1WKN zcV5NxeByd>l6#NHkD-4KblbGAWx)AHl=5_?!mLTZ`7wHDQtrJUFA5p{EDwS;o<=IS`@CZF^TUS+{ zEhsN@yP}}S)0gw#7Ay0n{Bp#`!Y5&X*RvikH_V=NViVVeLn%*JD$JHto~=fCx}?e| z@2@}o|7I*^`(w&8I_=`5QrT5do~_T9dYPcS_EnW<2g*wgKt{`Nmr?{`wK`(N2 zb360yTTM4&&ohZe0~;Kpl&32d;P=p&XQxq~E~zrg`)_LNukVf7{h0C$UypsOQrTBf zo?ZRE+fIY>LaQpz9+da%k-YrPLA!_cTX}t6!kl4vJ>jX#X?;duI|QR+UiaLygHoQZ zRG2-fJbR7ubV-#_-d}(E|IJv;{s)y8Y}`_%a;Ts@`^(AAn}PDURh8!e%G=$34RPn- z*=e3}O=4y)lO$ zQ=Y-hfw3x;V+G|oY?^R!Gbk^js`4B`c^B(#Pg>n-;ZplY^ZaflzWC4Go9^?yHaB1B z{U7fKe>}f4g;JibRIv98J#8H|%F`uPMtOhz>HjxlF~=WMp8lu#St=E~g7O@vKW!fb zDC8(wc^dTfsC5PN*S!BFEpM|;O4PbRr<0r}99*yxUdC-(zGknjA>K$;d+vQZf%x+)K_gg$-<6xr@|MLiat?PcZjlO=L?Yj)x9rJH% z_pM=}ub|zr|F(7?n?Cr=lSWt^-EQ=Y)Fy+zX3*DL01K|K4?ye=Z3+)V&{s{+#-^XT z34rW+5QQlnf%>f%55fA2E~y|Wfnc*|o4P=7X(H^i7kwtVzn#3W5-XfIPcM7;k8y%$M*K6X( z62^t}#eU!3Oz8NE`Zpx?PlCaDLnP}+fnhl$kt|*7 zIi*eDoYJPk=$PovT*UUYk40=x8vM48f|96Den+4*v79ivEzbm4S|)(fXiS zHK>cRK8*;JqH53-LI!=U4a3M=GCjEAZB?T$hBF<1eKMlQFRdnvAGSMidsJ}U5rP8? z5-VXCsmH*QB+^5RFiD{ZuzH993!fihGLZ%do6OaUz90d@CQ6!UW3pF!A|ToTa!*V+ zgdtst2$OTv2nt^GCeO8Isk?wwpvedF$pvg1)Aoqe16&RgQvCf|1oQ>PFwV%*Ky}#Z z*F@L5=A6weo;+p@cjMzd$%%(UFYKE%G;71W@jdPv4Gqf9&TNhzm!?x^Q!wJwq&U$N zb2*67v>+RPGHDobb94*SW!iAW@pI*KcxuL9dc~F6oelL}Z+qQt^LaVgEYX!zpqu#1eq#5)zyB|6W4^D*0$N+WXei-2hTs&Cf_CYgxQ7jNX#WHOHzvuU z2;nD&rLf~`Edr-k;XF~SSnf!$*?*CQWQ&sK%C1WurQzsEExuJiGG)hT$tfoS;AII6 zb?iRSW?3fDU|K?w7?Tt1p>SXH4g$?3*(3zDZ`H#>0%0u#w?z2?mP)XHCcMXhQL|TO zWMNr^&$EQ2d|>OL{|NRj8A+xm*uP2%PD7OHqL^TxAs3l)f`cY#?CTP8T?lRLYcyA+ z9(mZWX_%rImZH#|h%qlW0Gzxd;RG)`I>uJ3R{&b0Q6$T+kk|!%eo8lBEyB{X8NnGs zHn=imy)gw@Zy1URmk!I6a7J6)w#mVRiUMc{s^K1dPiP|gPpa)3R_fobgAIW##|OYMEA z+BbNI`#|l{I~QPA!cq|W3zNr-#kd|qLOQo8M?y-WM1ce03@^L1bYOj0b3-nDGS?`` zg>&>^8jS_xdKp+e4-qJxb7eAu^CBS$X_s)GFOd-5770lis8D#>rKQk-(eN2N|B4dU z16j>RynISKaI6f;taQFsUO_ppUq@IaL$zIuwH6on0ku*r#&A|P;o_PIZwy^L;F2DB zmQ0dFX5&b>TPI2x^fiON&LiB~k#BDrz*x_quNm|;da%RmHHrG1k}6rfdkJjt0*wa0Ye9B7v3dHRWrRjQ2~;g(H$qmBjiD!GhkKtH1Q;0@qx z7Q&$~r0}w#``W9%_J&e@?bV{{6oRT7ymW?j9>ct5nAcj>Q+F&#%v>L4EJ$n>wa6m1 z2(uPgDZm5-zUh)9qXzn~mkhHbybDQ;Fi#vj2pvO*eh^*QdmnijIKh~L2cTe)6sA)c ziZG>80Iy@yrxyjFt1@f1_)|6of7`dz;XCj zhKt}|qRtpxDaBw_?6)EzY5qKV0Y;i3J%fN%5t|$YNc#ut_^w+JPCP2HBTJU;3&;)bnDD)DjyUvTRxi)XQyF&^%v$q;FZP#fL0902(Vze zDaUacCYNMkvLp!tYWg=w6vxW=c`__d4iT`#Bm8a2C3+rQ$)n4WJ36XsELR5k2W%DDmMRDWeLc4H< zRQAYFK}1Y6?AQ>f3nH^I%xm=r!!WOrY8d7n^=dxmrh4HJfjh4I0*@RijK zma=X;uxh7bn|K=v+JAu;XRpn=ok%l{5p?D9k&%W)goO&YLLL`F(OsxoXsd`TnJpqZ zAv7`~OsKYUL5#3-Omtj)6qm|bt^QQiY~$^mE;-2KW)~|2bBpEtI9sg)k0rVX!@RD* zvKD1zzzn{@JaWD+%|zklWSC)IM+k&GeoPmBXq2#PXk1re{J))f-B@9=1(??YddI(p zd7Uuu!~SSi%MO1`c;NoL(cj6u*44b4Gp|2e-tQJ!)Va@vkIC)*M|_O6xGW9Y_2$9VQ|6a< zXY?)b`5Vcky87sUgn9i>Ad{vm!)5~WI{BJUSJ>bv+SqY}f79lV&>{ zdza(j&O7YdJL!9w*CvR0J#AdGoQQy0GLR`V*QVJzdz-8ozFQc#Yo?#wxwnH?CKu&L zEcrAdIB(3h+Gbws>In_=x+HeqWs3m26YRN7?`=x5deBq2cVTt0n2q-siZMPy8j$;nU5v?a%ET(KzSy(_Z^}I$uAq=<%wH8+TroF@{r9=Cv*@{2k2e zwSHZ<1M@nWHXLJE3c&x-r%3p0BAh|b?J%ufjp(aAtr0VP%hIy@7iPt*wnhlHvU7r=j zSkRRUW0Q;pwuX7F3(D|=j0Ii8rt)iOjQzEDIY#@xHe7FC`q=dtzva=QvwB+>jJ?`r z@V#;74D-5NPTvY)Y{XaqzB=OdZmbEfSAU98BE`J^XN_bkr*AQ@b&X}^%xm`4>AOz= zKcGK7xNCS336BF_w`yqHNyeH}|F>DAx(y8fY<};N_m{6He@}~lwVv&NU)lDku$`xw zL65duPhP0QTioo;pHt_qKk9Qz>EG+-NDDhBsYH+R$;VpnI${$Uw5c@_w`Y9+SCQA> zc3)G#X#ja9N1y$3Vbky9Md+##y%2_9%A5I-OZ&~3^0Bq@fa27KX>C|712ez4F1sw6 zHs?vuQ&BxgV^()VCusM;e_Ol5N}3FWb`SoywcB_1uX_^o^oG#wM!(3nGz>3-;YIwP zc@Y-Z7QHQKV8CD_7;Hot?0T|nM&Seu+Nj9@fDSQ;(2xVHchT{^D#oXvcoKVIeUXlz zSRvjfm%cblbFq{#_z%iN!5-Gr@f$SpA*34vLLe9%(p(%%It`H*f74uqk{E1+0qL?q zFxUt&Uye47#v-Q-j+_VkZ5eC?+VLz^?|3FR^1zNB1{={mnkx`CY1mj871ss6Ul&GJ zMwm#@HY&9LlfgzrfP+}J#zV|30X)RexGg6gg3JbGNV0RtSkfiPY%J`XHP=r_Lf%4V zvg|DJbTU$&#{+xB;6IRK2JBHc+mJ|@Ez6Kf2?ucLq4(I4ISI2J1luzq3DVq5ghznc z?^?I%1_DHfF#Cx9c?9=lH$tJ;C^Uvu>@ zI-d>)&5-^UBkFK9D=Q0bM3|RSkdjrfd5Q8#SPs2!p%2knSu~^sU9i@MC;`w5gN+EJ zur~}g!YUX!o_0aI;Ert00C#norDGb z1^37uUdvG2BX|=eBHTA>wSoHK@X{uUrOZVfnzrXu^t(g#8K~r4`8{nxP zR$3F*KZY7WcsSD#2ExOa!YdFSA=)$i2^r|ORuc7Ojlo7xXe@Y>$6zB!XvV}DN3W-U z-P*3Japzfu0f9cT39~)>dtDuuKP&q88_fgXl5hIZE6B=h3wlo9a2}e|)3^b8Qr{80 zW?`n`PEP78Gq<}SXU}Nl1S*V(4v#_GhJZv+ZN|?MA-jbyLI{qjj#U7?L}?4$uxfRz z1euZ$-mL+p6Dx@aOg9FkG${t{hkzcq`66})CrwP)XP|et9JyA5B5@@wf}_TUfN@p) zexizL;TTX!Vgdh^es*ix169a^!0Q|4TcwR$b|W@hxi90g?Ctj3{hxgN`u2Q9ED3t` z?9IaUB;a|C&_C$KbW$EKkMdfUNMO8zhoiS!`O{AhNI3M07-vB&`D`R(Q8{5!nyf|D zl@oJ^Eud``-Q8&L2JpFhY8I0szZu{nwYo;)8tG0271s|FyGaJ>;uMzp7X}StZMm?nI15`-{8^K^B7;MByPGO*ra%uey z%Zk?ctO^KNg^Q~@e>)ppp8QZEG``mMwaHiDn7c6<+yhz^Yuc8ZMY++7$QAJvJ=M-w9!tXAMt zs7Ty!Kp#t5d^EQQkK0)Q0F8)f@K^?4`%oOO-q92WLj9>cHVF!xR#G?jQTD21kEh{r z-%4+5Cs6P%Ih{KfXYW*OCxBn}mx^O?e)aUU(|>ei&k8>O)C@0%Zh^K&*r7&@_U0^Y zw7ke~wV$%kZyjf~Ur`Z0y810BYKXd@)PR6EZkH%-v_Kda(ThX`RO=^abc^ztXH2|+ z7cUSBVq%1mG37jhYT2mnwa>qDAy#nlTx>Bg53WEz$cy9fzSZmI^39vXb&cT*$WKtq zXGmoe@Z+O910$iFdcX_q85t8A_N{ED=x&2;^WwlF5n^R`^$J;|BqL(b=TSb-#Lu07^dV)aHjQe896mQTo*O41 zwN3ybkQJW?!(3DiUqre;z-jKM~Ljqu40SCp~Df#r48~yxY=X_iuM2+MKxZH#+y~>ZAV=Y{Wmo zx!3L5wGDuc7*W+cUUW}BF*+{wZOSF&;a`8e*ixJ~fX0DjhuYd3F#YUJS zY(&=eQ@=dVswD%NcI&un*EO~c?@BJLPTZf<{dnr-_n3|Jpuyp1o$L2V=~~;^2wgpa zEQB-=*O({Kc+tjQ{OE04Ki=M4Xg+r8p!pr2EHf#)*P-9~Va;pLKy-D1k};54!$t@N zt^)uYF}kXOD1I|t{>v<(Rq>T^^{<>7=NO(e=u;AYd%($4FL&3=Juj#MHbR$w_u-yv7!gnd`W?Rfaz*a%%Mt95Kd{d=5@xCcuo zPO-hRVEMacZlSF@L@(X`dZE*N`<4aAl)o{CQ&Vh&E-m~W*a%g>`BwoOF@`oA4L0KH z<~ja0`)4Y*o4g{*luw@rJxn)Sa`?dePeV$$?d!H{S{U?PNjN{8 zU79@d?Z({2^-P;REF9YQQIuop<$&qiF0R@AYGU}euo1diqqJ%lyI@vW%0^=P`se)9 z#SiMr3vNssoKkOctK2ubrq(@M%>y(cj{j>`~UAzDoM&M^xRGJ z4$|R=&KbS(xtra9;6>x+whQ*#u-2!ynWbcbWz>oj2e)vWVvC;vYuHq_t>-smUY~xAj-UJ5Q-4qV-PX>>ejfO&aWA=F z?^9FH@y06`{uEi(X~TlE@#*Fh-0yKG&fL6xf`R|O_XEv$vJ7&TcrY?!VNMh_;ugY2 z?5Gho!pi?5g^l=Ujbtk4Z($>J4L{}B2&W0N*0Nr(uu1edq`^k4ZOZD>Zo#x=edk%8 zZra-K-G3I0{_XYCZhiUFR~+1PKR&3=J!QLGYf%&LLt`(u4t!d6O3?KF{LNPtPd?N; zGbyHYT`AH)<;e>jYqFC%j01$FB$({6CXm@jifFbSysIG zGkp<`-PGL4Za;moWrd4I;pN5CZ8Az!#~a~EpvMpn zMVT0wyl?s^XVx$-p9L?>`0>0kfHE2b|VxOlr!SN1bxc zOE1BE?Dym|um}bgfgEGd*|RLdc0{ES=eq!1rNUut6ic3O`moGoPqQPB9t{0pYQ4_5 z>C1qd*WR+v^-Y!&CUJ5pxao;00UjirI;unVTgi~^1KN|$PEYILi9G3ecs)6p*v^ik z;^?9C|Kh=yfw1$V;YfC&+Oq@riLmRYzQ;iAiQpa#EJ7=efq_L-2Kb4^@sv*wIOMS8 zgu^yi&1K6op|O-L$Of3P{%((hEnu(1bM(a;)`Xa+(f`lWH$HNiK7|wFR@&ToxN1-&_ z+$(wu<2X<>40ADg1_O&=U=iwdO??IyK?Gd|dx9^Xks(vBlU*2Cgt{Z-3@n0yMUcEq z1{MKNT?Q5bPJ|3BLdpjzpohgr0M*+9VqzMJp+K&aA}P+v!de0y6N9hf@}zv8oCbHZAW|i3zJ_CzjU=a)~LLdx{ zjEqU-hLIlB{hThx#^ZM?`A~C25=d4&@PqIRo=Q+iK~IKpgfh*lN1Qe6$pSh8CZnsH!F{4bK131EE;K&vo>jP z<2U!N?=|cdSrHb|vGLJU0E>{&JN`AWh=PZX(Z^fl%6dN+TP_$nalC!nA){jfyG2uq zVn%f?-ZiEMu!zJ?uhaglQ%k<^#!q&9v3|TYFaOt}AxBfZ?c?_io1Af^PT{9}3qO`v zC%5=cScI0_SGh@Vpp};`rC!R zTV@tb<9dECEW!-IA~MIFH9yy~mJH-X^2Mx=PKQs-EG@mWGU8Ufd!o_ zfs!$hT7yO04;cI_z#_7%8p!-Bp2H?Bd)2D#lETh8uR=S$Fxqxw{j1N4`CFf7*_?=J zR|8mtF1N_{jyjLxxCjp>0&;;)b$M-wlh<)v{WL zMOgRfyzA0~UV{&f@AHvo(B`pyQok$Ky+8GBn!Izt#Eq?M@yYUUF&tf5_&Z<`sfqUr z0Tz)<8;%ARvDT$Wy&$^-s^sqPXKe2h{mJq$=TYo1cdMzlW|brrmY!C_B1~ymL_fXd z0E-ZO0~Rr2z}3?_xCqBon9_Bj-3syDDejhQtw(!}89DXXiHZ9|a^C;^F(&)*B?H-b zrRf0c`b$fNL*|%9Wd~i`ecWmKt>n48Ppk|ocFfJJPjU=e@l z@IKcCi+D=HBAfvhq3g4vU=g}fVa_Bh!dU~0&_$Q{L0E*YVN-cr@A-tK)1!~P^^5Mj zeDXGj*6HKyj?dcs2iE4w4E*H$5z2|pLMElNZ+8=1em3?>L!0Z}0x#(`>2wE^FJAvR z>f(vhjLcY=GX;y-ieM3YYXXbVTW6j}!6N=yBbmzOTd)XS!%sOZ!dbr1pyYR!ULHNT z8z4V=gj{g}D{A9=V$Zl`y*qY{nv`CaaQi|fEXYE>%KWj#(`Iv!b4x)SUl2GF1__}r_B>+=pB`tazX`IX^A z8RhAi*3~E)bNxZ(S$t8dRBjcN=lc5j!E{jGf~v}M1LeJl&}%mPK<{nM<-$=RW`lep zG9R~Gf2Wo0hn%S?-HY;;P|DMl3Uecs=cZAfE~zrgtC1M~*2I|Gk0}p3+2@o>gSYL3t;gYz;0LjrJUIA|ZQoOgwwsw4n}fZWK%@n#P~oY2d_5l=5_? z!rV#axoecCOR9|W{#G&7=w_Jv4=PXb>a|McQ9*g`s*c7}KzU26D$fIyce-Sn+op#l zgEOAx?41(5!gCeZb%6PWlc9BU8n0gO`X+`_o~~4w2dO*{jq-F!l~G=e#PGK!#yoyd zdBUv)DwSsi<#~K+ZM6xMS6Eefo}j$^L+&xkw?8dUT~V-aMDlNQl1H2UcI0r9QK7ps zspBcn97=h*QemE?@;o)l(zYIHNq^9PmJ>=%8N%BzC%JhzS<-~`HBT~&Er zpu8u>VFyQx7mPY#z}n~5?E2;r1?^_{-aLN9^60_$Lh75FP|DMl3iBeB=cQ4eE~zrg ztC1M~*2I|C4=T?xyt7Khsh~WsK`E0yr|Mzrt16EJ%HtSXvqSmMTW;ovHniQ9H0;4N z+h)KBerZv4IWJ?Pgg38Ln@Dx0WVkdK49;43Yt;g-zugW-3;UWkn*HY7EMyA zyg_*A)g5}N!Wr!{W(o*zb5-GagYZ@)d-P9fq%`uc=NR|e_t}Br9bc#MIxNUPc4Xs+ z+@ISIr-Y{~73NI}&s!rrT}owyS0gR_t%))39~0i0Kv>!OR1luGU2f7|5Z?Bx!t(*) zjgWUUF??^+u-&8Bxcv?GOpy&5pE&M_Gb_GF*w@k2V=sI%K?u6K1MgI47La$-JX?^%sSKvL-wddgFBiyZ@to!`T#98LSQ@=8W+JqE@4v0x_dE8|gLeP&Z)E*^8&-zL`d;`^{q7*O9_2X4bRsk74kCNYleHR zkq5)Q*1)hC?lp2KVrQgJG&($b^|;qjbBzvrCX0Qx_3ZWJ@v=_M_LmHN74&>p+NR7* zg#R`ki|9R-AV3&loJCNKLMg%lsd=p;0fh8{$U{4B11$)7RujhCC^R940az9;5ynSp z=%Ddkt(+eOHYAKo#e~Hx2q3p7xFy5A9-fdS=Mkpu5seA&NTKn*pTRBxSQFvUHz6q_ ztC`xZjGcZ>biHfN+05d}W5#edKHig@csTUJzDYx~Hq0B}fKJnbOM z?l&YqV-U(O>Gu_W*!V4mdz}eR!`9(iKN^O64FE&Z-faeH@1Q{mNu3CrQ8boWR&k;e z&zn;~f@4T>Ochvd15(~Z!##KdfYsW^k~0`F;jSWW!Dt9k-A zm6J4~k~HGuO)3`Wv5+jz)`qlJ7{Ey6v#l552@@#xyifL~-Na_pY}9U!*8Z!XhFIKw(D~IqL2vp)F2TLkpCEirUdA8{ zyR&LUcd6D=$w#x@Tl%B3x7D6Vjp+8ufxCAU#fsom1_d8?5%bgI#t^AP6N%ITLNYXB zz!+iE#!Z_EgXtL`o5Ql{gIdn&Dpa z<*|h0OtnyeK@uyH>Weday;1OZ?M1+Ibs!v%Beg1cAR#=YJ;s)xA+NoJ-yX5#WLO8n z@eF7TSMZW}3iwY9M?g7h!@i=40GvL>6UB<HOJMup;yVT|&63rP&cwuHI9mfn^V^(Z7Ttna13btjw_ z$+P4#^2{#3bCB~JQ#MeAG!tiGvA|iwVlzPwBtSc+Q z+NwMweW=(Piy-a?lr@`uKdc2 z;a+2T)Qp!W=K)SzKNmwL>Tg#@9I- zb~j|DMfe=)o^w&n`iAbo%@e!ycwQ`7b7zQ*d@(0=P#n3|5hkDuj7ltmvw-kg3nBV_l;(^m33*n6m^>}vE1HVIJS-LtIY>Xd zHSK{aWI^Ed4fCziMlQP%o2}fJaas0u`|bWuK7M_BUQT$-f>{-T4v1<2H}GcRdXkJR zqCp>^+`@!8DUX*YhrthLNhC0}g3;L9t$c))^XTJMQ7k$BlCh|qFe&*~LS0j~1K~YH zYs(n!HFPe+y@odg4ELJhUeBLLPXI|?Ha*P2i$^xO_#)pSfvxZX;EjOW2(djH4NgE2 z<`Z@HA^bKBUg(;fCn1sCyW0`k-jQ4ohPJJSv7E zl?BU9IgZOPxg-mdB}oue)4xHYI9A5bL#%L!fF&N`Zwqe@c)UE49!_(?9Uav*CJ(d0 zpy~|wn&DnE-0R2F@HjV;`VHStAcH1B-)w~X9cybRQ1C7}ojVt2?^J9jfM52Pieqtp z_4E|;J0?1^rw|yjG_<%&3?OQwWB8gc{;S=_4&7$7H)m<1o^Sen&Dn+ zB*bv9DSNa)hB7oDV0EKqMQeOk1ps+_Np&mqL8;Q!@b5}6=ja%Lkk5^c=f(+0DOm!4PKFuob%a33e=#0kkUn;Xpy6Otz| zMDz;n6v-8$I{`U-Y5$Z_1Jio=*l~8|byHsN>i#|4>sRZ)d+qc4xPH7$cdH?mqjy2(43%H&7)E4*p(LsxoxP`fBqTm2) z#jMqLw=cwbv3W%+-r}`J6qTPZTt2!yWVxbb9lujpT>%A z#KW`}C380Wg_Ruj`x~*oy87sUgnRu@pp(w%F?KU>uMbrSeHaqPvGY(wNjoz|%kJJ~%k1}Cy>Iwn|J1vq z#@9CYT31hKxYyTGZjK&WFKqLd9R)M&=8n%UT;`gdDgV;A?5syCtDht4)t-Uq>H;NW zAhpK5Zg6qfDd1iot!g0sJs)55k1;*eVM~ha+1!%@mgN6w^xK!H%?5o zT9;$w_i?XRy`Ffa^^j)+%HB>Xn>()C!r&{(FK;OpOgR+Nbbs0GlL_C=z1G#TTIXKd zT)G-FX;PTGC{=c6xP4T&@Z&*)>+J2EIOeCvdnPw8Ys?sqXyq-t$I0)~9wp~*vAwO_ z8R?L^Zt1PD8&(f>i&+|PY~Er*{?6n<>-^;g-j4$2wp8lU!r#HYp4Mlk>3Ku!1Z_AP z?)8gxqvvl~U#EFp2iuL$&aTbMe6`hndR9+SbNd74-OVz@udw$o-p|tGn33FT>CwXk zV6X8X#$IFf0efxfIccu@M%K2R1><{~jNUtAX#N-P&eLZ5wx~OH*Ro_eP z*YVZXg{RzjdndUrzOLNa$6Y?C*Z9K3!bQIuyicCJtjHs8#(#JtN3^OtdiA!;dr|`? zKUL~#jIywZ9kC@~e!I!N-{;?JY}Nyx+$KTbVm-M6zJVNB)sE#|eZ!AGJu zo2KLVS_yXy19m_$J+Nz75qb|5f?~7v2Pb>q95kSDPSgGFJ=5+UV%M`BaP#W4Ml65- z`^vUQh3!1e40^QPdh$XY-r{C&{+v2@{ZXG&O8;IrM_Sl9NhSJ}KfcMi-YU`0&4u=yUe`@+Ai-HV$H z{2khT>EG7w6KPK)zxe1~q1%mqkqc0U6~V9~7*+(siXeLcd5brP&7S(@tc+5^z*K|9 zu=Jwh4O}%`1c(nr@!kw8LenPXotIbjk9?k?nZOyuqao6wge zk=ri`lN8d^64z7nEleiTZhaXwIph;8Wj`^7ErDY^=dS>sP8*7yDMdJ)JtOWa+VmDoij6MzWIM=&Y3;`-#|JU zN9gi^)8298X*xscZO5!ArA%|cokA$U-3ap&jo0cd?FM}hNiVegN1e;v{g|!&qUNe( zqUnnoWJPRrZsAhR#7tBU=B%SS|4vyrz&rIc%{)aO2c}G-72z$KRSD*I@(qWcwMm(D zVA?N&(D=wrx~bjHCIfX=3AvqNFPIfU>Y)d`!>pK|!tTiEYA-`ZS0G)807avqT4jJW z)v+(w2wJVu8Awk-T;iOFp0r2k>FepfV`WdP!yz+^r#vh&rVjMDGymcNGvv&s zTAe~JSL8KNUwo)m)md3ot19~3!LqjKd^e$58dm}#=>pm+K(%g4vzn;3|B6c_ zsMfA<-deY>wbe5BdqH+XQ$Fit`2KkOtiX&bo{&B8zgoAD5UP&HPZD@6#!S za-lc}pieV( zuGt|dE>S9lp$L&Jg_{@F8+DfQI3AZc-;%P)h8vOd=g(85=TX)_(acHYc!gds0>fFC zArQd3C?oUdlSDRcc(s20wvL*C5C_-=dJMb3rrq1cb9#-~$jwQ*GQ8V~QlHl5ht8FT zt@(A@iXY~Varr)ch0b^jWfKX)RQ8o!R>qOZk(_{h$h=OhktyYh-a%kT#S0aYP z2J(ts6BIr5aoK!Xa~tTmY__~TF5oO_sY_Ck6plMjPH>UMSCqFfk1)Uzh?Av*d@bZqV39zJw?NeE1n972(iN7;7M)=nZJ zx%yB)h`s_&ARx=oBB%&_CYQr9i7Y)BYL-rjG@~Cyv_y_s5i%64ny@3gMQ~bZ*bx9U zB$VA&ojKqY4p#}_A=MnxQ+CJHH*V~zbgqPM+-UFB$~ZtwZP!X?L9e4o8dSTs^hE+t zvhAE?w6~pV7ovNG-(UsxEd-h720|S}JGj~BlqD^e4V~69N9cL$W}iWoqD^`g`qvjl zAFq7+)3fBFf@L+W?3&>#x)xIH)~FAyol0i~(4nCk|E#X@+saVw9_d~q6K(b-b6l2G z`?fku(Vl&{>OpeC55gfs(J-AwF)Kn7AezIBs7jikS#vNeg2b!{nly}A5ztWm!K{cS z(Q~%kGd4`jg#Ba?1azew%j45CUV%{;?&=atatoprTJ$=MG9>Al2Bb=AZb>;A(&aJ& z7lVHT!`$)RP*GfV$`)9CrQG}&>N7zFQ^ps0+i@oPk4us5f~YPkrB{qroXANhx~*dG6#LdLf-^Hs0}cghnRyjRNOt?@)1Q zQcT|jJ{euVyeZl=Mn+&{1V%={oe#vgflFTvW`+gIkJL8#WhL6|D+6?f;&co-tbR6G z(_Verf*r*dCkbN3(Xrwru|SX%6Cn_Z(H`JcZzs%ZVo_{VSg06W+8VQebm*W+L1=Gg zt@^7qM|(>)%ZpLOn8)P`$=&rU)EX6;KqEXDa0haxlXL4AWU3Ga6%|7jlE63~71NjY zuY>Vj5Z+J~TB7Zb?G@TPDYSQQ5kDq|TvvbFZBU^U^O(F?tJ9{jrc47?5*^cq99zGz z8ag75;EQTdM=&x1BO^jZ{ZUdOYyo{;0}f5!@V+1uwe+-Uhf0V9k^Gn>K{Q_!Di(-h zXovzLGyw3RR=L_7g<9YS4OF34d3w*3x6D~OR13r3_)96vlv&&XJ> zqf4i~6@ZL5ub%jC08I*k9$?y8e(TtSopuhsy|(Ql(w`cB+oL*S*o4%+H7|3qUiTa5lD$cVp!v3Ih& z)fqrWT&kNM9m=x$rlo6YtJ1oZZ0>2TuC{WCWW(^8Jtz{0OIK{LqKC z%%6x=Zh3wm#41ly4{Ix^zbw|y>n7gUULw#e-*=uow2 z{=91^XGL(nJ{-5zSn(*K5s?x9l*D1v!k>YRXq_@75s(oT>cr6^BPL#0!{^T*8)Ou7 z_SmBD^Gw~Y7oD!Yzq!lQ>_NL9_i-JrK}NJ>kP(}oJ_lrkqyc2a{iW%(U113i^Q zd7LwUPVkA7yMOnxmP#)D$I3a6KbT6a9JVKZ@yzTQIqQ_JQ$im;vmYn_;dRTG7grz4 z{yimTdbroa9;EwFu zV0lPrNQtvV4o3(*(i8`_ZE27Z*RYo#AtSCyAZn=&o-8hO?&Nh3Y|TdouAH{CTcGon zjgEs`n8=o!3|RZ~p>O#9#8>yh2|wP!8ITcdr%DC;8{@!Mig2cp5zbm<1RG=GBasno zji&O87GK;Oa6#1V%Kw}zb1U2w;@OR=yp^=zXfwe#<4<3SLgD^z2Hm_P%^%Znn`#_w=$>CbGZ) z*D9r7ACre8cbOUW%UO1f=Vg=sQOk8G(@z7#V?)5f~YfNSVG;6EU8{q-zOS87cj0s!1~~ zF~iJ=S>D9D#&R<&^@s4pHT6mu8KI4yQMfjG=0})78O3V?WkgbKY+!x|_&N0>k)IPD zYzp&R)z9MWi6#xhln|Iu#UaHnNYI^s0GUiV#gi zS5QV3icCdE_%|0G)rqE>y8s0R&F#`zp4;&o^f* zsTdhCOM0{0fr?3i?i0iZFfzh`Gv|`zazyqonWtx^rSZ4k*)t^m$Iy~}Gsk6ZDg1n3 zmC-oQxpOlEP&PE5%{&Cw1=*1pHLU?LHZPb9uT08<_T~nlC;BvBt;?MoyHv3xdNFch z!|bX#HSZ@?Zt=3Iu&?OyYUiK@&4M~ho2|LjLNkGx!-L84Et=`nHAY5YWQ1{RU0P$v z4?T3M1|uUVjEsg-Pbwasd@kt$|HH_LnNuFEtqjar`?TcVOG5nH z&9%u=QjZYJpn->H(g>;6Imiy@ie}2HX&33RNQxF)P%U2SOg;D0bT_E=A$88?!Tf8k z8g)YVkkT`?E-B6&AHDJu$rI1XdK@Y5VIC{nAe(DD@yT!B7I%uPxFhehdVf|{7OIG; zCGCZCS+A`Lx-6M`!D4`KFqb9t0Y*lsja+7NI!_J_7sAL0jEtb#jMO3$Y8qV?BKV67 z6W+Pv{5-lB2aP4wMp5gby7`KHjSCUpiV$|ECdWuUjDp@B8b&$M!zjwPIq8(!nX-R^ zS_d$#z?^$^0XL?A&t%dqw=*n2gCh$AmfERDSK2X~dRy-5ZCR7<>YY)|2G`t~gSx;i z(jm9A461^lKJ*?jGJ@`oU$Zr^RxIYgd9?yUl|o2aF4UX~n8PfT$PJ_!36J4%@7=-K zB(9#*2UW;3p%)>{f|9~akOQ4xR_B?K zrE?X!giDZ+Kr)0>l>4^Hfquo(CG^>42pyUmGV0`ZWOCR0Dd`BwjqbUSgd7=Rp}A6E zWCTV=U}OYFMv!`MM;A1(&u##qplA@J=JJ)5@DO!v)E6*2y48Qj1q>r2(jkIU)NC`j zU5t#NQB7*H6N6>wXhF57dqVZQ4@-cA(f&+FiaQovux`*_J4k~3a z3`*E*kg@g+BV(a+V;@wPI)#xD6w_OfQ4XDf?kbeU!uKtN5c&;7EJj8U7#Z;^4O#fZ zkr9{`0mJ=_ECa-~D36z?ze-FG1m*=dgJxcU=RQyiw?JqzXFZy2K{*>|$>tK21AOgN zP`G$$bO9P1Kr4#aeefUfF6N?5I{VU3y4GSf)HIFSn~b5)H07K$S2mB?~LX zk>N=q{s3soNV0xuV^oE4Zf+ZVR~P@U<9au!!K(VD9N*p4iTJ`;ehhq-3)`a1gybVz zl7zRUgrL8Pm1JZ)Dr!$1~eRoAHY6JIdJD5aSdVm z-s_lpCDDQC z<-}&$8xxaxk8fPw+aw{fCM)8_je-DRMLbZ?_&0#&mO!is3zwkBdmTm>NFGlgv3kE< zzdiTFuV2sh=@?W}eJS8kNYRI|A|~y%H|^g@R`~XE{?+ylPo+O3^0+oVpHJnUy9Z*i01MY5M!JB1~vj#LD%vU2_^KK{j3(T=nbPV8zoduU>5%`0b@*=S?d=La zmmq8*P~rq>G*-l+!zuTG74f8Qg6u3ibjEkrBCKBB+3B7&oBXj{zG=$ER#O%%&p)?mNouFyRi?@rbKG9MH!Fhe z$Qqp$F{^8ni{X0~zY?8UH~Hp;A6o=(OX@T>-v0T#Uxe`)d4sZW;z-tAGru$BY3l7E z`QMmTD0f9#q--j>Hf76(akhe@*rqLmrswY(GJ2D%!qDNi+tOeqn-=~IRzzTV6bY<| zXX?b!vLa4ANc`d77a!aWTOJWve7}D{NLobdm1z;TC*0c*wc=&QKn*Lxm|;aM>v0EI z5m61WBJ#_d2B86T!!KjRiuinX`C`4l_FedR)mX|6~P9V_()a+TcfG8FHTO*Tb{-pR^20c znrz0z>ysBe-A62#VNfYLBh7J;DM#mUdFEy>Jjofon_Rtf{J!4!vx6q;%?P~quZOQ4 zBg@xdnduQO3@c(YVny8e5LU!=OFqMj_)9foD%XZs5p0dmTULZiSI0K`Df+}4b;E85 zZ7-ceu8>2!JQ7ZH-?J`vym05?s$PSwW)<&g^39;Fi^pB~Iwj|d+4oEiv6UiR=^S#+ zFnq4B|D1Tnnwo!94#nNFx3WDR`}G?+|KEA4XA=@5uGuadzez<5^ZoYv@Es1ULmHez zdW0*=AqmQ$Cm)hQV~x+KRBkGnK2p~h2iVTR2VToScm`@Zlva3dAiNg~ZB7MTwBK=N z`?BDwrOQftTG+-5JxbFI^;U;wUg!2>gvVBjaHECirWGEWQnBzF?s4it8o*K8c#V+~w2fYN}boRVT zhA9}~v6Uj+Y2mqRg~z5;EWA%GuZH(exPP4Rgnp-0stz@T=Wb}!Ukt))Syy-+KzRGl zpTFUL?ipu!$VKJN`}6k?u=Xy=y1O{pE7sS-X4v&2MtE$chz_*yI%tK*rc^AvhEM#b zUP5&EIN|kaxm2a{s3E)#o4#4`83?a+UEz6v@E$ttbKhTPXc=g0<2%iW;$@yYA254? z@59*5nfk=9TlE>?v6Uh`XyJKig~z5;EWA%GuZH(eczm4jdU&{~RGu}2=dmwRM1b(x z)D@m52(R1Ly=NbU#GZHBk~UM=KhELJWpVMzLYMW0x#qow&vJ2MgvVBj@T7(3sTCfZ zQnBzFKJlM=3E}y1!V4Nvp;CF(5T2*KV)tSYo>g7pd4cd=IxbuC<=mNFw-@hNpR;IG zN~-tRsOv>L+83BeM{cR?qHginN)cYP@VvCbV^b;?-lvvV!}}+^K2CVPg?yFDyN2+* z5^m(R1mW4%6`nT;FFm2_Q1Zux(_5Ws?=L&mY2MV3(wU2X?!KY>SN$scC&!LvT0FK= zgf}fbZ>{jyl!}Gd@QMG_O9=0e6JCe4-Bl`|8p89of8_oX2+zK*@O(gc9I0$_uJeGn zuA>}}WTYEd_AFnc-z_WR_07?j{MRg=Cu4-iR*LYUh3BIc9-C6J@IJM?8s0zQ^Krs+ zp0q@z@~t5}pIfWiNB)Is@_gPaXClRIoF);-Ls!J`1y-x z&SR!B!ec8%_|n4j)e4VIsaSXopZHI`gz)`1;n`QFt5m!i!t?#qNAgGPe>63L8lF7T zd&Dr`uvn3ZA0=-5z3|`_6cnHbzx;v&c{P8dMLeEAPtPx)V{o8fV30pASdZuD9~kVf z$K^GCRqAhXN@^OF!sY5sr^ckzU;6eFw&ib2{;l2(2#x9+4%4c=nG@0CZ&i6*+5b8M zHS#}F(C5G2oX!m(X}vT5gZ=8}KQA~K=fBQiHu8u5JpYcqJbzz*KX1R_E<9cr|BgPv zor60D2XTW(@pzqw1& (TestEthereumNodeHandle, EthereumContractAddress) { - const SN_CONTRACT_ADDR: &str = "0xe2aF2c1AE11fE13aFDb7598D0836398108a4db0A"; - // Verify correct Ganache version. - let ganache_version = String::from_utf8_lossy( - &Command::new("ganache") - .arg("--version") - .output() - .expect("Failed to get Ganache version, check if it is installed.") - .stdout, - ) - .to_string(); - const GANACHE_VERSION_PREFIX: &str = "ganache v"; - let ganache_version = ganache_version - .strip_prefix(GANACHE_VERSION_PREFIX) - .expect("Failed to parse Ganache version."); - let major_version = ganache_version - .split('.') - .next() - .expect("Failed to parse Ganache major version.") - .parse::() - .expect("Failed to parse Ganache major version."); - assert!( - major_version >= MINIMAL_GANACHE_VERSION, - "Wrong Ganache version, expecting at least version 7. To install, run `npm install -g \ - ganache`." - ); - const DB_NAME: &str = "ganache-db"; - let db_archive_path = format!("resources/{DB_NAME}.tar"); - - // Unpack the Ganache db tar file into a temporary dir. - let mut archive = Archive::new(File::open(db_archive_path).expect("Ganache db not found.")); - let ganache_db = tempdir().unwrap(); - archive.unpack(ganache_db.path()).unwrap(); - - // Start Ganache instance. This will panic if Ganache is not installed. - let db_path = ganache_db.path().join(DB_NAME); - let ganache = Ganache::new().args(["--db", db_path.to_str().unwrap()]).spawn(); - - ((ganache, ganache_db), SN_CONTRACT_ADDR.to_string().parse().unwrap()) -} - // FIXME: This should be part of AnvilBaseLayer, however the usage in the simulator doesn't allow // that, since it is coupled with a manual invocation of an anvil instance that is managed inside // the github workflow. diff --git a/docs/papyrus/CONTRIBUTING.md b/docs/papyrus/CONTRIBUTING.md index afcc62da74c..0f5a6f6b737 100644 --- a/docs/papyrus/CONTRIBUTING.md +++ b/docs/papyrus/CONTRIBUTING.md @@ -44,9 +44,6 @@ git clone https://github.com/starkware-libs/papyrus Then, you will need to install - [Rust](https://www.rust-lang.org/tools/install) (1.73 or higher) - [Rust nightly toolchain 2022-07-27](https://rust-lang.github.io/rustup/installation/index.html#installing-nightly) -- [Ganache 7.4.3](https://www.npmjs.com/package/ganache) - - You'll need to install 7.4.3 and not a version above it. We'll relax this in the future. - - You'll need Ganache only for the tests of the [papyrus_base_layer](../../crates/papyrus_base_layer/) crate. ### CI Your code will need to pass [CI](../.github/workflows/ci.yml) before it can be merged. This means your code will need to: From e7b74845100f971059e612cda5d338f1568b5ab1 Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:51:27 +0200 Subject: [PATCH 310/313] blockifier: refactor get_particia_update_resources (#10042) --- crates/blockifier/src/bouncer.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/blockifier/src/bouncer.rs b/crates/blockifier/src/bouncer.rs index 44ae9959a08..ff6de60e6e7 100644 --- a/crates/blockifier/src/bouncer.rs +++ b/crates/blockifier/src/bouncer.rs @@ -946,15 +946,21 @@ pub fn map_class_hash_to_casm_hash_computation_resources( // and number of visited leaves includes reads and writes. pub fn get_particia_update_resources(n_visited_storage_entries: usize) -> ExecutionResources { const TREE_HEIGHT_UPPER_BOUND: usize = 24; - let n_updates = n_visited_storage_entries * TREE_HEIGHT_UPPER_BOUND; - - ExecutionResources { - // TODO(Yoni, 1/5/2024): re-estimate this. - n_steps: 32 * n_updates, - // For each Patricia update there are two hash calculations. - builtin_instance_counter: HashMap::from([(BuiltinName::pedersen, 2 * n_updates)]), + // TODO(Yoni, 1/5/2024): re-estimate this. + const STEPS_IN_TREE_PER_HEIGHT: usize = 16; + const PEDERSENS_PER_HEIGHT: usize = 1; + + let resources_per_tree_access = ExecutionResources { + n_steps: TREE_HEIGHT_UPPER_BOUND * STEPS_IN_TREE_PER_HEIGHT, + builtin_instance_counter: HashMap::from([( + BuiltinName::pedersen, + TREE_HEIGHT_UPPER_BOUND * PEDERSENS_PER_HEIGHT, + )]), n_memory_holes: 0, - } + }; + + // Multiply by 2 since each storage entry is accessed in both the old and new tree. + &resources_per_tree_access * (n_visited_storage_entries * 2) } pub fn verify_tx_weights_within_max_capacity( From eca860dbab930bd45783f0d6814e68b05813a566 Mon Sep 17 00:00:00 2001 From: Yoni <78365039+Yoni-Starkware@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:54:54 +0200 Subject: [PATCH 311/313] blockifier: add regression test to bouncer update (#10051) --- crates/blockifier/src/bouncer_test.rs | 38 ++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/crates/blockifier/src/bouncer_test.rs b/crates/blockifier/src/bouncer_test.rs index dde9bbf5dd7..042646f5507 100644 --- a/crates/blockifier/src/bouncer_test.rs +++ b/crates/blockifier/src/bouncer_test.rs @@ -410,23 +410,55 @@ fn test_bouncer_try_update_n_txs( let accumulated_weights = TxWeights { bouncer_weights, ..Default::default() }; let mut bouncer = Bouncer { accumulated_weights, bouncer_config, ..Bouncer::empty() }; + bouncer.bouncer_config.block_max_capacity.sierra_gas = GasAmount::MAX; + bouncer.bouncer_config.block_max_capacity.proving_gas = GasAmount::MAX; // Prepare first tx resources. let mut first_transactional_state = TransactionalState::create_transactional(&mut state); - let first_tx_state_changes_keys = - first_transactional_state.to_state_diff().unwrap().state_maps.keys(); + let first_tx_state_changes_keys = StateChangesKeys { + storage_keys: HashSet::from([(contract_address!(1_u128), storage_key!(1_u128))]), + modified_contracts: HashSet::from([contract_address!(1_u128)]), + ..StateChangesKeys::default() + }; + let first_tx_execution_summary = ExecutionSummary { + visited_storage_entries: HashSet::from([ + (contract_address!(1_u128), storage_key!(1_u128)), + (contract_address!(2_u128), storage_key!(2_u128)), + ]), + ..ExecutionSummary::default() + }; // Try to update the bouncer. let mut result = bouncer.try_update( &first_transactional_state, &first_tx_state_changes_keys, - &ExecutionSummary::default(), + &first_tx_execution_summary, &BuiltinCounterMap::default(), &TransactionResources::default(), &block_context.versioned_constants, ); assert_matches!(result, Ok(())); + // Regression test to cover complicated calculations such as patricia update. + expect![ + r#" + BouncerWeights { + l1_gas: 10, + message_segment_length: 10, + n_events: 10, + state_diff_size: 14, + sierra_gas: GasAmount( + 542410, + ), + n_txs: 20, + proving_gas: GasAmount( + 702922, + ), + } + "# + ] + .assert_debug_eq(&bouncer.accumulated_weights.bouncer_weights); + // Prepare second tx resources. let mut second_transactional_state = TransactionalState::create_transactional(&mut first_transactional_state); From e88251101395c5496b07d0e014b05290e3a6d050 Mon Sep 17 00:00:00 2001 From: Arnon Hod Date: Mon, 10 Nov 2025 19:04:28 +0200 Subject: [PATCH 312/313] apollo_integration_tests: add revert_l1_handler_tx_flow (#9960) --- crates/apollo_infra_utils/src/test_utils.rs | 1 + .../tests/common/mod.rs | 2 - .../tests/l1_handler_flow_test.rs | 39 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 crates/apollo_integration_tests/tests/l1_handler_flow_test.rs diff --git a/crates/apollo_infra_utils/src/test_utils.rs b/crates/apollo_infra_utils/src/test_utils.rs index cdd807c1ffb..859ae6d1d2e 100644 --- a/crates/apollo_infra_utils/src/test_utils.rs +++ b/crates/apollo_infra_utils/src/test_utils.rs @@ -31,6 +31,7 @@ pub enum TestIdentifier { EndToEndFlowTestManyTxs, EndToEndFlowTestCustomSyscallInvokeTxs, EndToEndFlowTestCustomCairo0Txs, + RevertedL1HandlerTx, InfraUnitTests, PositiveFlowIntegrationTest, RestartFlowIntegrationTest, diff --git a/crates/apollo_integration_tests/tests/common/mod.rs b/crates/apollo_integration_tests/tests/common/mod.rs index 0967f543974..b6243edbb64 100644 --- a/crates/apollo_integration_tests/tests/common/mod.rs +++ b/crates/apollo_integration_tests/tests/common/mod.rs @@ -167,8 +167,6 @@ pub async fn end_to_end_flow(args: EndToEndFlowArgs) { } assert_full_blocks_flow(&global_recorder_handle, expecting_full_blocks); - // TODO(Arni): Remove this once we have a test that expects reverted transactions. - assert!(!expecting_reverted_transactions, "No test should expect reverted transactions."); assert_on_number_of_reverted_transactions_flow( &global_recorder_handle, expecting_reverted_transactions, diff --git a/crates/apollo_integration_tests/tests/l1_handler_flow_test.rs b/crates/apollo_integration_tests/tests/l1_handler_flow_test.rs new file mode 100644 index 00000000000..c0251d2a70d --- /dev/null +++ b/crates/apollo_integration_tests/tests/l1_handler_flow_test.rs @@ -0,0 +1,39 @@ +use apollo_infra_utils::test_utils::TestIdentifier; +use apollo_integration_tests::utils::create_l1_to_l2_messages_args; +use blockifier::bouncer::BouncerWeights; +use mempool_test_utils::starknet_api_test_utils::MultiAccountTransactionGenerator; +use starknet_api::transaction::L1HandlerTransaction; + +use crate::common::{end_to_end_flow, test_single_tx, EndToEndFlowArgs, TestScenario}; + +mod common; + +/// Number of threads is 3 = Num of sequencer + 1 for the test thread. +#[tokio::test(flavor = "multi_thread", worker_threads = 3)] +async fn reverted_l1_handler_tx_flow() { + end_to_end_flow( + EndToEndFlowArgs::new( + TestIdentifier::RevertedL1HandlerTx, + create_test_scenarios(), + BouncerWeights::default().proving_gas, + ) + .expecting_reverted_transactions(), + ) + .await +} + +fn create_test_scenarios() -> Vec { + vec![TestScenario { + create_rpc_txs_fn: |_| vec![], + create_l1_to_l2_messages_args_fn: create_l1_to_l2_reverted_message_args, + test_tx_hashes_fn: test_single_tx, + }] +} + +fn create_l1_to_l2_reverted_message_args( + tx_generator: &mut MultiAccountTransactionGenerator, +) -> Vec { + const N_TXS: usize = 1; + const SHOULD_REVERT: bool = true; + create_l1_to_l2_messages_args(tx_generator, N_TXS, SHOULD_REVERT) +} From cb82f8d5cef0928e70f46485350ec847096b6ecc Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Tue, 11 Nov 2025 09:07:11 +0200 Subject: [PATCH 313/313] blockifier: add concurrent transfers benchmark (#9965) --- .github/workflows/blockifier_ci.yml | 2 +- .../bench_tools/src/types/benchmark_config.rs | 12 +-- crates/blockifier/benches/main.rs | 78 ++++++++++++++++--- .../src/test_utils/transfers_generator.rs | 8 +- 4 files changed, 78 insertions(+), 22 deletions(-) diff --git a/.github/workflows/blockifier_ci.yml b/.github/workflows/blockifier_ci.yml index 99cfeff937f..24e1c930c96 100644 --- a/.github/workflows/blockifier_ci.yml +++ b/.github/workflows/blockifier_ci.yml @@ -123,4 +123,4 @@ jobs: clean: false # Benchmark the current branch and compare to the previous run. - - run: cargo run -p bench_tools -- run-and-compare --package blockifier --out /tmp/new_results --regression-limit 8.0 + # - run: cargo run -p bench_tools -- run-and-compare --package blockifier --out /tmp/new_results --regression-limit 8.0 diff --git a/crates/bench_tools/src/types/benchmark_config.rs b/crates/bench_tools/src/types/benchmark_config.rs index f92758da726..7525ad10599 100644 --- a/crates/bench_tools/src/types/benchmark_config.rs +++ b/crates/bench_tools/src/types/benchmark_config.rs @@ -61,15 +61,13 @@ pub const BENCHMARKS: &[BenchmarkConfig] = &[ ]), }, BenchmarkConfig { - name: "transfers_benchmark_cairo_native", + name: "transfers_sequential_benchmark_cairo_native", package: "blockifier", cmd_args: &[ "bench", - "-p", - "blockifier", "--bench", "blockifier", - "transfers", + "transfers_sequential", "--features", "testing,cairo_native", ], @@ -77,15 +75,13 @@ pub const BENCHMARKS: &[BenchmarkConfig] = &[ criterion_benchmark_names: None, // Single benchmark with same name. }, BenchmarkConfig { - name: "transfers_benchmark_vm", + name: "transfers_sequential_benchmark_vm", package: "blockifier", cmd_args: &[ "bench", - "-p", - "blockifier", "--bench", "blockifier", - "transfers", + "transfers_sequential", "--features", "testing", ], diff --git a/crates/blockifier/benches/main.rs b/crates/blockifier/benches/main.rs index a472662ad9e..d89edbe6e84 100644 --- a/crates/blockifier/benches/main.rs +++ b/crates/blockifier/benches/main.rs @@ -14,13 +14,18 @@ use std::sync::Arc; use apollo_infra_utils::set_global_allocator; use blockifier::blockifier::concurrent_transaction_executor::ConcurrentTransactionExecutor; -use blockifier::blockifier::config::{ConcurrencyConfig, TransactionExecutorConfig}; +use blockifier::blockifier::config::{ + ConcurrencyConfig, + TransactionExecutorConfig, + WorkerPoolConfig, +}; use blockifier::blockifier::transaction_executor::TransactionExecutor; use blockifier::concurrency::worker_pool::WorkerPool; use blockifier::context::BlockContext; use blockifier::state::cached_state::CachedState; use blockifier::test_utils::dict_state_reader::DictStateReader; use blockifier::test_utils::transfers_generator::{ + ExecutorWrapper, RecipientGeneratorType, TransfersGenerator, TransfersGeneratorConfig, @@ -36,7 +41,8 @@ use starknet_api::test_utils::invoke::executable_invoke_tx; use starknet_api::transaction::TransactionVersion; /// The name of the benchmarks without the suffix. -const TRANSFERS_BENCHMARK_NAME: &str = "transfers_benchmark"; +const SEQUENTIAL_TRANSFERS_BENCHMARK_NAME: &str = "transfers_sequential_benchmark"; +const CONCURRENT_TRANSFERS_BENCHMARK_NAME: &str = "transfers_concurrent_benchmark"; const HEAVY_TX_CONCURRENT_BENCHMARK_NAME: &str = "heavy_tx_benchmark_concurrent"; const HEAVY_TX_SEQUENTIAL_BENCHMARK_NAME: &str = "heavy_tx_benchmark_sequential"; @@ -48,6 +54,12 @@ const BENCHMARK_NAME_SUFFIX: &str = "_vm"; const HEAVY_TX_ENTRY_POINT: &str = "test_builtin_counts_consistency"; +/// Cairo version to use for benchmarks, selected based on the cairo_native feature. +#[cfg(feature = "cairo_native")] +const CAIRO_VERSION: CairoVersion = CairoVersion::Cairo1(RunnableCairo1::Native); +#[cfg(not(feature = "cairo_native"))] +const CAIRO_VERSION: CairoVersion = CairoVersion::Cairo1(RunnableCairo1::Casm); + // TODO(Arni): Consider how to run this benchmark both with and without setting the allocator. Maybe // hide this macro call under a feature, and run this benchmark regularly or with // `cargo bench --bench blockifier --feature=specified_allocator` @@ -83,14 +95,13 @@ fn setup_heavy_tx_benchmark( } /// Benchmarks the execution phase of the transfers flow. +/// Benchmarks the execution phase of the transfers flow (sequential). /// The sender account is chosen round-robin. /// The recipient account is chosen randomly. -/// The transactions are executed concurrently. -pub fn transfers_benchmark(c: &mut Criterion) { +pub fn transfers_benchmark_sequential(c: &mut Criterion) { let transfers_generator_config = TransfersGeneratorConfig { recipient_generator_type: RecipientGeneratorType::Random, - #[cfg(feature = "cairo_native")] - cairo_version: CairoVersion::Cairo1(RunnableCairo1::Native), + cairo_version: CAIRO_VERSION, concurrency_config: ConcurrencyConfig::create_for_testing(false), ..Default::default() }; @@ -98,12 +109,12 @@ pub fn transfers_benchmark(c: &mut Criterion) { // Benchmark only the execution phase (run_block_of_transfers call). // Transaction generation and state setup happen for each iteration but are not timed. c.bench_function( - &format!("{}{}", TRANSFERS_BENCHMARK_NAME, BENCHMARK_NAME_SUFFIX), + &format!("{}{}", SEQUENTIAL_TRANSFERS_BENCHMARK_NAME, BENCHMARK_NAME_SUFFIX), |benchmark| { benchmark.iter_batched( || { // Setup: prepare transactions and executor (not measured). - transfers_generator.prepare_to_run_block_of_transfers(None) + transfers_generator.prepare_to_run_block_of_transfers(None, None) }, |(txs, mut executor_wrapper)| { // Measured: execute the transactions. @@ -115,6 +126,52 @@ pub fn transfers_benchmark(c: &mut Criterion) { ); } +/// Benchmarks the execution phase of the transfers flow (concurrent). +/// The sender account is chosen round-robin. +/// The recipient account is chosen randomly. +pub fn transfers_benchmark_concurrent(c: &mut Criterion) { + let transfers_generator_config = TransfersGeneratorConfig { + recipient_generator_type: RecipientGeneratorType::Random, + #[cfg(feature = "cairo_native")] + cairo_version: CAIRO_VERSION, + concurrency_config: ConcurrencyConfig::create_for_testing(true), + ..Default::default() + }; + let mut transfers_generator = TransfersGenerator::new(transfers_generator_config); + + // Create worker pool before benchmarking. + let worker_pool = Arc::new(WorkerPool::start(&WorkerPoolConfig::create_for_testing())); + + // Benchmark only the execution phase (run_block_of_transfers call). + // Transaction generation and state setup happen for each iteration but are not timed. + c.bench_function( + &format!("{}{}", CONCURRENT_TRANSFERS_BENCHMARK_NAME, BENCHMARK_NAME_SUFFIX), + |benchmark| { + benchmark.iter_batched( + || { + // Setup: prepare transactions and executor (not measured). + transfers_generator + .prepare_to_run_block_of_transfers(Some(worker_pool.clone()), None) + }, + |(txs, mut executor_wrapper)| { + // Measured: execute the transactions. + TransfersGenerator::run_block_of_transfers(&txs, &mut executor_wrapper, None); + match executor_wrapper { + ExecutorWrapper::Concurrent(ref mut executor, _) => { + executor.abort_block(); + } + _ => panic!("Executor wrapper is not a concurrent executor"), + } + }, + BatchSize::SmallInput, + ) + }, + ); + + // Cleanup worker pool after all benchmark iterations complete. + Arc::try_unwrap(worker_pool).expect("More than one instance of worker pool exists").join(); +} + /// Benchmarks the execution phase of `HEAVY_TX_ENTRY_POINT` using /// ConcurrentTransactionExecutor. pub fn heavy_tx_benchmark_concurrent(c: &mut Criterion) { @@ -143,7 +200,6 @@ pub fn heavy_tx_benchmark_concurrent(c: &mut Criterion) { // Measured: execute the transaction. let results = executor.add_txs_and_wait(&[tx]); let tx_execution_info = &results[0].as_ref().unwrap().0; - tx_execution_info.check_call_infos_native_execution(true); assert!( !tx_execution_info.is_reverted(), "Transaction reverted: {:?}", @@ -196,8 +252,10 @@ pub fn heavy_tx_benchmark_sequential(c: &mut Criterion) { criterion_group! { name = benches; config = Criterion::default().sample_size(30); - targets = transfers_benchmark, + targets = transfers_benchmark_sequential, + transfers_benchmark_concurrent, heavy_tx_benchmark_concurrent, heavy_tx_benchmark_sequential } + criterion_main!(benches); diff --git a/crates/blockifier/src/test_utils/transfers_generator.rs b/crates/blockifier/src/test_utils/transfers_generator.rs index 03a1c87c249..a6e8e709a86 100644 --- a/crates/blockifier/src/test_utils/transfers_generator.rs +++ b/crates/blockifier/src/test_utils/transfers_generator.rs @@ -175,6 +175,7 @@ impl TransfersGenerator { /// Returns the transactions and the executor wrapper. pub fn prepare_to_run_block_of_transfers( &mut self, + worker_pool: Option>>>, timeout: Option, ) -> (Vec, ExecutorWrapper) { // Reset nonce manager since we create a fresh state. @@ -204,8 +205,9 @@ impl TransfersGenerator { }; let executor_wrapper = if executor_config.concurrency_config.enabled { - let worker_pool = - Arc::new(WorkerPool::start(&executor_config.get_worker_pool_config())); + let worker_pool = worker_pool.unwrap_or_else(|| { + Arc::new(WorkerPool::start(&executor_config.get_worker_pool_config())) + }); let executor = ConcurrentTransactionExecutor::new_for_testing( state, @@ -287,7 +289,7 @@ impl TransfersGenerator { timeout: Option, ) -> (BlockExecutionSummary, Vec) { // Prepare: generates transactions and creates executor. - let (txs, mut executor_wrapper) = self.prepare_to_run_block_of_transfers(timeout); + let (txs, mut executor_wrapper) = self.prepare_to_run_block_of_transfers(None, timeout); // Run: executes the transactions and asserts that none of them reverted. let execution_deadline = timeout.map(|timeout_duration| Instant::now() + timeout_duration);