From abeee8190d3c3a5e577d71024bdfb30ff516ad03 Mon Sep 17 00:00:00 2001 From: Alex Ostrovski Date: Tue, 22 Oct 2024 16:19:30 +0300 Subject: [PATCH] fix(en): Return `SyncState` health check (#3142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Returns `SyncState`-based health check, which was removed when transitioning to the node framework. ## Why ❔ This health check looks useful and is used at least in some internal automations. ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [x] Tests for the changes have been added / updated. - [x] Documentation comments have been added / updated. - [x] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`. --- core/bin/external_node/src/tests/mod.rs | 14 +++++++++++--- .../layers/state_keeper/external_io.rs | 6 ++++++ .../implementations/layers/sync_state_updater.rs | 8 ++++++++ core/node/node_sync/src/sync_state.rs | 1 + 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/core/bin/external_node/src/tests/mod.rs b/core/bin/external_node/src/tests/mod.rs index b21dbd0db9a..c5dd88748e5 100644 --- a/core/bin/external_node/src/tests/mod.rs +++ b/core/bin/external_node/src/tests/mod.rs @@ -22,10 +22,18 @@ const POLL_INTERVAL: Duration = Duration::from_millis(100); #[tracing::instrument] // Add args to the test logs async fn external_node_basics(components_str: &'static str) { let _guard = zksync_vlog::ObservabilityBuilder::new().try_build().ok(); // Enable logging to simplify debugging - let (env, env_handles) = utils::TestEnvironment::with_genesis_block(components_str).await; - let expected_health_components = utils::expected_health_components(&env.components); + let mut expected_health_components = utils::expected_health_components(&env.components); + let expected_shutdown_components = expected_health_components.clone(); + let has_core_or_api = env.components.0.iter().any(|component| { + [Component::Core, Component::HttpApi, Component::WsApi].contains(component) + }); + if has_core_or_api { + // The `sync_state` component doesn't signal its shutdown, but should be present in the list of components + expected_health_components.push("sync_state"); + } + let l2_client = utils::mock_l2_client(&env); let eth_client = utils::mock_eth_client(env.config.diamond_proxy_address()); @@ -84,7 +92,7 @@ async fn external_node_basics(components_str: &'static str) { let health_data = app_health.check_health().await; tracing::info!(?health_data, "final health data"); assert_matches!(health_data.inner().status(), HealthStatus::ShutDown); - for name in expected_health_components { + for name in expected_shutdown_components { let component_health = &health_data.components()[name]; assert_matches!(component_health.status(), HealthStatus::ShutDown); } diff --git a/core/node/node_framework/src/implementations/layers/state_keeper/external_io.rs b/core/node/node_framework/src/implementations/layers/state_keeper/external_io.rs index 31b76550767..2c23f5aa9a1 100644 --- a/core/node/node_framework/src/implementations/layers/state_keeper/external_io.rs +++ b/core/node/node_framework/src/implementations/layers/state_keeper/external_io.rs @@ -8,6 +8,7 @@ use zksync_types::L2ChainId; use crate::{ implementations::resources::{ action_queue::ActionQueueSenderResource, + healthcheck::AppHealthCheckResource, main_node_client::MainNodeClientResource, pools::{MasterPool, PoolResource}, state_keeper::{ConditionalSealerResource, StateKeeperIOResource}, @@ -26,6 +27,7 @@ pub struct ExternalIOLayer { #[derive(Debug, FromContext)] #[context(crate = crate)] pub struct Input { + pub app_health: AppHealthCheckResource, pub pool: PoolResource, pub main_node_client: MainNodeClientResource, } @@ -57,6 +59,10 @@ impl WiringLayer for ExternalIOLayer { async fn wire(self, input: Self::Input) -> Result { // Create `SyncState` resource. let sync_state = SyncState::default(); + let app_health = &input.app_health.0; + app_health + .insert_custom_component(Arc::new(sync_state.clone())) + .map_err(WiringError::internal)?; // Create `ActionQueueSender` resource. let (action_queue_sender, action_queue) = ActionQueue::new(); diff --git a/core/node/node_framework/src/implementations/layers/sync_state_updater.rs b/core/node/node_framework/src/implementations/layers/sync_state_updater.rs index 1f86b43f7a5..dd2652dfddb 100644 --- a/core/node/node_framework/src/implementations/layers/sync_state_updater.rs +++ b/core/node/node_framework/src/implementations/layers/sync_state_updater.rs @@ -1,9 +1,12 @@ +use std::sync::Arc; + use zksync_dal::{ConnectionPool, Core}; use zksync_node_sync::SyncState; use zksync_web3_decl::client::{DynClient, L2}; use crate::{ implementations::resources::{ + healthcheck::AppHealthCheckResource, main_node_client::MainNodeClientResource, pools::{MasterPool, PoolResource}, sync_state::SyncStateResource, @@ -24,6 +27,7 @@ pub struct SyncStateUpdaterLayer; pub struct Input { /// Fetched to check whether the `SyncState` was already provided by another layer. pub sync_state: Option, + pub app_health: AppHealthCheckResource, pub master_pool: PoolResource, pub main_node_client: MainNodeClientResource, } @@ -62,6 +66,10 @@ impl WiringLayer for SyncStateUpdaterLayer { let MainNodeClientResource(main_node_client) = input.main_node_client; let sync_state = SyncState::default(); + let app_health = &input.app_health.0; + app_health + .insert_custom_component(Arc::new(sync_state.clone())) + .map_err(WiringError::internal)?; Ok(Output { sync_state: Some(sync_state.clone().into()), diff --git a/core/node/node_sync/src/sync_state.rs b/core/node/node_sync/src/sync_state.rs index e061ff7da01..f8a2fe00ec0 100644 --- a/core/node/node_sync/src/sync_state.rs +++ b/core/node/node_sync/src/sync_state.rs @@ -173,6 +173,7 @@ impl CheckHealth for SyncState { Health::from(&*self.0.borrow()) } } + impl SyncStateInner { fn is_synced(&self) -> (bool, Option) { if let (Some(main_node_block), Some(local_block)) = (self.main_node_block, self.local_block)