Skip to content

Commit

Permalink
Merge branch 'main' into feat/pli_config_cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
ilitteri authored May 13, 2024
2 parents 98d9b37 + a67325c commit 63f1b29
Show file tree
Hide file tree
Showing 49 changed files with 1,336 additions and 581 deletions.
2 changes: 1 addition & 1 deletion .github/release-please/manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"core": "24.1.0",
"prover": "14.0.0"
"prover": "14.1.0"
}
4 changes: 2 additions & 2 deletions .github/workflows/ci-core-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ jobs:
matrix:
consensus: [false, true]
base_token: ["Eth", "Custom"]
deployment_mode: ["Rollup", "Validium"]
deployment_mode: ["Rollup"] #, "Validium"] - Temporary disable validium until PR/1910.
env:
SERVER_COMPONENTS: "api,tree,eth,state_keeper,housekeeper,commitment_generator${{ matrix.consensus && ',consensus' || '' }}"

Expand Down Expand Up @@ -278,7 +278,7 @@ jobs:
matrix:
consensus: [false, true]
base_token: ["Eth", "Custom"]
deployment_mode: ["Rollup", "Validium"]
deployment_mode: ["Rollup"] # "Validium"] - Temporary disable validium until PR/1910.
runs-on: [matterlabs-ci-runner]

env:
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 44 additions & 15 deletions core/bin/external_node/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{
env,
ffi::OsString,
num::{NonZeroU32, NonZeroU64, NonZeroUsize},
time::Duration,
};
Expand Down Expand Up @@ -34,14 +35,40 @@ use zksync_web3_decl::{
namespaces::{EnNamespaceClient, ZksNamespaceClient},
};

use crate::config::observability::ObservabilityENConfig;

pub(crate) mod observability;
#[cfg(test)]
mod tests;

const BYTES_IN_MEGABYTE: usize = 1_024 * 1_024;

/// Encapsulation of configuration source with a mock implementation used in tests.
trait ConfigurationSource: 'static {
type Vars<'a>: Iterator<Item = (OsString, OsString)> + 'a;

fn vars(&self) -> Self::Vars<'_>;

fn var(&self, name: &str) -> Option<String>;
}

#[derive(Debug)]
struct Environment;

impl ConfigurationSource for Environment {
type Vars<'a> = env::VarsOs;

fn vars(&self) -> Self::Vars<'_> {
env::vars_os()
}

fn var(&self, name: &str) -> Option<String> {
env::var(name).ok()
}
}

/// This part of the external node config is fetched directly from the main node.
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[derive(Debug, Deserialize)]
pub(crate) struct RemoteENConfig {
pub bridgehub_proxy_addr: Option<Address>,
pub state_transition_proxy_addr: Option<Address>,
Expand Down Expand Up @@ -165,7 +192,7 @@ impl RemoteENConfig {
}
}

