diff --git a/.github/workflows/ci-core-reusable.yml b/.github/workflows/ci-core-reusable.yml index c5440395c904..b88704733874 100644 --- a/.github/workflows/ci-core-reusable.yml +++ b/.github/workflows/ci-core-reusable.yml @@ -518,12 +518,15 @@ jobs: # # ci_run ./bin/run_on_all_chains.sh "zkstack dev test revert --no-deps --external-node --no-kill --ignore-prerequisites" ${{ env.CHAINS }} ${{ env.INTEGRATION_TESTS_LOGS_DIR }} # -# # Upgrade tests should run last, because as soon as they -# # finish the bootloader will be different -# # TODO make upgrade tests safe to run multiple times -# - name: Run upgrade test -# run: | -# ci_run zkstack dev test upgrade --no-deps --chain era + # Upgrade tests should run last, because as soon as they + # finish the bootloader will be different + # TODO make upgrade tests safe to run multiple times + - name: Run upgrade test + run: | + ci_run killall -INT zksync_server || true + ci_run zkstack server --ignore-prerequisites --chain gateway &> ${{ env.SERVER_LOGS_DIR }}/gateway.log & + ci_run sleep 5 + ci_run zkstack dev test upgrade --no-deps --chain era - name: Upload logs uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 diff --git a/contracts b/contracts index e6573f6e9e7d..e8648270f38f 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit e6573f6e9e7d52cda2f5c0aa3e772ad10413934d +Subproject commit e8648270f38f170af1dd4db3d0f089e49d74a1ad diff --git a/core/lib/config/src/configs/gateway.rs b/core/lib/config/src/configs/gateway.rs index cc0cdcc1d6a2..1fa23ef3ff07 100644 --- a/core/lib/config/src/configs/gateway.rs +++ b/core/lib/config/src/configs/gateway.rs @@ -28,6 +28,8 @@ pub struct GatewayChainConfig { pub validator_timelock_addr: Address, pub multicall3_addr: Address, pub diamond_proxy_addr: Address, + // FIXME: there is no "governnace" for a chain, only an admin, we + // need to figure out what we mean here pub chain_admin_addr: Option
, pub governance_addr: Address, pub settlement_layer: u64, @@ -37,19 +39,16 @@ impl GatewayChainConfig { pub fn from_gateway_and_chain_data( gateway_config: &GatewayConfig, diamond_proxy_addr: Address, - chain_admin_addr: Address, + l2_chain_admin_addr: Address, settlement_layer: u64, ) -> Self { - // FIXME: there is no "governnace" for a chain, only an admin, we - // need to figure out what we mean here - Self { state_transition_proxy_addr: gateway_config.state_transition_proxy_addr, validator_timelock_addr: gateway_config.validator_timelock_addr, multicall3_addr: gateway_config.multicall3_addr, diamond_proxy_addr, - chain_admin_addr: Some(chain_admin_addr), - governance_addr: chain_admin_addr, + chain_admin_addr: Some(l2_chain_admin_addr), + governance_addr: l2_chain_admin_addr, settlement_layer, } } diff --git a/core/node/consistency_checker/src/lib.rs b/core/node/consistency_checker/src/lib.rs index 368881f127b4..e3f57af4cd7d 100644 --- a/core/node/consistency_checker/src/lib.rs +++ b/core/node/consistency_checker/src/lib.rs @@ -14,12 +14,9 @@ use zksync_eth_client::{ }; use zksync_health_check::{Health, HealthStatus, HealthUpdater, ReactiveHealthCheck}; use zksync_l1_contract_interface::{ - i_executor::{ - commit::kzg::ZK_SYNC_BYTES_PER_BLOB, - structures::{ - CommitBatchInfo, StoredBatchInfo, PUBDATA_SOURCE_BLOBS, PUBDATA_SOURCE_CALLDATA, - PUBDATA_SOURCE_CUSTOM_PRE_GATEWAY, SUPPORTED_ENCODING_VERSION, - }, + i_executor::structures::{ + CommitBatchInfo, StoredBatchInfo, PUBDATA_SOURCE_BLOBS, PUBDATA_SOURCE_CALLDATA, + PUBDATA_SOURCE_CUSTOM_PRE_GATEWAY, SUPPORTED_ENCODING_VERSION, }, Tokenizable, }; @@ -240,23 +237,6 @@ impl LocalL1BatchCommitData { let da = detect_da(protocol_version, reference, self.commitment_mode) .context("cannot detect DA source from reference commitment token")?; - // For rollups with `PubdataSendingMode::Calldata`, it's required that the pubdata fits into a single blob. - if matches!(self.commitment_mode, L1BatchCommitmentMode::Rollup) - && matches!(da, PubdataSendingMode::Calldata) - { - let pubdata_len = self - .l1_batch - .header - .pubdata_input - .as_ref() - .map_or_else(|| self.l1_batch.construct_pubdata().len(), Vec::len); - anyhow::ensure!( - pubdata_len <= ZK_SYNC_BYTES_PER_BLOB, - "pubdata size is too large when using calldata DA source: expected <={ZK_SYNC_BYTES_PER_BLOB} bytes, \ - got {pubdata_len} bytes" - ); - } - let local_token = CommitBatchInfo::new(self.commitment_mode, &self.l1_batch, da).into_token(); anyhow::ensure!( diff --git a/core/tests/ts-integration/src/env.ts b/core/tests/ts-integration/src/env.ts index de0dcac2358c..03d8e1ff8d5c 100644 --- a/core/tests/ts-integration/src/env.ts +++ b/core/tests/ts-integration/src/env.ts @@ -7,7 +7,7 @@ import { Reporter } from './reporter'; import * as yaml from 'yaml'; import { L2_BASE_TOKEN_ADDRESS } from 'zksync-ethers/build/utils'; import { FileConfig, loadConfig, loadEcosystem, shouldLoadConfigFromFile } from 'utils/build/file-configs'; -import { NodeSpawner } from './utils'; +import { NodeSpawner } from 'utils'; import { logsTestPath } from 'utils/build/logs'; import * as nodefs from 'node:fs/promises'; import { exec } from 'utils'; diff --git a/core/tests/ts-integration/tests/fees.test.ts b/core/tests/ts-integration/tests/fees.test.ts index fc156e03f16d..765dc8b73a81 100644 --- a/core/tests/ts-integration/tests/fees.test.ts +++ b/core/tests/ts-integration/tests/fees.test.ts @@ -21,7 +21,7 @@ import { logsTestPath } from 'utils/build/logs'; import { sleep } from 'utils/build'; import { killPidWithAllChilds } from 'utils/build/kill'; import path from 'path'; -import { NodeSpawner } from '../src/utils'; +import { NodeSpawner } from 'utils'; import { sendTransfers } from '../src/context-owner'; import { Reporter } from '../src/reporter'; diff --git a/core/tests/upgrade-test/tests/upgrade.test.ts b/core/tests/upgrade-test/tests/upgrade.test.ts index 4065480b121b..8bc8904b6148 100644 --- a/core/tests/upgrade-test/tests/upgrade.test.ts +++ b/core/tests/upgrade-test/tests/upgrade.test.ts @@ -3,52 +3,74 @@ import { Tester } from './tester'; import * as zksync from 'zksync-ethers'; import * as ethers from 'ethers'; import { expect } from 'chai'; -import fs from 'fs'; +import fs from 'node:fs/promises'; +import { existsSync, readFileSync } from 'node:fs'; import { BytesLike } from '@ethersproject/bytes'; -import { IZkSyncHyperchain } from 'zksync-ethers/build/typechain'; import { BigNumberish } from 'ethers'; import { loadConfig, shouldLoadConfigFromFile } from 'utils/build/file-configs'; import { Contracts, initContracts, - runServerInBackground, setAggregatedBlockExecuteDeadline, setAggregatedBlockProveDeadline, setBlockCommitDeadlineMs, setEthSenderSenderAggregatedBlockCommitDeadline } from './utils'; import path from 'path'; +import { ZKSYNC_MAIN_ABI } from 'zksync-ethers/build/utils'; const pathToHome = path.join(__dirname, '../../../..'); const fileConfig = shouldLoadConfigFromFile(); const contracts: Contracts = initContracts(pathToHome, fileConfig.loadFromFile); -let serverComponents = [ - 'api', - 'tree', - 'eth', - 'state_keeper', - 'commitment_generator', - 'da_dispatcher', - 'vm_runner_protective_reads' -]; +const ZK_CHAIN_INTERFACE = JSON.parse( + readFileSync(pathToHome + '/contracts/l1-contracts/out/IZKChain.sol/IZKChain.json').toString() +).abi; const depositAmount = ethers.parseEther('0.001'); +interface GatewayInfo { + gatewayChainId: string; + gatewayProvider: zksync.Provider; + gatewayCTM: string; + l2ChainAdmin: string; + l2DiamondProxyAddress: string; +} + +interface Call { + target: string; + value: BigNumberish; + data: BytesLike; +} + describe('Upgrade test', function () { + // Utility wallets for facilitating testing let tester: Tester; let alice: zksync.Wallet; + + // The wallet that controls the ecosystem governance on L1. let ecosystemGovWallet: ethers.Wallet; - let adminGovWallet: ethers.Wallet; - let mainContract: IZkSyncHyperchain; - let governanceContract: ethers.Contract; - let chainAdminContract: ethers.Contract; + // The wallet that controls the chain admin on the settlement layer. + // The settlement layer can be either Gateway or L1. Depending on this, + // the provider changes. + let slAdminGovWallet: ethers.Wallet; + + // The address of the ecosystem governance. It is present on L1. + let ecosystemGovernance: string; + + // The chain admin contract on the settlement layer. + let slChainAdminContract: ethers.Contract; + // The diamond proxy contract on the settlement layer. + let slMainContract: ethers.Contract; + let bootloaderHash: string; + let defaultAccountHash: string; + let bytecodeSupplier: string; let executeOperation: string; let forceDeployAddress: string; let forceDeployBytecode: string; - let logs: fs.WriteStream; + let logs: fs.FileHandle; let ethProviderAddress: string | undefined; let web3JsonRpc: string | undefined; @@ -58,89 +80,130 @@ describe('Upgrade test', function () { let upgradeAddress: string | undefined; let contractsPriorityTxMaxGasLimit: string; + // Information about Gateway. Note, that it is non-null only if the chain settles + // on top of Gateway, i.e. checking whether this variable is null allows to also know + // whetheer the chain settles on top of Gateway. + let gatewayInfo: GatewayInfo | null = null; + + let mainNodeSpawner: utils.NodeSpawner; + before('Create test wallet', async () => { forceDeployAddress = '0xf04ce00000000000000000000000000000000000'; deployerAddress = '0x0000000000000000000000000000000000008007'; complexUpgraderAddress = '0x000000000000000000000000000000000000800f'; + logs = await fs.open('upgrade.log', 'a'); - if (fileConfig.loadFromFile) { - const generalConfig = loadConfig({ - pathToHome, - chain: fileConfig.chain, - config: 'general.yaml' - }); - const contractsConfig = loadConfig({ - pathToHome, - chain: fileConfig.chain, - config: 'contracts.yaml' - }); - const secretsConfig = loadConfig({ + if (!fileConfig.loadFromFile) { + throw new Error('Non file based not supported'); + } + + const generalConfig = loadConfig({ + pathToHome, + chain: fileConfig.chain, + config: 'general.yaml' + }); + const contractsConfig = loadConfig({ + pathToHome, + chain: fileConfig.chain, + config: 'contracts.yaml' + }); + const secretsConfig = loadConfig({ + pathToHome, + chain: fileConfig.chain, + config: 'secrets.yaml' + }); + const genesisConfig = loadConfig({ + pathToHome, + chain: fileConfig.chain, + config: 'genesis.yaml' + }); + + ethProviderAddress = secretsConfig.l1.l1_rpc_url; + web3JsonRpc = generalConfig.api.web3_json_rpc.http_url; + contractsL2DefaultUpgradeAddr = contractsConfig.l2.default_l2_upgrader; + bytecodeSupplier = contractsConfig.ecosystem_contracts.l1_bytecodes_supplier_addr; + contractsPriorityTxMaxGasLimit = '72000000'; + + const slChainId = genesisConfig.sl_chain_id; + const l1ChainId = genesisConfig.l1_chain_id; + + if (slChainId && l1ChainId != slChainId) { + const gatewayChainConfig = loadConfig({ pathToHome, chain: fileConfig.chain, - config: 'secrets.yaml' + config: 'gateway_chain.yaml' }); - ethProviderAddress = secretsConfig.l1.l1_rpc_url; - web3JsonRpc = generalConfig.api.web3_json_rpc.http_url; - contractsL2DefaultUpgradeAddr = contractsConfig.l2.default_l2_upgrader; - upgradeAddress = contractsConfig.l1.default_upgrade_addr; - contractsPriorityTxMaxGasLimit = '72000000'; - } else { - ethProviderAddress = process.env.L1_RPC_ADDRESS || process.env.ETH_CLIENT_WEB3_URL; - web3JsonRpc = process.env.ZKSYNC_WEB3_API_URL || process.env.API_WEB3_JSON_RPC_HTTP_URL; - contractsL2DefaultUpgradeAddr = process.env.CONTRACTS_L2_DEFAULT_UPGRADE_ADDR!; - - upgradeAddress = process.env.CONTRACTS_DEFAULT_UPGRADE_ADDR; - if (!upgradeAddress) { - throw new Error('CONTRACTS_DEFAULT_UPGRADE_ADDR not set'); - } - contractsPriorityTxMaxGasLimit = process.env.CONTRACTS_PRIORITY_TX_MAX_GAS_LIMIT!; + gatewayInfo = { + gatewayChainId: slChainId, + gatewayProvider: new zksync.Provider(secretsConfig.l1.gateway_url), + gatewayCTM: gatewayChainConfig.state_transition_proxy_addr, + l2ChainAdmin: gatewayChainConfig.chain_admin_addr, + l2DiamondProxyAddress: gatewayChainConfig.diamond_proxy_addr + }; } + mainNodeSpawner = new utils.NodeSpawner(pathToHome, logs, fileConfig, { + enableConsensus: false, + ethClientWeb3Url: ethProviderAddress!, + apiWeb3JsonRpcHttpUrl: web3JsonRpc!, + baseTokenAddress: contractsConfig.l1.base_token_addr + }); + tester = await Tester.init(ethProviderAddress!, web3JsonRpc!); alice = tester.emptyWallet(); - if (fileConfig.loadFromFile) { - const chainWalletConfig = loadConfig({ - pathToHome, - chain: fileConfig.chain, - config: 'wallets.yaml' - }); + const chainWalletConfig = loadConfig({ + pathToHome, + chain: fileConfig.chain, + config: 'wallets.yaml' + }); - adminGovWallet = new ethers.Wallet(chainWalletConfig.governor.private_key, alice._providerL1()); + slAdminGovWallet = gatewayInfo + ? new zksync.Wallet(chainWalletConfig.governor.private_key, gatewayInfo.gatewayProvider) + : new ethers.Wallet(chainWalletConfig.governor.private_key, alice._providerL1()); - const ecosystemWalletConfig = loadConfig({ - pathToHome, - chain: fileConfig.chain, - configsFolder: '../../configs/', - config: 'wallets.yaml' - }); + const ecosystemWalletConfig = loadConfig({ + pathToHome, + chain: fileConfig.chain, + configsFolder: '../../configs/', + config: 'wallets.yaml' + }); - if (ecosystemWalletConfig.governor.private_key == chainWalletConfig.governor.private_key) { - ecosystemGovWallet = adminGovWallet; - } else { - ecosystemGovWallet = new ethers.Wallet(ecosystemWalletConfig.governor.private_key, alice._providerL1()); - } + // Note, that the following check is needed to reduce flackiness. In case the + // `ecosystemGovWallet` and `slAdminGovWallet` refer to the same account, then + // sending transactions from the same account while using different `Wallet` objects + // could lead to flacky issues. + if (chainWalletConfig.governor.private_key == ecosystemWalletConfig.governor.private_key && !gatewayInfo) { + ecosystemGovWallet = slAdminGovWallet; } else { - let govMnemonic = ethers.Mnemonic.fromPhrase( - require('../../../../etc/test_config/constant/eth.json').mnemonic - ); - let govWalletHD = ethers.HDNodeWallet.fromMnemonic(govMnemonic, "m/44'/60'/0'/0/1"); - adminGovWallet = new ethers.Wallet(govWalletHD.privateKey, alice._providerL1()); - ecosystemGovWallet = adminGovWallet; + ecosystemGovWallet = new ethers.Wallet(ecosystemWalletConfig.governor.private_key, alice._providerL1()); } - logs = fs.createWriteStream('upgrade.log', { flags: 'a' }); + upgradeAddress = await deployDefaultUpgradeImpl(slAdminGovWallet); + forceDeployBytecode = contracts.counterBytecode; + + slChainAdminContract = gatewayInfo + ? new ethers.Contract(gatewayInfo.l2ChainAdmin, contracts.chainAdminAbi, gatewayInfo.gatewayProvider) + : new ethers.Contract( + contractsConfig.l1.chain_admin_addr, + contracts.chainAdminAbi, + tester.syncWallet.providerL1 + ); + + slMainContract = gatewayInfo + ? new ethers.Contract(gatewayInfo.l2DiamondProxyAddress, ZKSYNC_MAIN_ABI, gatewayInfo.gatewayProvider) + : new ethers.Contract(contractsConfig.l1.diamond_proxy_addr, ZKSYNC_MAIN_ABI, tester.syncWallet.providerL1); + + const l1CtmContract = new ethers.Contract( + contractsConfig.ecosystem_contracts.state_transition_proxy_addr, + contracts.chainTypeManager, + tester.syncWallet.providerL1 + ); + ecosystemGovernance = await l1CtmContract.owner(); }); step('Run server and execute some transactions', async () => { - // Make sure server isn't running. - try { - await utils.exec('pkill zksync_server'); - // It may take some time for witness generator to stop. - await utils.sleep(10); - } catch (_) {} - // Set small timeouts. process.env.ETH_SENDER_SENDER_AGGREGATED_BLOCK_COMMIT_DEADLINE = '1'; process.env.ETH_SENDER_SENDER_AGGREGATED_BLOCK_PROVE_DEADLINE = '1'; @@ -154,36 +217,9 @@ describe('Upgrade test', function () { setAggregatedBlockExecuteDeadline(pathToHome, fileConfig, 1); setBlockCommitDeadlineMs(pathToHome, fileConfig, 2000); } + await mainNodeSpawner.killAndSpawnMainNode(); - // Run server in background. - runServerInBackground({ - components: serverComponents, - stdio: ['ignore', logs, logs], - cwd: pathToHome, - useZkStack: fileConfig.loadFromFile, - chain: fileConfig.chain - }); - // Server may need some time to recompile if it's a cold run, so wait for it. - let iter = 0; - while (iter < 30 && !mainContract) { - try { - mainContract = await tester.syncWallet.getMainContract(); - } catch (_) { - await utils.sleep(1); - } - iter += 1; - } - if (!mainContract) { - throw new Error('Server did not start'); - } - - const stmAddr = await mainContract.getStateTransitionManager(); - const stmContract = new ethers.Contract(stmAddr, contracts.stateTransitonManager, tester.syncWallet.providerL1); - const governanceAddr = await stmContract.owner(); - governanceContract = new ethers.Contract(governanceAddr, contracts.governanceAbi, tester.syncWallet.providerL1); - const chainAdminAddr = await mainContract.getAdmin(); - chainAdminContract = new ethers.Contract(chainAdminAddr, contracts.chainAdminAbi, tester.syncWallet.providerL1); - let blocksCommitted = await mainContract.getTotalBatchesCommitted(); + let blocksCommitted = await slMainContract.getTotalBatchesCommitted(); const initialL1BatchNumber = await tester.web3Provider.getL1BatchNumber(); @@ -226,42 +262,35 @@ describe('Upgrade test', function () { } // Wait for at least one new committed block - let newBlocksCommitted = await mainContract.getTotalBatchesCommitted(); + let newBlocksCommitted = await slMainContract.getTotalBatchesCommitted(); let tryCount = 0; while (blocksCommitted === newBlocksCommitted && tryCount < 30) { - newBlocksCommitted = await mainContract.getTotalBatchesCommitted(); + newBlocksCommitted = await slMainContract.getTotalBatchesCommitted(); tryCount += 1; await utils.sleep(1); } }); - step('Send l1 tx for saving new bootloader', async () => { - const path = `${pathToHome}/contracts/system-contracts/zkout/playground_batch.yul/contracts-preprocessed/bootloader/playground_batch.yul.json`; - let bootloaderCode; - if (fs.existsSync(path)) { - bootloaderCode = '0x'.concat(require(path).bytecode.object); - } else { - const legacyPath = `${pathToHome}/contracts/system-contracts/bootloader/build/artifacts/playground_batch.yul.zbin`; - bootloaderCode = ethers.hexlify(fs.readFileSync(legacyPath)); - } + step('Publish bytecodes', async () => { + const bootloaderCode = readCode( + 'contracts/system-contracts/zkout/playground_batch.yul/contracts-preprocessed/bootloader/playground_batch.yul.json', + 'contracts/system-contracts/bootloader/build/artifacts/playground_batch.yul.zbin' + ); + + const defaultAACode = readCode( + 'contracts/system-contracts/zkout/DefaultAccount.sol/DefaultAccount.json', + 'contracts/system-contracts/artifacts-zk/contracts-preprocessed/DefaultAccount.sol/DefaultAccount.json' + ); bootloaderHash = ethers.hexlify(zksync.utils.hashBytecode(bootloaderCode)); - const txHandle = await tester.syncWallet.requestExecute({ - contractAddress: ethers.ZeroAddress, - calldata: '0x', - l2GasLimit: 20000000, - factoryDeps: [bootloaderCode], - overrides: { - gasLimit: 3000000 - } - }); - await txHandle.wait(); - await waitForNewL1Batch(alice); + defaultAccountHash = ethers.hexlify(zksync.utils.hashBytecode(defaultAACode)); + + await publishBytecode(tester.ethWallet, bytecodeSupplier, bootloaderCode); + await publishBytecode(tester.ethWallet, bytecodeSupplier, defaultAACode); + await publishBytecode(tester.ethWallet, bytecodeSupplier, forceDeployBytecode); }); step('Schedule governance call', async () => { - forceDeployBytecode = contracts.counterBytecode; - const forceDeployment: ForceDeployment = { bytecodeHash: ethers.hexlify(zksync.utils.hashBytecode(forceDeployBytecode)), newAddress: forceDeployAddress, @@ -279,7 +308,7 @@ describe('Upgrade test', function () { ]); const { stmUpgradeData, chainUpgradeCalldata, setTimestampCalldata } = await prepareUpgradeCalldata( - adminGovWallet, + alice._providerL1(), alice._providerL2(), upgradeAddress!, { @@ -296,23 +325,37 @@ describe('Upgrade test', function () { reserved: [0, 0, 0, 0], data, signature: '0x', - factoryDeps: [ethers.hexlify(zksync.utils.hashBytecode(forceDeployBytecode))], + factoryDeps: [ + bootloaderHash, + defaultAccountHash, + ethers.hexlify(zksync.utils.hashBytecode(forceDeployBytecode)) + ], paymasterInput: '0x', reservedDynamic: '0x' }, - factoryDeps: [forceDeployBytecode], bootloaderHash, upgradeTimestamp: 0 - } + }, + gatewayInfo ); executeOperation = chainUpgradeCalldata; console.log('Sending scheduleTransparentOperation'); - await sendGovernanceOperation(stmUpgradeData.scheduleTransparentOperation); + await sendGovernanceOperation(stmUpgradeData.scheduleTransparentOperation, 0, null); + console.log('Sending executeOperation'); - await sendGovernanceOperation(stmUpgradeData.executeOperation); + await sendGovernanceOperation( + stmUpgradeData.executeOperation, + stmUpgradeData.executeOperationValue, + gatewayInfo ? gatewayInfo.gatewayProvider : null + ); + console.log('Sending chain admin operation'); - await sendChainAdminOperation(setTimestampCalldata); + await sendChainAdminOperation({ + target: await slChainAdminContract.getAddress(), + data: setTimestampCalldata, + value: 0 + }); // Wait for server to process L1 event. await utils.sleep(2); @@ -334,10 +377,10 @@ describe('Upgrade test', function () { l1BatchNumber -= 1; } - let lastBatchExecuted = await mainContract.getTotalBatchesExecuted(); + let lastBatchExecuted = await slMainContract.getTotalBatchesExecuted(); let tryCount = 0; while (lastBatchExecuted < l1BatchNumber && tryCount < 40) { - lastBatchExecuted = await mainContract.getTotalBatchesExecuted(); + lastBatchExecuted = await slMainContract.getTotalBatchesExecuted(); tryCount += 1; await utils.sleep(2); } @@ -346,13 +389,13 @@ describe('Upgrade test', function () { } // Execute the upgrade - const executeMulticallData = chainAdminContract.interface.encodeFunctionData('multicall', [ - [[await mainContract.getAddress(), 0, executeOperation]], - true - ]); - await sendChainAdminOperation(executeMulticallData); + await sendChainAdminOperation({ + target: await slMainContract.getAddress(), + data: executeOperation, + value: 0 + }); - let bootloaderHashL1 = await mainContract.getL2BootloaderBytecodeHash(); + let bootloaderHashL1 = await slMainContract.getL2BootloaderBytecodeHash(); expect(bootloaderHashL1).eq(bootloaderHash); }); @@ -369,18 +412,7 @@ describe('Upgrade test', function () { step('Execute transactions after simple restart', async () => { // Stop server. - await utils.exec('pkill zksync_server'); - await utils.sleep(10); - - // Run again. - runServerInBackground({ - components: serverComponents, - stdio: ['ignore', logs, logs], - cwd: pathToHome, - useZkStack: fileConfig.loadFromFile, - chain: fileConfig.chain - }); - await utils.sleep(10); + await mainNodeSpawner.killAndSpawnMainNode(); // Trying to send a transaction from the same address again await checkedRandomTransfer(alice, 1n); @@ -399,29 +431,93 @@ describe('Upgrade test', function () { } catch (_) {} }); - async function sendGovernanceOperation(data: string) { + async function sendGovernanceOperation( + data: string, + value: BigNumberish, + providerForPriorityOp: zksync.Provider | null + ) { const transaction = await ecosystemGovWallet.sendTransaction({ - to: await governanceContract.getAddress(), + to: ecosystemGovernance, + value: value, data: data, type: 0 }); console.log(`Sent governance operation, tx_hash=${transaction.hash}, nonce=${transaction.nonce}`); - await transaction.wait(); + const receipt = await transaction.wait(); console.log(`Governance operation succeeded, tx_hash=${transaction.hash}`); + + // The governance operations may trigger additional L1->L2 transactions to gateway, which we should wait. + if (!providerForPriorityOp) { + // No further waiting is needed. + return; + } + + const contract = await providerForPriorityOp.getMainContractAddress(); + const hash = zksync.utils.getL2HashFromPriorityOp(receipt!, contract); + console.log(`Gateway L1->L2 transaction with hash ${hash} detected`); + + await providerForPriorityOp.waitForTransaction(hash); + console.log('Transaction complete!'); } - async function sendChainAdminOperation(data: string) { - const transaction = await adminGovWallet.sendTransaction({ - to: await chainAdminContract.getAddress(), - data: data, + async function sendChainAdminOperation(call: Call) { + const executeMulticallData = slChainAdminContract.interface.encodeFunctionData('multicall', [[call], true]); + + const transaction = await slAdminGovWallet.sendTransaction({ + to: await slChainAdminContract.getAddress(), + data: executeMulticallData, type: 0 }); console.log(`Sent chain admin operation, tx_hash=${transaction.hash}, nonce=${transaction.nonce}`); await transaction.wait(); console.log(`Chain admin operation succeeded, tx_hash=${transaction.hash}`); } + + async function deployDefaultUpgradeImpl(runner: ethers.Wallet): Promise