Skip to content

Commit

Permalink
feat: integrate gateway changes for some components (#3274)
Browse files Browse the repository at this point in the history
## What ❔

Generally moves some code from gateway integration branch into main.
High-level list of changes:
- `eth_watch`: refactors watcher's client so it can use L2-specific
features if gateway is queried. New event processor is added for chains
that settle on gateway, it calculates part of merkle proof for L2->L1
logs.
- `api`: new method is added to `unstable` namespace that is utilized by
the new event processor. This method encapsulates a few storage reads +
builds merkle tree. This is a temporary measure and method will likely
be removed (that's why it's in unstable namespace) pretty soon after a
contract getter that does exactly the same is merged into contracts,
replacing unstable_getChainLogProof invocation with a simple `eth_call`
- `consistency_checker`, `tree_data_fetcher`: adds support for reading
batch commitment from either L1 or GW depending on what the SL is for a
batch.
- adds support for new format of commitBatches, proveBatches,
executeBatches data encoding
- bug fixes: `L2_NATIVE_TOKEN_VAULT_ADDRESS` was used instead of
`L2_ASSET_ROUTER_ADDRESS` in
`core/bin/external_node/src/node_builder.rs`, mixed up if/else branches
in `core/node/commitment_generator/src/lib.rs`
- some clean up, renaming, refactoring: `resolve_l1_batch_to_l2_block` +
`get_block_details` are replaced with just `get_batch_details` in
`batch_status_updater`, some code for old protocol versions (pre-boojum
or pre-shared-bridge) removed, `l1_` prefix is added to some addresses
to avoid confusion


## Why ❔

Finalize and merge some gateway features

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [ ] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.
- [ ] Code has been formatted via `zkstack dev fmt` and `zkstack dev
lint`.
  • Loading branch information
perekopskiy authored Nov 27, 2024
1 parent 40f8123 commit cbc91e3
Show file tree
Hide file tree
Showing 108 changed files with 4,908 additions and 1,594 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

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

66 changes: 40 additions & 26 deletions core/bin/external_node/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,15 @@ impl ConfigurationSource for Environment {
/// This part of the external node config is fetched directly from the main node.
#[derive(Debug, Deserialize)]
pub(crate) struct RemoteENConfig {
pub bridgehub_proxy_addr: Option<Address>,
pub state_transition_proxy_addr: Option<Address>,
pub transparent_proxy_admin_addr: Option<Address>,
/// Should not be accessed directly. Use [`ExternalNodeConfig::diamond_proxy_address`] instead.
diamond_proxy_addr: Address,
#[serde(alias = "bridgehub_proxy_addr")]
pub l1_bridgehub_proxy_addr: Option<Address>,
#[serde(alias = "state_transition_proxy_addr")]
pub l1_state_transition_proxy_addr: Option<Address>,
#[serde(alias = "transparent_proxy_admin_addr")]
pub l1_transparent_proxy_admin_addr: Option<Address>,
/// Should not be accessed directly. Use [`ExternalNodeConfig::l1_diamond_proxy_address`] instead.
#[serde(alias = "diamond_proxy_addr")]
l1_diamond_proxy_addr: Address,
// While on L1 shared bridge and legacy bridge are different contracts with different addresses,
// the `l2_erc20_bridge_addr` and `l2_shared_bridge_addr` are basically the same contract, but with
// a different name, with names adapted only for consistency.
Expand Down Expand Up @@ -144,7 +148,7 @@ impl RemoteENConfig {
.rpc_context("ecosystem_contracts")
.await
.ok();
let diamond_proxy_addr = client
let l1_diamond_proxy_addr = client
.get_main_contract()
.rpc_context("get_main_contract")
.await?;
Expand Down Expand Up @@ -180,14 +184,14 @@ impl RemoteENConfig {
}

Ok(Self {
bridgehub_proxy_addr: ecosystem_contracts.as_ref().map(|a| a.bridgehub_proxy_addr),
state_transition_proxy_addr: ecosystem_contracts
l1_bridgehub_proxy_addr: ecosystem_contracts.as_ref().map(|a| a.bridgehub_proxy_addr),
l1_state_transition_proxy_addr: ecosystem_contracts
.as_ref()
.map(|a| a.state_transition_proxy_addr),
transparent_proxy_admin_addr: ecosystem_contracts
l1_transparent_proxy_admin_addr: ecosystem_contracts
.as_ref()
.map(|a| a.transparent_proxy_admin_addr),
diamond_proxy_addr,
l1_diamond_proxy_addr,
l2_testnet_paymaster_addr,
l1_erc20_bridge_proxy_addr: bridges.l1_erc20_default_bridge,
l2_erc20_bridge_addr: l2_erc20_default_bridge,
Expand All @@ -212,10 +216,10 @@ impl RemoteENConfig {
#[cfg(test)]
fn mock() -> Self {
Self {
bridgehub_proxy_addr: None,
state_transition_proxy_addr: None,
transparent_proxy_admin_addr: None,
diamond_proxy_addr: Address::repeat_byte(1),
l1_bridgehub_proxy_addr: None,
l1_state_transition_proxy_addr: None,
l1_transparent_proxy_admin_addr: None,
l1_diamond_proxy_addr: Address::repeat_byte(1),
l1_erc20_bridge_proxy_addr: Some(Address::repeat_byte(2)),
l2_erc20_bridge_addr: Some(Address::repeat_byte(3)),
l2_weth_bridge_addr: None,
Expand Down Expand Up @@ -479,7 +483,6 @@ pub(crate) struct OptionalENConfig {
#[serde(default = "OptionalENConfig::default_pruning_data_retention_sec")]
pruning_data_retention_sec: u64,
/// Gateway RPC URL, needed for operating during migration.
#[allow(dead_code)]
pub gateway_url: Option<SensitiveUrl>,
/// Interval for bridge addresses refreshing in seconds.
bridge_addresses_refresh_interval_sec: Option<NonZeroU64>,
Expand All @@ -489,7 +492,11 @@ pub(crate) struct OptionalENConfig {
}

impl OptionalENConfig {
fn from_configs(general_config: &GeneralConfig, enconfig: &ENConfig) -> anyhow::Result<Self> {
fn from_configs(
general_config: &GeneralConfig,
enconfig: &ENConfig,
secrets: &Secrets,
) -> anyhow::Result<Self> {
let api_namespaces = load_config!(general_config.api_config, web3_json_rpc.api_namespaces)
.map(|a: Vec<String>| a.iter().map(|a| a.parse()).collect::<Result<_, _>>())
.transpose()?;
Expand Down Expand Up @@ -721,7 +728,10 @@ impl OptionalENConfig {
.unwrap_or_else(Self::default_main_node_rate_limit_rps),
api_namespaces,
contracts_diamond_proxy_addr: None,
gateway_url: enconfig.gateway_url.clone(),
gateway_url: secrets
.l1
.as_ref()
.and_then(|l1| l1.gateway_rpc_url.clone()),
bridge_addresses_refresh_interval_sec: enconfig.bridge_addresses_refresh_interval_sec,
timestamp_asserter_min_time_till_end_sec: general_config
.timestamp_asserter_config
Expand Down Expand Up @@ -1340,7 +1350,11 @@ impl ExternalNodeConfig<()> {
&external_node_config,
&secrets_config,
)?;
let optional = OptionalENConfig::from_configs(&general_config, &external_node_config)?;
let optional = OptionalENConfig::from_configs(
&general_config,
&external_node_config,
&secrets_config,
)?;
let postgres = PostgresConfig {
database_url: secrets_config
.database
Expand Down Expand Up @@ -1383,7 +1397,7 @@ impl ExternalNodeConfig<()> {
let remote = RemoteENConfig::fetch(main_node_client)
.await
.context("Unable to fetch required config values from the main node")?;
let remote_diamond_proxy_addr = remote.diamond_proxy_addr;
let remote_diamond_proxy_addr = remote.l1_diamond_proxy_addr;
if let Some(local_diamond_proxy_addr) = self.optional.contracts_diamond_proxy_addr {
anyhow::ensure!(
local_diamond_proxy_addr == remote_diamond_proxy_addr,
Expand Down Expand Up @@ -1430,14 +1444,14 @@ impl ExternalNodeConfig {
}
}

/// Returns a verified diamond proxy address.
/// Returns verified L1 diamond proxy address.
/// If local configuration contains the address, it will be checked against the one returned by the main node.
/// Otherwise, the remote value will be used. However, using remote value has trust implications for the main
/// node so relying on it solely is not recommended.
pub fn diamond_proxy_address(&self) -> Address {
pub fn l1_diamond_proxy_address(&self) -> Address {
self.optional
.contracts_diamond_proxy_addr
.unwrap_or(self.remote.diamond_proxy_addr)
.unwrap_or(self.remote.l1_diamond_proxy_addr)
}
}

Expand All @@ -1461,10 +1475,10 @@ impl From<&ExternalNodeConfig> for InternalApiConfig {
l1_weth_bridge: config.remote.l1_weth_bridge_addr,
l2_weth_bridge: config.remote.l2_weth_bridge_addr,
},
bridgehub_proxy_addr: config.remote.bridgehub_proxy_addr,
state_transition_proxy_addr: config.remote.state_transition_proxy_addr,
transparent_proxy_admin_addr: config.remote.transparent_proxy_admin_addr,
diamond_proxy_addr: config.remote.diamond_proxy_addr,
l1_bridgehub_proxy_addr: config.remote.l1_bridgehub_proxy_addr,
l1_state_transition_proxy_addr: config.remote.l1_state_transition_proxy_addr,
l1_transparent_proxy_admin_addr: config.remote.l1_transparent_proxy_admin_addr,
l1_diamond_proxy_addr: config.remote.l1_diamond_proxy_addr,
l2_testnet_paymaster_addr: config.remote.l2_testnet_paymaster_addr,
req_entities_limit: config.optional.req_entities_limit,
fee_history_limit: config.optional.fee_history_limit,
Expand Down
22 changes: 12 additions & 10 deletions core/bin/external_node/src/node_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use zksync_node_framework::{
service::{ZkStackService, ZkStackServiceBuilder},
};
use zksync_state::RocksdbStorageOptions;
use zksync_types::L2_NATIVE_TOKEN_VAULT_ADDRESS;
use zksync_types::L2_ASSET_ROUTER_ADDRESS;

use crate::{config::ExternalNodeConfig, metrics::framework::ExternalNodeMetricsLayer, Component};

Expand Down Expand Up @@ -181,8 +181,7 @@ impl ExternalNodeBuilder {
let query_eth_client_layer = QueryEthClientLayer::new(
self.config.required.settlement_layer_id(),
self.config.required.eth_client_url.clone(),
// TODO(EVM-676): add this config for external node
Default::default(),
self.config.optional.gateway_url.clone(),
);
self.node.add_layer(query_eth_client_layer);
Ok(self)
Expand All @@ -200,12 +199,11 @@ impl ExternalNodeBuilder {
.remote
.l2_shared_bridge_addr
.context("Missing `l2_shared_bridge_addr`")?;
let l2_legacy_shared_bridge_addr = if l2_shared_bridge_addr == L2_NATIVE_TOKEN_VAULT_ADDRESS
{
// System has migrated to `L2_NATIVE_TOKEN_VAULT_ADDRESS`, use legacy shared bridge address from main node.
let l2_legacy_shared_bridge_addr = if l2_shared_bridge_addr == L2_ASSET_ROUTER_ADDRESS {
// System has migrated to `L2_ASSET_ROUTER_ADDRESS`, use legacy shared bridge address from main node.
self.config.remote.l2_legacy_shared_bridge_addr
} else {
// System hasn't migrated on `L2_NATIVE_TOKEN_VAULT_ADDRESS`, we can safely use `l2_shared_bridge_addr`.
// System hasn't migrated on `L2_ASSET_ROUTER_ADDRESS`, we can safely use `l2_shared_bridge_addr`.
Some(l2_shared_bridge_addr)
};

Expand Down Expand Up @@ -278,7 +276,7 @@ impl ExternalNodeBuilder {

fn add_l1_batch_commitment_mode_validation_layer(mut self) -> anyhow::Result<Self> {
let layer = L1BatchCommitmentModeValidationLayer::new(
self.config.diamond_proxy_address(),
self.config.l1_diamond_proxy_address(),
self.config.optional.l1_batch_commit_data_generator_mode,
);
self.node.add_layer(layer);
Expand All @@ -297,9 +295,10 @@ impl ExternalNodeBuilder {
fn add_consistency_checker_layer(mut self) -> anyhow::Result<Self> {
let max_batches_to_recheck = 10; // TODO (BFT-97): Make it a part of a proper EN config
let layer = ConsistencyCheckerLayer::new(
self.config.diamond_proxy_address(),
self.config.l1_diamond_proxy_address(),
max_batches_to_recheck,
self.config.optional.l1_batch_commit_data_generator_mode,
self.config.required.l2_chain_id,
);
self.node.add_layer(layer);
Ok(self)
Expand All @@ -324,7 +323,10 @@ impl ExternalNodeBuilder {
}

fn add_tree_data_fetcher_layer(mut self) -> anyhow::Result<Self> {
let layer = TreeDataFetcherLayer::new(self.config.diamond_proxy_address());
let layer = TreeDataFetcherLayer::new(
self.config.l1_diamond_proxy_address(),
self.config.required.l2_chain_id,
);
self.node.add_layer(layer);
Ok(self)
}
Expand Down
6 changes: 3 additions & 3 deletions core/bin/external_node/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async fn external_node_basics(components_str: &'static str) {
}

let l2_client = utils::mock_l2_client(&env);
let eth_client = utils::mock_eth_client(env.config.diamond_proxy_address());
let eth_client = utils::mock_eth_client(env.config.l1_diamond_proxy_address());

let node_handle = tokio::task::spawn_blocking(move || {
std::thread::spawn(move || {
Expand Down Expand Up @@ -104,7 +104,7 @@ async fn node_reacts_to_stop_signal_during_initial_reorg_detection() {
let (env, env_handles) = utils::TestEnvironment::with_genesis_block("core").await;

let l2_client = utils::mock_l2_client_hanging();
let eth_client = utils::mock_eth_client(env.config.diamond_proxy_address());
let eth_client = utils::mock_eth_client(env.config.l1_diamond_proxy_address());

let mut node_handle = tokio::task::spawn_blocking(move || {
std::thread::spawn(move || {
Expand Down Expand Up @@ -140,7 +140,7 @@ async fn running_tree_without_core_is_not_allowed() {
let (env, _env_handles) = utils::TestEnvironment::with_genesis_block("tree").await;

let l2_client = utils::mock_l2_client(&env);
let eth_client = utils::mock_eth_client(env.config.diamond_proxy_address());
let eth_client = utils::mock_eth_client(env.config.l1_diamond_proxy_address());

let node_handle = tokio::task::spawn_blocking(move || {
std::thread::spawn(move || {
Expand Down
3 changes: 3 additions & 0 deletions core/bin/external_node/src/tests/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ pub(super) fn block_details_base(hash: H256) -> api::BlockDetailsBase {
status: api::BlockStatus::Sealed,
commit_tx_hash: None,
committed_at: None,
commit_chain_id: None,
prove_tx_hash: None,
proven_at: None,
prove_chain_id: None,
execute_tx_hash: None,
executed_at: None,
execute_chain_id: None,
l1_gas_price: 0,
l2_fair_gas_price: 0,
fair_pubdata_price: None,
Expand Down
7 changes: 2 additions & 5 deletions core/bin/zksync_server/src/node_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,7 @@ impl MainNodeBuilder {
let query_eth_client_layer = QueryEthClientLayer::new(
genesis.settlement_layer_id(),
eth_config.l1_rpc_url,
self.configs
.eth
.as_ref()
.and_then(|x| Some(x.gas_adjuster?.settlement_mode))
.unwrap_or(SettlementMode::SettlesToL1),
eth_config.gateway_rpc_url,
);
self.node.add_layer(query_eth_client_layer);
Ok(self)
Expand Down Expand Up @@ -283,6 +279,7 @@ impl MainNodeBuilder {
self.node.add_layer(EthWatchLayer::new(
try_load_config!(eth_config.watcher),
self.contracts_config.clone(),
self.genesis_config.l2_chain_id,
));
Ok(self)
}
Expand Down
2 changes: 1 addition & 1 deletion core/lib/basic_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl<'de> Deserialize<'de> for L2ChainId {
}

impl L2ChainId {
fn new(number: u64) -> Result<Self, String> {
pub fn new(number: u64) -> Result<Self, String> {
if number > L2ChainId::max().0 {
return Err(format!(
"Cannot convert given value {} into L2ChainId. It's greater than MAX: {}",
Expand Down
8 changes: 7 additions & 1 deletion core/lib/basic_types/src/web3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,20 @@ pub struct Filter {
}

#[derive(Default, Debug, PartialEq, Clone)]
pub struct ValueOrArray<T>(Vec<T>);
pub struct ValueOrArray<T>(pub Vec<T>);

impl<T> ValueOrArray<T> {
pub fn flatten(self) -> Vec<T> {
self.0
}
}

impl<T> From<T> for ValueOrArray<T> {
fn from(value: T) -> Self {
Self(vec![value])
}
}

impl<T> Serialize for ValueOrArray<T>
where
T: Serialize,
Expand Down
1 change: 0 additions & 1 deletion core/lib/config/src/configs/en_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,5 @@ pub struct ENConfig {
pub main_node_url: SensitiveUrl,
pub main_node_rate_limit_rps: Option<NonZeroUsize>,

pub gateway_url: Option<SensitiveUrl>,
pub bridge_addresses_refresh_interval_sec: Option<NonZeroU64>,
}
1 change: 1 addition & 0 deletions core/lib/config/src/configs/secrets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct DatabaseSecrets {
#[derive(Debug, Clone, PartialEq)]
pub struct L1Secrets {
pub l1_rpc_url: SensitiveUrl,
pub gateway_rpc_url: Option<SensitiveUrl>,
}

#[derive(Debug, Clone, PartialEq)]
Expand Down
3 changes: 1 addition & 2 deletions core/lib/config/src/testonly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,7 @@ impl Distribution<configs::secrets::L1Secrets> for EncodeDist {
use configs::secrets::L1Secrets;
L1Secrets {
l1_rpc_url: format!("localhost:{}", rng.gen::<u16>()).parse().unwrap(),
gateway_rpc_url: Some(format!("localhost:{}", rng.gen::<u16>()).parse().unwrap()),
}
}
}
Expand Down Expand Up @@ -938,8 +939,6 @@ impl Distribution<configs::en_config::ENConfig> for EncodeDist {
_ => L1BatchCommitmentMode::Validium,
},
main_node_rate_limit_rps: self.sample_opt(|| rng.gen()),
gateway_url: self
.sample_opt(|| format!("localhost:{}", rng.gen::<u16>()).parse().unwrap()),
bridge_addresses_refresh_interval_sec: self.sample_opt(|| rng.gen()),
}
}
Expand Down
2 changes: 2 additions & 0 deletions core/lib/constants/src/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ pub const EVM_GAS_MANAGER_ADDRESS: Address = H160([
0x00, 0x00, 0x80, 0x13,
]);

/// Note, that the `Create2Factory` and higher are explicitly deployed on a non-system-contract address
/// as they don't require any kernel space features.
pub const CREATE2_FACTORY_ADDRESS: Address = H160([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00,
Expand Down
Loading

0 comments on commit cbc91e3

Please sign in to comment.