#[derive(Debug, Deserialize, Clone, PartialEq)]
#[derive(Debug, Deserialize)]
pub(crate) enum BlockFetcher {
ServerAPI,
Consensus,
Expand All @@ -174,7 +201,7 @@ pub(crate) enum BlockFetcher {
/// This part of the external node config is completely optional to provide.
/// It can tweak limits of the API, delay intervals of certain components, etc.
/// If any of the fields are not provided, the default values will be used.
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Deserialize)]
pub(crate) struct OptionalENConfig {
// User-facing API limits
/// Max possible limit of filters to be in the API state at once.
Expand Down Expand Up @@ -315,8 +342,6 @@ pub(crate) struct OptionalENConfig {
database_slow_query_threshold_ms: Option<u64>,

// Other config settings
/// Port on which the Prometheus exporter server is listening.
pub prometheus_port: Option<u16>,
/// Capacity of the queue for asynchronous miniblock sealing. Once this many miniblocks are queued,
/// sealing will block until some of the miniblocks from the queue are processed.
/// 0 means that sealing is synchronous; this is mostly useful for performance comparison, testing etc.
Expand Down Expand Up @@ -606,7 +631,7 @@ impl OptionalENConfig {
}

/// This part of the external node config is required for its operation.
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[derive(Debug, Deserialize)]
pub(crate) struct RequiredENConfig {
/// L1 chain ID (e.g., 9 for Ethereum mainnet). This ID will be checked against the `eth_client_url` RPC provider on initialization
/// to ensure that there's no mismatch between the expected and actual L1 network.
Expand Down Expand Up @@ -664,7 +689,7 @@ impl RequiredENConfig {
/// While also mandatory, it historically used different naming scheme for corresponding
/// environment variables.
/// Thus it is kept separately for backward compatibility and ease of deserialization.
#[derive(Debug, Clone, Deserialize, PartialEq)]
#[derive(Debug, Deserialize)]
pub(crate) struct PostgresConfig {
database_url: SensitiveUrl,
pub max_connections: u32,
Expand Down Expand Up @@ -699,7 +724,7 @@ impl PostgresConfig {

/// Experimental part of the external node config. All parameters in this group can change or disappear without notice.
/// Eventually, parameters from this group generally end up in the optional group.
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Deserialize)]
pub(crate) struct ExperimentalENConfig {
// State keeper cache config
/// Block cache capacity of the state keeper RocksDB cache. The default value is 128 MB.
Expand Down Expand Up @@ -767,26 +792,27 @@ impl SnapshotsRecoveryConfig {
}
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Deserialize)]
pub struct ApiComponentConfig {
/// Address of the tree API used by this EN in case it does not have a
/// local tree component running and in this case needs to send requests
/// to some external tree API.
pub tree_api_remote_url: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Deserialize)]
pub struct TreeComponentConfig {
pub api_port: Option<u16>,
}

/// External Node Config contains all the configuration required for the EN operation.
/// It is split into three parts: required, optional and remote for easier navigation.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub(crate) struct ExternalNodeConfig {
pub required: RequiredENConfig,
pub postgres: PostgresConfig,
pub optional: OptionalENConfig,
pub observability: ObservabilityENConfig,
pub remote: RemoteENConfig,
pub experimental: ExperimentalENConfig,
pub consensus: Option<ConsensusConfig>,
Expand All @@ -799,6 +825,7 @@ impl ExternalNodeConfig {
pub async fn new(
required: RequiredENConfig,
optional: OptionalENConfig,
observability: ObservabilityENConfig,
main_node_client: &BoxedL2Client,
) -> anyhow::Result<Self> {
let experimental = envy::prefixed("EN_EXPERIMENTAL_")
Expand All @@ -823,6 +850,7 @@ impl ExternalNodeConfig {
required,
optional,
experimental,
observability,
consensus: read_consensus_config().context("read_consensus_config()")?,
tree_component: tree_component_config,
api_component: api_component_config,
Expand All @@ -836,6 +864,7 @@ impl ExternalNodeConfig {
postgres: PostgresConfig::mock(test_pool),
optional: OptionalENConfig::mock(),
remote: RemoteENConfig::mock(),
observability: ObservabilityENConfig::default(),
experimental: ExperimentalENConfig::mock(),
consensus: None,
api_component: ApiComponentConfig {
Expand All @@ -846,8 +875,8 @@ impl ExternalNodeConfig {
}
}

impl From<ExternalNodeConfig> for InternalApiConfig {
fn from(config: ExternalNodeConfig) -> Self {
impl From<&ExternalNodeConfig> for InternalApiConfig {
fn from(config: &ExternalNodeConfig) -> Self {
Self {
l1_chain_id: config.required.l1_chain_id,
l2_chain_id: config.required.l2_chain_id,
Expand Down Expand Up @@ -879,8 +908,8 @@ impl From<ExternalNodeConfig> for InternalApiConfig {
}
}

impl From<ExternalNodeConfig> for TxSenderConfig {
fn from(config: ExternalNodeConfig) -> Self {
impl From<&ExternalNodeConfig> for TxSenderConfig {
fn from(config: &ExternalNodeConfig) -> Self {
Self {
// Fee account address does not matter for the EN operation, since
// actual fee distribution is handled my the main node.
Expand Down
134 changes: 96 additions & 38 deletions core/bin/external_node/src/config/observability.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,101 @@
use zksync_config::configs::ObservabilityConfig;

pub fn observability_config_from_env() -> anyhow::Result<ObservabilityConfig> {
// The logic in this method mimics the historical logic of loading observability options
// This is left intact, since some of the existing deployments may rely on the this behavior.
let sentry_url = if let Ok(sentry_url) = std::env::var("MISC_SENTRY_URL") {
if sentry_url == "unset" {
None
} else {
Some(sentry_url)
use std::{collections::HashMap, time::Duration};

use anyhow::Context as _;
use prometheus_exporter::PrometheusExporterConfig;
use serde::Deserialize;
use vlog::LogFormat;

use super::{ConfigurationSource, Environment};

/// Observability part of the node configuration.
#[derive(Debug, Default, Deserialize)]
pub(crate) struct ObservabilityENConfig {
/// Port to bind the Prometheus exporter server to. If not specified, the server will not be launched.
/// If the push gateway URL is specified, it will prevail.
pub prometheus_port: Option<u16>,
/// Prometheus push gateway to push metrics to. Overrides `prometheus_port`. A full URL must be specified
/// including `job_id` and other path segments; it will be used verbatim as the URL to push data to.
pub prometheus_pushgateway_url: Option<String>,
/// Interval between pushing metrics to the Prometheus push gateway.
#[serde(default = "ObservabilityENConfig::default_prometheus_push_interval_ms")]
pub prometheus_push_interval_ms: u64,
/// Sentry URL to send panics to.
pub sentry_url: Option<String>,
/// Environment to use when sending data to Sentry.
pub sentry_environment: Option<String>,
/// Log format to use: either `plain` (default) or `json`.
#[serde(default)]
pub log_format: LogFormat,
}

impl ObservabilityENConfig {
const fn default_prometheus_push_interval_ms() -> u64 {
10_000
}

pub fn from_env() -> envy::Result<Self> {
Self::new(&Environment)
}

pub(super) fn new(source: &impl ConfigurationSource) -> envy::Result<Self> {
const OBSOLETE_VAR_NAMES: &[(&str, &str)] = &[
("MISC_SENTRY_URL", "EN_SENTRY_URL"),
("MISC_LOG_FORMAT", "EN_LOG_FORMAT"),
];

let en_vars = source.vars().filter_map(|(name, value)| {
let name = name.into_string().ok()?;
if !name.starts_with("EN_") {
return None;
}
Some((name, value.into_string().ok()?))
});
let mut vars: HashMap<_, _> = en_vars.collect();

for &(old_name, new_name) in OBSOLETE_VAR_NAMES {
if vars.contains_key(new_name) {
continue; // new name is set; it should prevail over the obsolete one.
}
if let Some(value) = source.var(old_name) {
vars.insert(new_name.to_owned(), value);
}
}
} else {
None
};
let sentry_environment = std::env::var("EN_SENTRY_ENVIRONMENT").ok().or_else(|| {
let l1_network = std::env::var("CHAIN_ETH_NETWORK").ok();
let l2_network = std::env::var("CHAIN_ETH_ZKSYNC_NETWORK").ok();
match (l1_network, l2_network) {
(Some(l1_network), Some(l2_network)) => {
Some(format!("{} - {}", l1_network, l2_network))

envy::prefixed("EN_").from_iter(vars)
}

pub fn prometheus(&self) -> Option<PrometheusExporterConfig> {
match (self.prometheus_port, &self.prometheus_pushgateway_url) {
(_, Some(url)) => {
if self.prometheus_port.is_some() {
tracing::info!("Both Prometheus port and push gateway URLs are specified; the push gateway URL will be used");
}
let push_interval = Duration::from_millis(self.prometheus_push_interval_ms);
Some(PrometheusExporterConfig::push(url.clone(), push_interval))
}
_ => None,
(Some(port), None) => Some(PrometheusExporterConfig::pull(port)),
(None, None) => None,
}
});
let log_format = if let Ok(log_format) = std::env::var("MISC_LOG_FORMAT") {
if log_format != "plain" && log_format != "json" {
anyhow::bail!("MISC_LOG_FORMAT has an unexpected value {}", log_format);
}

pub fn build_observability(&self) -> anyhow::Result<vlog::ObservabilityGuard> {
let mut builder = vlog::ObservabilityBuilder::new().with_log_format(self.log_format);
// Some legacy deployments use `unset` as an equivalent of `None`.
let sentry_url = self.sentry_url.as_deref().filter(|&url| url != "unset");
if let Some(sentry_url) = sentry_url {
builder = builder
.with_sentry_url(sentry_url)
.context("Invalid Sentry URL")?
.with_sentry_environment(self.sentry_environment.clone());
}
let guard = builder.build();

// Report whether sentry is running after the logging subsystem was initialized.
if let Some(sentry_url) = sentry_url {
tracing::info!("Sentry configured with URL: {sentry_url}");
} else {
tracing::info!("No sentry URL was provided");
}
log_format
} else {
"plain".to_string()
};
let log_directives = std::env::var("RUST_LOG").ok();

Ok(ObservabilityConfig {
sentry_url,
sentry_environment,
log_format,
opentelemetry: None,
sporadic_crypto_errors_substrs: vec![],
log_directives,
})
Ok(guard)
}
}
Loading

0 comments on commit 63f1b29

Please sign in to comment.