use std::num::NonZeroUsize;
use anyhow::Context as _;
use zksync_config::configs::{api, ApiConfig};
use zksync_protobuf::{
repr::{read_required_repr, ProtoRepr},
required,
};
use crate::{parse_h160, parse_h256, proto::api as proto};
impl ProtoRepr for proto::Api {
type Type = ApiConfig;
fn read(&self) -> anyhow::Result<Self::Type> {
Ok(Self::Type {
web3_json_rpc: read_required_repr(&self.web3_json_rpc).context("web3_json_rpc")?,
prometheus: read_required_repr(&self.prometheus).context("prometheus")?,
healthcheck: read_required_repr(&self.healthcheck).context("healthcheck")?,
merkle_tree: read_required_repr(&self.merkle_tree).context("merkle_tree")?,
})
}
fn build(this: &Self::Type) -> Self {
Self {
web3_json_rpc: Some(ProtoRepr::build(&this.web3_json_rpc)),
prometheus: Some(ProtoRepr::build(&this.prometheus)),
healthcheck: Some(ProtoRepr::build(&this.healthcheck)),
merkle_tree: Some(ProtoRepr::build(&this.merkle_tree)),
}
}
}
impl ProtoRepr for proto::Web3JsonRpc {
type Type = api::Web3JsonRpcConfig;
fn read(&self) -> anyhow::Result<Self::Type> {
let account_pks = self
.account_pks
.iter()
.enumerate()
.map(|(i, k)| parse_h256(k).context(i))
.collect::<Result<Vec<_>, _>>()
.context("account_pks")?;
let account_pks = if account_pks.is_empty() {
None
} else {
Some(account_pks)
};
let max_response_body_size_overrides_mb = self
.max_response_body_size_overrides
.iter()
.enumerate()
.map(|(i, entry)| {
let size_mb = if let Some(size_mb) = entry.size_mb {
let size_mb =
usize::try_from(size_mb).with_context(|| format!("[{i}].size_mb"))?;
NonZeroUsize::new(size_mb).with_context(|| format!("[{i}].size_mb is zero"))?
} else {
NonZeroUsize::MAX
};
Ok((
entry
.method
.clone()
.with_context(|| format!("[{i}].method"))?,
size_mb,
))
})
.collect::<anyhow::Result<_>>()
.context("max_response_body_size_overrides")?;
let api_namespaces = if self.api_namespaces.is_empty() {
None
} else {
Some(self.api_namespaces.clone())
};
Ok(Self::Type {
http_port: required(&self.http_port)
.and_then(|p| Ok((*p).try_into()?))
.context("http_port")?,
http_url: required(&self.http_url).context("http_url")?.clone(),
ws_port: required(&self.ws_port)
.and_then(|p| Ok((*p).try_into()?))
.context("ws_port")?,
ws_url: required(&self.ws_url).context("ws_url")?.clone(),
req_entities_limit: self.req_entities_limit,
filters_disabled: self.filters_disabled.unwrap_or(false),
filters_limit: self.filters_limit,
subscriptions_limit: self.subscriptions_limit,
pubsub_polling_interval: self.pubsub_polling_interval,
max_nonce_ahead: *required(&self.max_nonce_ahead).context("max_nonce_ahead")?,
gas_price_scale_factor: *required(&self.gas_price_scale_factor)
.context("gas_price_scale_factor")?,
request_timeout: self.request_timeout,
account_pks,
estimate_gas_scale_factor: *required(&self.estimate_gas_scale_factor)
.context("estimate_gas_scale_factor")?,
estimate_gas_acceptable_overestimation: *required(
&self.estimate_gas_acceptable_overestimation,
)
.context("acceptable_overestimation")?,
max_tx_size: required(&self.max_tx_size)
.and_then(|x| Ok((*x).try_into()?))
.context("max_tx_size")?,
vm_execution_cache_misses_limit: self
.vm_execution_cache_misses_limit
.map(|x| x.try_into())
.transpose()
.context("vm_execution_cache_misses_limit")?,
vm_concurrency_limit: self
.vm_concurrency_limit
.map(|x| x.try_into())
.transpose()
.context("vm_concurrency_limit")?,
factory_deps_cache_size_mb: self
.factory_deps_cache_size_mb
.map(|x| x.try_into())
.transpose()
.context("factory_deps_cache_size_mb")?,
initial_writes_cache_size_mb: self
.initial_writes_cache_size_mb
.map(|x| x.try_into())
.transpose()
.context("initial_writes_cache_size_mb")?,
latest_values_cache_size_mb: self
.latest_values_cache_size_mb
.map(|x| x.try_into())
.transpose()
.context("latest_values_cache_size_mb")?,
fee_history_limit: self.fee_history_limit,
max_batch_request_size: self
.max_batch_request_size
.map(|x| x.try_into())
.transpose()
.context("max_batch_request_size")?,
max_response_body_size_mb: self
.max_response_body_size_mb
.map(|x| x.try_into())
.transpose()
.context("max_response_body_size_mb")?,
max_response_body_size_overrides_mb,
websocket_requests_per_minute_limit: self
.websocket_requests_per_minute_limit
.map(|x| x.try_into())
.transpose()
.context("websocket_requests_per_minute_limit")?,
tree_api_url: self.tree_api_url.clone(),
mempool_cache_update_interval: self.mempool_cache_update_interval,
mempool_cache_size: self
.mempool_cache_size
.map(|x| x.try_into())
.transpose()
.context("mempool_cache_size")?,
whitelisted_tokens_for_aa: self
.whitelisted_tokens_for_aa
.iter()
.enumerate()
.map(|(i, k)| parse_h160(k).context(i))
.collect::<Result<Vec<_>, _>>()
.context("account_pks")?,
extended_api_tracing: self.extended_api_tracing.unwrap_or_default(),
api_namespaces,
})
}
fn build(this: &Self::Type) -> Self {
Self {
http_port: Some(this.http_port.into()),
http_url: Some(this.http_url.clone()),
ws_port: Some(this.ws_port.into()),
ws_url: Some(this.ws_url.clone()),
req_entities_limit: this.req_entities_limit,
filters_disabled: Some(this.filters_disabled),
mempool_cache_update_interval: this.mempool_cache_update_interval,
mempool_cache_size: this.mempool_cache_size.map(|x| x.try_into().unwrap()),
filters_limit: this.filters_limit,
subscriptions_limit: this.subscriptions_limit,
pubsub_polling_interval: this.pubsub_polling_interval,
max_nonce_ahead: Some(this.max_nonce_ahead),
gas_price_scale_factor: Some(this.gas_price_scale_factor),
request_timeout: this.request_timeout,
account_pks: this
.account_pks
.as_ref()
.map(|keys| keys.iter().map(|k| format!("{:?}", k)).collect())
.unwrap_or_default(),
estimate_gas_scale_factor: Some(this.estimate_gas_scale_factor),
estimate_gas_acceptable_overestimation: Some(
this.estimate_gas_acceptable_overestimation,
),
max_tx_size: Some(this.max_tx_size.try_into().unwrap()),
vm_execution_cache_misses_limit: this
.vm_execution_cache_misses_limit
.map(|x| x.try_into().unwrap()),
vm_concurrency_limit: this.vm_concurrency_limit.map(|x| x.try_into().unwrap()),
factory_deps_cache_size_mb: this
.factory_deps_cache_size_mb
.map(|x| x.try_into().unwrap()),
initial_writes_cache_size_mb: this
.initial_writes_cache_size_mb
.map(|x| x.try_into().unwrap()),
latest_values_cache_size_mb: this
.latest_values_cache_size_mb
.map(|x| x.try_into().unwrap()),
fee_history_limit: this.fee_history_limit,
max_batch_request_size: this.max_batch_request_size.map(|x| x.try_into().unwrap()),
max_response_body_size_mb: this
.max_response_body_size_mb
.map(|x| x.try_into().unwrap()),
max_response_body_size_overrides: this
.max_response_body_size_overrides_mb
.iter()
.map(|(method, size_mb)| proto::MaxResponseSizeOverride {
method: Some(method.to_owned()),
size_mb: if size_mb == usize::MAX {
None
} else {
Some(size_mb.try_into().expect("failed converting usize to u64"))
},
})
.collect(),
websocket_requests_per_minute_limit: this
.websocket_requests_per_minute_limit
.map(|x| x.into()),
tree_api_url: this.tree_api_url.clone(),
whitelisted_tokens_for_aa: this
.whitelisted_tokens_for_aa
.iter()
.map(|k| format!("{:?}", k))
.collect(),
extended_api_tracing: Some(this.extended_api_tracing),
api_namespaces: this.api_namespaces.clone().unwrap_or_default(),
}
}
}
impl ProtoRepr for proto::HealthCheck {
type Type = api::HealthCheckConfig;
fn read(&self) -> anyhow::Result<Self::Type> {
Ok(Self::Type {
port: required(&self.port)
.and_then(|&port| Ok(port.try_into()?))
.context("port")?,
slow_time_limit_ms: self.slow_time_limit_ms,
hard_time_limit_ms: self.hard_time_limit_ms,
})
}
fn build(this: &Self::Type) -> Self {
Self {
port: Some(this.port.into()),
slow_time_limit_ms: this.slow_time_limit_ms,
hard_time_limit_ms: this.hard_time_limit_ms,
}
}
}
impl ProtoRepr for proto::MerkleTreeApi {
type Type = api::MerkleTreeApiConfig;
fn read(&self) -> anyhow::Result<Self::Type> {
Ok(Self::Type {
port: required(&self.port)
.and_then(|p| Ok((*p).try_into()?))
.context("port")?,
})
}
fn build(this: &Self::Type) -> Self {
Self {
port: Some(this.port.into()),
}
}
}