Skip to content

Commit

Permalink
feat: add revert tests to zk_toolbox (#2317)
Browse files Browse the repository at this point in the history
## What ❔

- Adds revert tests to zk_toolbox
<!-- What are the changes this PR brings about? -->
<!-- Example: This PR adds a PR template to the repo. -->
<!-- (For bigger PRs adding more context is appreciated) -->

## Why ❔

<!-- Why are these changes done? What goal do they contribute to? What
are the principles behind them? -->
<!-- Example: PR templates ensure PR reviewers, observers, and future
iterators are in context about the evolution of repos. -->

## Checklist

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

- [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 `zk fmt` and `zk lint`.
  • Loading branch information
aon authored Jun 27, 2024
1 parent f86eb13 commit c9ad002
Show file tree
Hide file tree
Showing 42 changed files with 756 additions and 336 deletions.
17 changes: 12 additions & 5 deletions .github/workflows/ci-zk-toolbox-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
path: zk_toolbox.tar
compression-level: 0

integration_test:
tests:
runs-on: [matterlabs-ci-runner]
needs: [build]

Expand Down Expand Up @@ -95,25 +95,32 @@ jobs:
- name: Run integration tests
run: |
ci_run zk_supervisor integration-tests --ignore-prerequisites --verbose
ci_run zk_supervisor test integration --ignore-prerequisites --verbose
- name: Run external node server
run: |
ci_run zk_inception external-node configs --db-url=postgres://postgres:notsecurepassword@postgres:5432 \
--db-name=zksync_en_localhost_era --l1-rpc-url=http://reth:8545
--db-name=zksync_en_localhost_era --l1-rpc-url=http://reth:8545
ci_run zk_inception external-node init --ignore-prerequisites
ci_run zk_inception external-node run --ignore-prerequisites &>external_node.log &
ci_run sleep 5
- name: Run integration tests en
run: |
ci_run zk_supervisor integration-tests --ignore-prerequisites --verbose --external-node
ci_run zk_supervisor test integration --ignore-prerequisites --verbose --external-node
- name: Run revert tests
run: |
ci_run zk_supervisor test revert --ignore-prerequisites --verbose
- name: Show server.log logs
if: always()
run: ci_run cat server.log || true

- name: Show external_node.log logs
if: always()
run: ci_run cat external_node.log || true

- name: Show revert.log logs
if: always()
run: ci_run cat ./core/tests/revert-test/revert.log || true
2 changes: 2 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions core/bin/block_reverter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ publish = false

[dependencies]
zksync_config.workspace = true
zksync_core_leftovers.workspace = true
zksync_env_config.workspace = true
zksync_dal.workspace = true
zksync_protobuf_config.workspace = true
zksync_object_store.workspace = true
zksync_types.workspace = true
zksync_block_reverter.workspace = true
Expand Down
158 changes: 131 additions & 27 deletions core/bin/block_reverter/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::env;
use std::path::PathBuf;

use anyhow::Context as _;
use clap::{Parser, Subcommand};
Expand All @@ -11,9 +11,13 @@ use zksync_block_reverter::{
BlockReverter, BlockReverterEthConfig, NodeRole,
};
use zksync_config::{
configs::{chain::NetworkConfig, DatabaseSecrets, L1Secrets, ObservabilityConfig},
ContractsConfig, DBConfig, EthConfig, PostgresConfig,
configs::{
chain::NetworkConfig, wallets::Wallets, DatabaseSecrets, GeneralConfig, L1Secrets,
ObservabilityConfig,
},
ContractsConfig, DBConfig, EthConfig, GenesisConfig, PostgresConfig,
};
use zksync_core_leftovers::temp_config_store::decode_yaml_repr;
use zksync_dal::{ConnectionPool, Core};
use zksync_env_config::{object_store::SnapshotsObjectStoreConfig, FromEnv};
use zksync_object_store::ObjectStoreFactory;
Expand All @@ -24,6 +28,21 @@ use zksync_types::{Address, L1BatchNumber};
struct Cli {
#[command(subcommand)]
command: Command,
/// Path to yaml config. If set, it will be used instead of env vars
#[arg(long, global = true)]
config_path: Option<PathBuf>,
/// Path to yaml contracts config. If set, it will be used instead of env vars
#[arg(long, global = true)]
contracts_config_path: Option<PathBuf>,
/// Path to yaml secrets config. If set, it will be used instead of env vars
#[arg(long, global = true)]
secrets_path: Option<PathBuf>,
/// Path to yaml wallets config. If set, it will be used instead of env vars
#[arg(long, global = true)]
wallets_path: Option<PathBuf>,
/// Path to yaml genesis config. If set, it will be used instead of env vars
#[arg(long, global = true)]
genesis_path: Option<PathBuf>,
}

#[derive(Debug, Subcommand)]
Expand Down Expand Up @@ -84,7 +103,7 @@ enum Command {

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let command = Cli::parse().command;
let opts = Cli::parse();
let observability_config =
ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?;
let log_format: zksync_vlog::LogFormat = observability_config
Expand All @@ -103,35 +122,111 @@ async fn main() -> anyhow::Result<()> {
}
let _guard = builder.build();

let eth_sender = EthConfig::from_env().context("EthConfig::from_env()")?;
let db_config = DBConfig::from_env().context("DBConfig::from_env()")?;
let general_config: Option<GeneralConfig> = if let Some(path) = opts.config_path {
let yaml = std::fs::read_to_string(&path).with_context(|| path.display().to_string())?;
let config =
decode_yaml_repr::<zksync_protobuf_config::proto::general::GeneralConfig>(&yaml)
.context("failed decoding general YAML config")?;
Some(config)
} else {
None
};
let wallets_config: Option<Wallets> = if let Some(path) = opts.wallets_path {
let yaml = std::fs::read_to_string(&path).with_context(|| path.display().to_string())?;
let config = decode_yaml_repr::<zksync_protobuf_config::proto::wallets::Wallets>(&yaml)
.context("failed decoding wallets YAML config")?;
Some(config)
} else {
None
};
let genesis_config: Option<GenesisConfig> = if let Some(path) = opts.genesis_path {
let yaml = std::fs::read_to_string(&path).with_context(|| path.display().to_string())?;
let config = decode_yaml_repr::<zksync_protobuf_config::proto::genesis::Genesis>(&yaml)
.context("failed decoding genesis YAML config")?;
Some(config)
} else {
None
};

let eth_sender = match &general_config {
Some(general_config) => general_config
.eth
.clone()
.context("Failed to find eth config")?,
None => EthConfig::from_env().context("EthConfig::from_env()")?,
};
let db_config = match &general_config {
Some(general_config) => general_config
.db_config
.clone()
.context("Failed to find eth config")?,
None => DBConfig::from_env().context("DBConfig::from_env()")?,
};
let contracts = match opts.contracts_config_path {
Some(path) => {
let yaml =
std::fs::read_to_string(&path).with_context(|| path.display().to_string())?;
decode_yaml_repr::<zksync_protobuf_config::proto::contracts::Contracts>(&yaml)
.context("failed decoding contracts YAML config")?
}
None => ContractsConfig::from_env().context("ContractsConfig::from_env()")?,
};
let secrets_config = if let Some(path) = opts.secrets_path {
let yaml = std::fs::read_to_string(&path).with_context(|| path.display().to_string())?;
let config = decode_yaml_repr::<zksync_protobuf_config::proto::secrets::Secrets>(&yaml)
.context("failed decoding secrets YAML config")?;
Some(config)
} else {
None
};

let default_priority_fee_per_gas = eth_sender
.gas_adjuster
.context("gas_adjuster")?
.default_priority_fee_per_gas;
let contracts = ContractsConfig::from_env().context("ContractsConfig::from_env()")?;
let network = NetworkConfig::from_env().context("NetworkConfig::from_env()")?;
let database_secrets = DatabaseSecrets::from_env().context("DatabaseSecrets::from_env()")?;
let l1_secrets = L1Secrets::from_env().context("L1Secrets::from_env()")?;
let postgress_config = PostgresConfig::from_env().context("PostgresConfig::from_env()")?;
let era_chain_id = env::var("CONTRACTS_ERA_CHAIN_ID")
.context("`CONTRACTS_ERA_CHAIN_ID` env variable is not set")?
.parse()
.map_err(|err| {
anyhow::anyhow!("failed parsing `CONTRACTS_ERA_CHAIN_ID` env variable: {err}")
})?;
let config = BlockReverterEthConfig::new(&eth_sender, &contracts, &network, era_chain_id)?;

let database_secrets = match &secrets_config {
Some(secrets_config) => secrets_config
.database
.clone()
.context("Failed to find database config")?,
None => DatabaseSecrets::from_env().context("DatabaseSecrets::from_env()")?,
};
let l1_secrets = match &secrets_config {
Some(secrets_config) => secrets_config
.l1
.clone()
.context("Failed to find l1 config")?,
None => L1Secrets::from_env().context("L1Secrets::from_env()")?,
};
let postgres_config = match &general_config {
Some(general_config) => general_config
.postgres_config
.clone()
.context("Failed to find postgres config")?,
None => PostgresConfig::from_env().context("PostgresConfig::from_env()")?,
};
let zksync_network_id = match &genesis_config {
Some(genesis_config) => genesis_config.l2_chain_id,
None => {
NetworkConfig::from_env()
.context("NetworkConfig::from_env()")?
.zksync_network_id
}
};

let config = BlockReverterEthConfig::new(&eth_sender, &contracts, zksync_network_id)?;

let connection_pool = ConnectionPool::<Core>::builder(
database_secrets.master_url()?,
postgress_config.max_connections()?,
postgres_config.max_connections()?,
)
.build()
.await
.context("failed to build a connection pool")?;
let mut block_reverter = BlockReverter::new(NodeRole::Main, connection_pool);

match command {
match opts.command {
Command::Display {
json,
operator_address,
Expand All @@ -157,13 +252,22 @@ async fn main() -> anyhow::Result<()> {
let eth_client = Client::http(l1_secrets.l1_rpc_url.clone())
.context("Ethereum client")?
.build();
#[allow(deprecated)]
let reverter_private_key = eth_sender
.sender
.context("eth_sender_config")?
.private_key()
.context("eth_sender_config.private_key")?
.context("eth_sender_config.private_key is not set")?;
let reverter_private_key = if let Some(wallets_config) = wallets_config {
wallets_config
.eth_sender
.unwrap()
.operator
.private_key()
.to_owned()
} else {
#[allow(deprecated)]
eth_sender
.sender
.context("eth_sender_config")?
.private_key()
.context("eth_sender_config.private_key")?
.context("eth_sender_config.private_key is not set")?
};

let priority_fee_per_gas = priority_fee_per_gas.unwrap_or(default_priority_fee_per_gas);
let l1_chain_id = eth_client
Expand Down
1 change: 0 additions & 1 deletion core/lib/protobuf_config/src/proto/config/chain.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ enum FeeModelVersion {
V2 = 1;
}


message StateKeeper {
optional uint64 transaction_slots = 1; // required
optional uint64 block_commit_deadline_ms = 2; // required; ms
Expand Down
39 changes: 12 additions & 27 deletions core/node/block_reverter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{path::Path, sync::Arc, time::Duration};
use anyhow::Context as _;
use serde::Serialize;
use tokio::{fs, sync::Semaphore};
use zksync_config::{configs::chain::NetworkConfig, ContractsConfig, EthConfig};
use zksync_config::{ContractsConfig, EthConfig};
use zksync_contracts::hyperchain_contract;
use zksync_dal::{ConnectionPool, Core, CoreDal};
// Public re-export to simplify the API use.
Expand Down Expand Up @@ -36,15 +36,13 @@ pub struct BlockReverterEthConfig {
validator_timelock_addr: H160,
default_priority_fee_per_gas: u64,
hyperchain_id: L2ChainId,
era_chain_id: L2ChainId,
}

impl BlockReverterEthConfig {
pub fn new(
eth_config: &EthConfig,
contract: &ContractsConfig,
network_config: &NetworkConfig,
era_chain_id: L2ChainId,
hyperchain_id: L2ChainId,
) -> anyhow::Result<Self> {
Ok(Self {
diamond_proxy_addr: contract.diamond_proxy_addr,
Expand All @@ -54,8 +52,7 @@ impl BlockReverterEthConfig {
.as_ref()
.context("gas adjuster")?
.default_priority_fee_per_gas,
hyperchain_id: network_config.zksync_network_id,
era_chain_id,
hyperchain_id,
})
}
}
Expand Down Expand Up @@ -484,27 +481,15 @@ impl BlockReverter {

let contract = hyperchain_contract();

// It is expected that for all new chains `revertBatchesSharedBridge` can be used.
// For Era, we are using `revertBatches` function for backwards compatibility in case the migration
// to the shared bridge is not yet complete.
let data = if eth_config.hyperchain_id == eth_config.era_chain_id {
let revert_function = contract
.function("revertBatches")
.context("`revertBatches` function must be present in contract")?;
revert_function
.encode_input(&[Token::Uint(last_l1_batch_to_keep.0.into())])
.context("failed encoding `revertBatches` input")?
} else {
let revert_function = contract
.function("revertBatchesSharedBridge")
.context("`revertBatchesSharedBridge` function must be present in contract")?;
revert_function
.encode_input(&[
Token::Uint(eth_config.hyperchain_id.as_u64().into()),
Token::Uint(last_l1_batch_to_keep.0.into()),
])
.context("failed encoding `revertBatchesSharedBridge` input")?
};
let revert_function = contract
.function("revertBatchesSharedBridge")
.context("`revertBatchesSharedBridge` function must be present in contract")?;
let data = revert_function
.encode_input(&[
Token::Uint(eth_config.hyperchain_id.as_u64().into()),
Token::Uint(last_l1_batch_to_keep.0.into()),
])
.context("failed encoding `revertBatchesSharedBridge` input")?;

let options = Options {
nonce: Some(nonce.into()),
Expand Down
12 changes: 10 additions & 2 deletions core/tests/revert-test/tests/revert-and-restart-en.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,11 @@ class MainNode {
}
});
// Wait until the main node starts responding.
let tester: Tester = await Tester.init(env.ETH_CLIENT_WEB3_URL, env.API_WEB3_JSON_RPC_HTTP_URL);
let tester: Tester = await Tester.init(
env.ETH_CLIENT_WEB3_URL,
env.API_WEB3_JSON_RPC_HTTP_URL,
env.CONTRACTS_BASE_TOKEN_ADDR
);
while (true) {
try {
await tester.syncWallet.provider.getBlockNumber();
Expand Down Expand Up @@ -197,7 +201,11 @@ class ExtNode {
}
});
// Wait until the node starts responding.
let tester: Tester = await Tester.init(env.EN_ETH_CLIENT_URL, `http://127.0.0.1:${env.EN_HTTP_PORT}`);
let tester: Tester = await Tester.init(
env.EN_ETH_CLIENT_URL,
`http://127.0.0.1:${env.EN_HTTP_PORT}`,
env.CONTRACTS_BASE_TOKEN_ADDR
);
while (true) {
try {
await tester.syncWallet.provider.getBlockNumber();
Expand Down
Loading

0 comments on commit c9ad002

Please sign in to comment.