diff --git a/.github/workflows/ci-core-lint-reusable.yml b/.github/workflows/ci-core-lint-reusable.yml index f9107c2133bd..527d9db4c09e 100644 --- a/.github/workflows/ci-core-lint-reusable.yml +++ b/.github/workflows/ci-core-lint-reusable.yml @@ -82,7 +82,6 @@ jobs: ci_run zkstack dev lint -t js --check ci_run zkstack dev lint -t ts --check ci_run zkstack dev lint -t rs --check - ci_run zkstack dev lint -t rust-toolchain ci_run zkstack dev lint -t autocompletion - name: Check Database diff --git a/contracts b/contracts index 82a893dd9917..96bbeedcf320 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 82a893dd991784ed314af1e3d6a7a295cd466169 +Subproject commit 96bbeedcf3208d776854ca59b3e02cf27a18eaf2 diff --git a/core/lib/types/src/api/mod.rs b/core/lib/types/src/api/mod.rs index dca6ce7eb0f0..a90246492936 100644 --- a/core/lib/types/src/api/mod.rs +++ b/core/lib/types/src/api/mod.rs @@ -1112,6 +1112,7 @@ pub struct GatewayMigrationStatus { pub latest_notification: Option, pub state: GatewayMigrationState, pub settlement_layer: Option, + pub wait_for_batches_to_be_committed: bool, } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] diff --git a/core/node/api_server/src/web3/namespaces/unstable/mod.rs b/core/node/api_server/src/web3/namespaces/unstable/mod.rs index 24435e647360..ccf4267e833b 100644 --- a/core/node/api_server/src/web3/namespaces/unstable/mod.rs +++ b/core/node/api_server/src/web3/namespaces/unstable/mod.rs @@ -8,11 +8,13 @@ use zksync_dal::{Connection, Core, CoreDal, DalError}; use zksync_mini_merkle_tree::MiniMerkleTree; use zksync_multivm::{interface::VmEvent, zk_evm_latest::ethereum_types::U64}; use zksync_types::{ + aggregated_operations::L1BatchAggregatedActionType, api, api::{ ChainAggProof, DataAvailabilityDetails, GatewayMigrationStatus, L1ToL2TxsStatus, TeeProof, TransactionDetailedResult, TransactionExecutionInfo, }, + eth_sender::EthTxFinalityStatus, server_notification::GatewayMigrationState, tee_types::TeeType, web3, @@ -248,6 +250,27 @@ impl UnstableNamespace { .await .map_err(DalError::generalize)?; + let all_batches_with_interop_roots_committed = match connection + .interop_root_dal() + .get_latest_processed_interop_root_l1_batch_number() + .await + .map_err(DalError::generalize)? + { + None => true, + Some(latest_processed_l1_batch_number) => { + match connection + .eth_sender_dal() + .get_last_sent_successfully_eth_tx_by_batch_and_op( + L1BatchNumber::from(latest_processed_l1_batch_number), + L1BatchAggregatedActionType::Commit, + ) + .await + { + Some(tx) => tx.eth_tx_finality_status == EthTxFinalityStatus::Finalized, + None => false, + } + } + }; let state = GatewayMigrationState::from_sl_and_notification( self.state .api_config @@ -264,6 +287,7 @@ impl UnstableNamespace { .api_config .settlement_layer .settlement_layer_for_sending_txs(), + wait_for_batches_to_be_committed: !all_batches_with_interop_roots_committed, }) } diff --git a/core/node/eth_sender/src/eth_tx_aggregator.rs b/core/node/eth_sender/src/eth_tx_aggregator.rs index cdec952ed005..906b081557ce 100644 --- a/core/node/eth_sender/src/eth_tx_aggregator.rs +++ b/core/node/eth_sender/src/eth_tx_aggregator.rs @@ -857,12 +857,13 @@ impl EthTxAggregator { op_restrictions.precommit_restriction = reason; // From V31 when migrating to or from gateway, we need to wait for all blocks to be executed, // so there is no restriction for prove and execute operations - if let Some(SettlementLayer::Gateway(_)) = self.settlement_layer { - // For the migration from gateway to L1, we need we need to ensure all batches containing interop roots get committed and executed. - if !self + if matches!(self.settlement_layer, Some(SettlementLayer::Gateway(_))) { + if self .is_waiting_for_batches_with_interop_roots_to_be_committed(storage) .await? { + // For the migration from gateway to L1, we need to ensure all batches containing interop roots + // get committed and executed. Once this happens, we can re-enable commit & precommit. op_restrictions.commit_restriction = None; op_restrictions.precommit_restriction = None; } diff --git a/core/tests/gateway-migration-test/tests/migration.test.ts b/core/tests/gateway-migration-test/tests/migration.test.ts index 72ae324772d0..dcb1c95b2d58 100644 --- a/core/tests/gateway-migration-test/tests/migration.test.ts +++ b/core/tests/gateway-migration-test/tests/migration.test.ts @@ -226,9 +226,23 @@ describe('Migration from gateway test', function () { } } } else { - await utils.spawn( - `zkstack chain gateway migrate-from-gateway --chain ${fileConfig.chain} --gateway-chain-name ${gatewayChain}` - ); + let migrationSucceeded = false; + for (let i = 0; i < 60; i++) { + try { + await utils.spawn( + `zkstack chain gateway migrate-from-gateway --chain ${fileConfig.chain} --gateway-chain-name ${gatewayChain}` + ); + migrationSucceeded = true; + break; + } catch (e) { + console.log(`Migration attempt ${i} failed with error: ${e}`); + await utils.sleep(2); + } + } + + if (!migrationSucceeded) { + throw new Error('Migration from gateway did not succeed after 60 attempts'); + } } await mainNodeSpawner.mainNode?.waitForShutdown(); // Node is already killed, so we simply start the new server diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/gateway/gateway_common.rs b/zkstack_cli/crates/zkstack/src/commands/chain/gateway/gateway_common.rs index 42cea5b99719..aade775836fb 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/gateway/gateway_common.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/gateway/gateway_common.rs @@ -52,6 +52,7 @@ impl MigrationDirection { #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum NotificationReceivedState { + NotAllBatchesCommitted, NotAllBatchesExecuted(U256, U256), UnconfirmedTxs(usize), } @@ -71,6 +72,9 @@ impl std::fmt::Display for NotificationReceivedState { "There are some unconfirmed transactions: {unconfirmed_txs}" ) } + NotificationReceivedState::NotAllBatchesCommitted => { + write!(f, "Not all batches have been committed yet") + } } } } @@ -309,6 +313,12 @@ pub(crate) async fn get_gateway_migration_state( ), )); } + + if gateway_migration_status.wait_for_batches_to_be_committed { + return Ok(GatewayMigrationProgressState::NotificationReceived( + NotificationReceivedState::NotAllBatchesCommitted, + )); + } } let unconfirmed_txs = zk_client.get_unconfirmed_txs_count().await?; diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/gateway/migrate_from_gateway.rs b/zkstack_cli/crates/zkstack/src/commands/chain/gateway/migrate_from_gateway.rs index 8ffaeeb41676..ecc7eb952936 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/gateway/migrate_from_gateway.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/gateway/migrate_from_gateway.rs @@ -39,7 +39,10 @@ use crate::{ admin_call_builder::AdminCallBuilder, gateway::{ constants::DEFAULT_MAX_L1_GAS_PRICE_FOR_PRIORITY_TXS, - gateway_common::extract_and_wait_for_priority_ops, + gateway_common::{ + extract_and_wait_for_priority_ops, get_gateway_migration_state, + GatewayMigrationProgressState, MigrationDirection, + }, }, init::get_l1_da_validator, utils::send_tx, @@ -85,6 +88,32 @@ pub async fn run(args: MigrateFromGatewayArgs, shell: &Shell) -> anyhow::Result< .ctm .diamond_cut_data; + let gateway_general_config = gateway_chain_config.get_general_config().await?; + let gw_rpc_url = gateway_general_config.l2_http_url()?; + + let state = get_gateway_migration_state( + l1_url.clone(), + chain_contracts_config + .ecosystem_contracts + .bridgehub_proxy_addr, + chain_config.chain_id.as_u64(), + chain_config + .get_general_config() + .await? + .l2_http_url() + .context("L2 RPC URL must be provided for cross checking")?, + gw_rpc_url.clone(), + MigrationDirection::FromGateway, + ) + .await?; + + if state != GatewayMigrationProgressState::ServerReady { + anyhow::bail!( + "Chain is not ready for starting the migration from Gateway. Current state: {:?}", + state + ); + } + let start_migrate_from_gateway_call = start_migrate_chain_from_gateway( shell, &args.forge_args, @@ -108,8 +137,6 @@ pub async fn run(args: MigrateFromGatewayArgs, shell: &Shell) -> anyhow::Result< let (calldata, value) = AdminCallBuilder::new(start_migrate_from_gateway_call.calls).compile_full_calldata(); - let general_config = gateway_chain_config.get_general_config().await?; - let gw_rpc_url = general_config.l2_http_url()?; let gateway_provider = get_ethers_provider(&gw_rpc_url)?; let gateway_zk_client = get_zk_client(&gw_rpc_url, chain_config.chain_id.as_u64())?; diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/commands/lint.rs b/zkstack_cli/crates/zkstack/src/commands/dev/commands/lint.rs index c3f195e18362..316b25181e75 100644 --- a/zkstack_cli/crates/zkstack/src/commands/dev/commands/lint.rs +++ b/zkstack_cli/crates/zkstack/src/commands/dev/commands/lint.rs @@ -41,8 +41,8 @@ pub fn run(shell: &Shell, args: LintArgs) -> anyhow::Result<()> { Target::Js, Target::Ts, Target::Contracts, - Target::RustToolchain, Target::Autocompletion, + Target::RustToolchain, ] } else { args.targets.clone() diff --git a/zkstack_cli/rust-toolchain b/zkstack_cli/rust-toolchain index b67e7d5348c2..9e75344344a7 100644 --- a/zkstack_cli/rust-toolchain +++ b/zkstack_cli/rust-toolchain @@ -1,2 +1,2 @@ [toolchain] -channel = "1.89.0" +channel = "nightly-2025-09-19"