From ea0b15a68276f28c23d8f90f8a9d11c48371f208 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Wed, 24 Jan 2024 00:46:13 +0200 Subject: [PATCH 01/37] Diff reducing commit --- core/bin/external_node/src/config/mod.rs | 7 + core/lib/config/src/configs/contracts.rs | 12 + ...de45f8f3f3b6cf2e4136f25a1c3ab85d92668.json | 15 + core/lib/dal/src/protocol_versions_dal.rs | 39 +++ core/lib/env_config/src/contracts.rs | 5 + core/lib/types/src/protocol_version.rs | 280 +++++++++++------- core/lib/web3_decl/src/namespaces/zks.rs | 3 + .../src/api_server/execution_sandbox/apply.rs | 2 +- .../src/api_server/execution_sandbox/mod.rs | 2 +- .../web3/backend_jsonrpsee/namespaces/zks.rs | 4 + .../src/api_server/web3/namespaces/zks.rs | 5 + .../zksync_core/src/api_server/web3/state.rs | 2 + .../src/eth_sender/eth_tx_aggregator.rs | 2 - core/lib/zksync_core/src/eth_watch/client.rs | 28 +- .../src/eth_watch/event_processors/mod.rs | 1 + .../event_processors/set_chain_id.rs | 98 ++++++ core/lib/zksync_core/src/eth_watch/mod.rs | 7 +- core/lib/zksync_core/src/eth_watch/tests.rs | 6 +- core/lib/zksync_core/src/lib.rs | 3 + .../zksync_core/src/state_keeper/keeper.rs | 67 +++-- 20 files changed, 450 insertions(+), 138 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668.json create mode 100644 core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index 6bf06f049303..d8d26eea8bb2 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -22,6 +22,7 @@ const BYTES_IN_MEGABYTE: usize = 1_024 * 1_024; /// This part of the external node config is fetched directly from the main node. #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct RemoteENConfig { + pub bridgehub_proxy_addr: Address, pub diamond_proxy_addr: Address, pub l1_erc20_bridge_proxy_addr: Address, pub l2_erc20_bridge_addr: Address, @@ -42,6 +43,10 @@ impl RemoteENConfig { .get_testnet_paymaster() .await .context("Failed to fetch paymaster")?; + let bridgehub_proxy_addr = client + .get_bridgehub_contract() + .await + .context("Failed to fetch L1 bridgehub contract address")?; let diamond_proxy_addr = client .get_main_contract() .await @@ -63,6 +68,7 @@ impl RemoteENConfig { ); Ok(Self { + bridgehub_proxy_addr, diamond_proxy_addr, l2_testnet_paymaster_addr, l1_erc20_bridge_proxy_addr: bridges.l1_erc20_default_bridge, @@ -510,6 +516,7 @@ impl From for InternalApiConfig { l1_weth_bridge: config.remote.l1_weth_bridge_proxy_addr, l2_weth_bridge: config.remote.l2_weth_bridge_addr, }, + bridgehub_proxy_addr: config.remote.bridgehub_proxy_addr, diamond_proxy_addr: config.remote.diamond_proxy_addr, l2_testnet_paymaster_addr: config.remote.l2_testnet_paymaster_addr, req_entities_limit: config.optional.req_entities_limit, diff --git a/core/lib/config/src/configs/contracts.rs b/core/lib/config/src/configs/contracts.rs index a05027e0bf0d..26fad9ff70b6 100644 --- a/core/lib/config/src/configs/contracts.rs +++ b/core/lib/config/src/configs/contracts.rs @@ -14,6 +14,13 @@ pub enum ProverAtGenesis { pub struct ContractsConfig { pub governance_addr: Address, pub mailbox_facet_addr: Address, + + pub bridgehub_proxy_addr: Address, + pub bridgehub_impl_addr: Address, + pub state_transition_proxy_addr: Address, + pub state_transition_impl_addr: Address, + pub transparent_proxy_admin_addr: Address, + pub executor_facet_addr: Address, pub admin_facet_addr: Address, pub getters_facet_addr: Address, @@ -49,6 +56,10 @@ impl ContractsConfig { /// Same goes for hashes. pub fn for_tests() -> Self { Self { + bridgehub_proxy_addr: Address::repeat_byte(0x01), + bridgehub_impl_addr: Address::repeat_byte(0x01), + state_transition_proxy_addr: Address::repeat_byte(0x01), + state_transition_impl_addr: Address::repeat_byte(0x01), mailbox_facet_addr: Address::repeat_byte(0x01), executor_facet_addr: Address::repeat_byte(0x02), admin_facet_addr: Address::repeat_byte(0x03), @@ -57,6 +68,7 @@ impl ContractsConfig { diamond_init_addr: Address::repeat_byte(0x07), diamond_upgrade_init_addr: Address::repeat_byte(0x08), diamond_proxy_addr: Address::repeat_byte(0x09), + transparent_proxy_admin_addr: Address::repeat_byte(0x09), validator_timelock_addr: Address::repeat_byte(0x0a), genesis_tx_hash: H256::repeat_byte(0x01), l1_erc20_bridge_proxy_addr: Address::repeat_byte(0x0b), diff --git a/core/lib/dal/.sqlx/query-a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668.json b/core/lib/dal/.sqlx/query-a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668.json new file mode 100644 index 000000000000..1fd7b8fdf1b3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE protocol_versions\n SET\n upgrade_tx_hash = $1\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668" +} diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 8aad040221c4..400a973c66a4 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -98,6 +98,45 @@ impl ProtocolVersionsDal<'_, '_> { db_transaction.commit().await.unwrap(); } + pub async fn save_genesis_upgrade(&mut self, id: ProtocolVersionId, tx_hash: Option) { + sqlx::query!( + r#" + UPDATE protocol_versions + SET + upgrade_tx_hash = $1 + WHERE + id = $2 + "#, + tx_hash.map(|tx_hash| tx_hash.0.to_vec()), + id as i32, + ) + .execute(self.storage.conn()) + .await + .unwrap(); + } + + pub async fn save_genesis_upgrade_with_tx( + &mut self, + id: ProtocolVersionId, + tx: ProtocolUpgradeTx, + ) { + let tx_hash = Some(tx.common_data.hash()); + + let mut db_transaction = self.storage.start_transaction().await.unwrap(); + + db_transaction + .transactions_dal() + .insert_system_transaction(tx) + .await; + + db_transaction + .protocol_versions_dal() + .save_genesis_upgrade(id, tx_hash) + .await; + + db_transaction.commit().await.unwrap(); + } + pub async fn base_system_contracts_by_timestamp( &mut self, current_timestamp: u64, diff --git a/core/lib/env_config/src/contracts.rs b/core/lib/env_config/src/contracts.rs index 537b68414c63..ba4d5f4a7f12 100644 --- a/core/lib/env_config/src/contracts.rs +++ b/core/lib/env_config/src/contracts.rs @@ -19,6 +19,10 @@ mod tests { fn expected_config() -> ContractsConfig { ContractsConfig { + bridgehub_proxy_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), + bridgehub_impl_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), + state_transition_proxy_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), + state_transition_impl_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), governance_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), mailbox_facet_addr: addr("0f6Fa881EF414Fc6E818180657c2d5CD7Ac6cCAd"), executor_facet_addr: addr("18B631537801963A964211C0E86645c1aBfbB2d3"), @@ -28,6 +32,7 @@ mod tests { diamond_init_addr: addr("FFC35A5e767BE36057c34586303498e3de7C62Ba"), diamond_upgrade_init_addr: addr("FFC35A5e767BE36057c34586303498e3de7C62Ba"), diamond_proxy_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"), + transparent_proxy_admin_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), validator_timelock_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"), genesis_tx_hash: hash( "b99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e", diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 38caa0f8a20e..0339f0b5a215 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -303,119 +303,21 @@ impl TryFrom for ProtocolUpgrade { unreachable!(); }; - let Token::Tuple(mut transaction) = decoded.remove(0) else { + let Token::Tuple(transaction) = decoded.remove(0) else { unreachable!() }; let factory_deps = decoded.remove(0).into_array().unwrap(); - let tx = { - let canonical_tx_hash = H256(keccak256(&encode(&[Token::Tuple(transaction.clone())]))); - - assert_eq!(transaction.len(), 16); - - let tx_type = transaction.remove(0).into_uint().unwrap(); - if tx_type == PROTOCOL_UPGRADE_TX_TYPE.into() { - // There is an upgrade tx. Decoding it. - let sender = transaction.remove(0).into_uint().unwrap(); - let sender = u256_to_account_address(&sender); - - let contract_address = transaction.remove(0).into_uint().unwrap(); - let contract_address = u256_to_account_address(&contract_address); - - let gas_limit = transaction.remove(0).into_uint().unwrap(); - - let gas_per_pubdata_limit = transaction.remove(0).into_uint().unwrap(); - - let max_fee_per_gas = transaction.remove(0).into_uint().unwrap(); - - let max_priority_fee_per_gas = transaction.remove(0).into_uint().unwrap(); - assert_eq!(max_priority_fee_per_gas, U256::zero()); - - let paymaster = transaction.remove(0).into_uint().unwrap(); - let paymaster = u256_to_account_address(&paymaster); - assert_eq!(paymaster, Address::zero()); - - let upgrade_id = transaction.remove(0).into_uint().unwrap(); - - let msg_value = transaction.remove(0).into_uint().unwrap(); - - let reserved = transaction - .remove(0) - .into_fixed_array() - .unwrap() - .into_iter() - .map(|token| token.into_uint().unwrap()) - .collect::>(); - assert_eq!(reserved.len(), 4); - - let to_mint = reserved[0]; - let refund_recipient = u256_to_account_address(&reserved[1]); - - // All other reserved fields should be zero - for item in reserved.iter().skip(2) { - assert_eq!(item, &U256::zero()); - } + let eth_hash = event + .transaction_hash + .expect("Event transaction hash is missing"); + let eth_block = event + .block_number + .expect("Event block number is missing") + .as_u64(); - let calldata = transaction.remove(0).into_bytes().unwrap(); - - let signature = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(signature.len(), 0); - - let _factory_deps_hashes = transaction.remove(0).into_array().unwrap(); - - let paymaster_input = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(paymaster_input.len(), 0); - - // TODO (SMA-1621): check that `reservedDynamic` are constructed correctly. - let reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(reserved_dynamic.len(), 0); - - let eth_hash = event - .transaction_hash - .expect("Event transaction hash is missing"); - let eth_block = event - .block_number - .expect("Event block number is missing") - .as_u64(); - - let common_data = ProtocolUpgradeTxCommonData { - canonical_tx_hash, - sender, - upgrade_id: (upgrade_id.as_u32() as u16).try_into().unwrap(), - to_mint, - refund_recipient, - gas_limit, - max_fee_per_gas, - gas_per_pubdata_limit, - eth_hash, - eth_block, - }; - - let factory_deps = factory_deps - .into_iter() - .map(|t| t.into_bytes().unwrap()) - .collect(); - - let execute = Execute { - contract_address, - calldata: calldata.to_vec(), - factory_deps: Some(factory_deps), - value: msg_value, - }; - - Some(ProtocolUpgradeTx { - common_data, - execute, - received_timestamp_ms: unix_timestamp_ms(), - }) - } else if tx_type == U256::zero() { - // There is no upgrade tx. - None - } else { - panic!("Unexpected tx type {} when decoding upgrade", tx_type); - } - }; + let tx = ProtocolUpgradeTx::decode_tx(transaction, eth_hash, eth_block, factory_deps); let bootloader_code_hash = H256::from_slice(&decoded.remove(0).into_fixed_bytes().unwrap()); let default_account_code_hash = H256::from_slice(&decoded.remove(0).into_fixed_bytes().unwrap()); @@ -462,6 +364,170 @@ impl TryFrom for ProtocolUpgrade { } } +impl ProtocolUpgrade { + pub fn decode_set_chain_id_event( + event: Log, + timestamp: u64, + ) -> Result>::Error> { + let transaction_param_type = ParamType::Tuple(vec![ + ParamType::Uint(256), // txType + ParamType::Uint(256), // sender + ParamType::Uint(256), // to + ParamType::Uint(256), // gasLimit + ParamType::Uint(256), // gasPerPubdataLimit + ParamType::Uint(256), // maxFeePerGas + ParamType::Uint(256), // maxPriorityFeePerGas + ParamType::Uint(256), // paymaster + ParamType::Uint(256), // nonce (serial ID) + ParamType::Uint(256), // value + ParamType::FixedArray(Box::new(ParamType::Uint(256)), 4), // reserved + ParamType::Bytes, // calldata + ParamType::Bytes, // signature + ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps + ParamType::Bytes, // paymaster input + ParamType::Bytes, // reservedDynamic + ]); + + let Token::Tuple(transaction) = decode(&[transaction_param_type], &event.data.0)?.remove(0) + else { + unreachable!() + }; + + let version_id = event.topics[2].to_low_u64_be(); + + let eth_hash = event + .transaction_hash + .expect("Event transaction hash is missing"); + let eth_block = event + .block_number + .expect("Event block number is missing") + .as_u64(); + + let factory_deps: Vec = Vec::new(); + + let upgrade_tx = + ProtocolUpgradeTx::decode_tx(transaction, eth_hash, eth_block, factory_deps); + + let upgrade = ProtocolUpgrade { + id: ProtocolVersionId::try_from(version_id as u16).expect("Version is not supported"), + bootloader_code_hash: None, + default_account_code_hash: None, + verifier_params: None, + verifier_address: None, + timestamp, + tx: upgrade_tx, + }; + Ok(upgrade) + } +} + +impl ProtocolUpgradeTx { + pub fn decode_tx( + mut transaction: Vec, + eth_hash: H256, + eth_block: u64, + factory_deps: Vec, + ) -> Option { + let canonical_tx_hash = H256(keccak256(&encode(&[Token::Tuple(transaction.clone())]))); + + assert_eq!(transaction.len(), 16); + + let tx_type = transaction.remove(0).into_uint().unwrap(); + if tx_type == PROTOCOL_UPGRADE_TX_TYPE.into() { + // There is an upgrade tx. Decoding it. + let sender = transaction.remove(0).into_uint().unwrap(); + let sender = u256_to_account_address(&sender); + + let contract_address = transaction.remove(0).into_uint().unwrap(); + let contract_address = u256_to_account_address(&contract_address); + + let gas_limit = transaction.remove(0).into_uint().unwrap(); + + let gas_per_pubdata_limit = transaction.remove(0).into_uint().unwrap(); + + let max_fee_per_gas = transaction.remove(0).into_uint().unwrap(); + + let max_priority_fee_per_gas = transaction.remove(0).into_uint().unwrap(); + assert_eq!(max_priority_fee_per_gas, U256::zero()); + + let paymaster = transaction.remove(0).into_uint().unwrap(); + let paymaster = u256_to_account_address(&paymaster); + assert_eq!(paymaster, Address::zero()); + + let upgrade_id = transaction.remove(0).into_uint().unwrap(); + + let msg_value = transaction.remove(0).into_uint().unwrap(); + + let reserved = transaction + .remove(0) + .into_fixed_array() + .unwrap() + .into_iter() + .map(|token| token.into_uint().unwrap()) + .collect::>(); + assert_eq!(reserved.len(), 4); + + let to_mint = reserved[0]; + let refund_recipient = u256_to_account_address(&reserved[1]); + + // All other reserved fields should be zero + for item in reserved.iter().skip(2) { + assert_eq!(item, &U256::zero()); + } + + let calldata = transaction.remove(0).into_bytes().unwrap(); + + let signature = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(signature.len(), 0); + + let _factory_deps_hashes = transaction.remove(0).into_array().unwrap(); + + let paymaster_input = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(paymaster_input.len(), 0); + + // TODO (SMA-1621): check that reservedDynamic are constructed correctly. + let reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(reserved_dynamic.len(), 0); + + let common_data = ProtocolUpgradeTxCommonData { + canonical_tx_hash, + sender, + upgrade_id: (upgrade_id.as_u32() as u16).try_into().unwrap(), + to_mint, + refund_recipient, + gas_limit, + max_fee_per_gas, + gas_per_pubdata_limit, + eth_hash, + eth_block, + }; + + let factory_deps = factory_deps + .into_iter() + .map(|t| t.into_bytes().unwrap()) + .collect(); + + let execute = Execute { + contract_address, + calldata: calldata.to_vec(), + factory_deps: Some(factory_deps), + value: msg_value, + }; + + Some(ProtocolUpgradeTx { + common_data, + execute, + received_timestamp_ms: unix_timestamp_ms(), + }) + } else if tx_type == U256::zero() { + // There is no upgrade tx. + None + } else { + panic!("Unexpected tx type {} when decoding upgrade", tx_type); + } + } +} + impl TryFrom for ProtocolUpgrade { type Error = crate::ethabi::Error; diff --git a/core/lib/web3_decl/src/namespaces/zks.rs b/core/lib/web3_decl/src/namespaces/zks.rs index a9eddaa03122..0c808c043f18 100644 --- a/core/lib/web3_decl/src/namespaces/zks.rs +++ b/core/lib/web3_decl/src/namespaces/zks.rs @@ -34,6 +34,9 @@ pub trait ZksNamespace { #[method(name = "estimateGasL1ToL2")] async fn estimate_gas_l1_to_l2(&self, req: CallRequest) -> RpcResult; + #[method(name = "getBridgehubContract")] + async fn get_bridgehub_contract(&self) -> RpcResult
; + #[method(name = "getMainContract")] async fn get_main_contract(&self) -> RpcResult
; diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/apply.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/apply.rs index 25b01495eb74..f65ae9db3f43 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/apply.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/apply.rs @@ -324,7 +324,7 @@ impl BlockArgs { ) } - pub(crate) async fn resolve_block_info( + pub async fn resolve_block_info( &self, connection: &mut StorageProcessor<'_>, ) -> anyhow::Result { diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs index 3c3a8e9a36ad..7ac18aae858a 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs @@ -284,7 +284,7 @@ pub(crate) struct BlockArgs { } impl BlockArgs { - pub(crate) async fn pending(connection: &mut StorageProcessor<'_>) -> anyhow::Result { + pub async fn pending(connection: &mut StorageProcessor<'_>) -> anyhow::Result { let (block_id, resolved_block_number) = get_pending_state(connection).await?; Ok(Self { block_id, diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs index db0760a66c76..7a9fc8e46ccb 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs @@ -31,6 +31,10 @@ impl ZksNamespaceServer for ZksNamespace { .map_err(into_jsrpc_error) } + async fn get_bridgehub_contract(&self) -> RpcResult
{ + Ok(self.get_bridgehub_contract_impl()) + } + async fn get_main_contract(&self) -> RpcResult
{ Ok(self.get_main_contract_impl()) } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs index 86f879a87373..ce610f8da98d 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs @@ -123,6 +123,11 @@ impl ZksNamespace { .map_err(|err| err.into_web3_error(method_name)) } + #[tracing::instrument(skip(self))] + pub fn get_bridgehub_contract_impl(&self) -> Address { + self.state.api_config.bridgehub_proxy_addr + } + #[tracing::instrument(skip(self))] pub fn get_main_contract_impl(&self) -> Address { self.state.api_config.diamond_proxy_addr diff --git a/core/lib/zksync_core/src/api_server/web3/state.rs b/core/lib/zksync_core/src/api_server/web3/state.rs index 180e2de7211f..0964f21c48bf 100644 --- a/core/lib/zksync_core/src/api_server/web3/state.rs +++ b/core/lib/zksync_core/src/api_server/web3/state.rs @@ -81,6 +81,7 @@ pub struct InternalApiConfig { pub estimate_gas_scale_factor: f64, pub estimate_gas_acceptable_overestimation: u32, pub bridge_addresses: api::BridgeAddresses, + pub bridgehub_proxy_addr: Address, pub diamond_proxy_addr: Address, pub l2_testnet_paymaster_addr: Option
, pub req_entities_limit: usize, @@ -106,6 +107,7 @@ impl InternalApiConfig { l1_weth_bridge: contracts_config.l1_weth_bridge_proxy_addr, l2_weth_bridge: contracts_config.l2_weth_bridge_addr, }, + bridgehub_proxy_addr: contracts_config.bridgehub_proxy_addr, diamond_proxy_addr: contracts_config.diamond_proxy_addr, l2_testnet_paymaster_addr: contracts_config.l2_testnet_paymaster_addr, req_entities_limit: web3_config.req_entities_limit(), diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs index 6211b6363849..588c1f368b6f 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs @@ -296,7 +296,6 @@ impl EthTxAggregator { // This is here for backward compatibility with the old verifier: // Pre-boojum verifier returns the full verification key; // New verifier returns the hash of the verification key - tracing::debug!("Calling get_verification_key"); if contracts_are_pre_boojum { let abi = Contract { functions: [( @@ -313,7 +312,6 @@ impl EthTxAggregator { Ok(l1_vk_commitment(Token::from_tokens(vk)?)) } else { let get_vk_hash = self.functions.verification_key_hash.as_ref(); - tracing::debug!("Calling verificationKeyHash"); let args = CallFunctionArgs::new(&get_vk_hash.unwrap().name, ()) .for_contract(verifier_address, self.functions.verifier_contract.clone()); let vk_hash = self.eth_client.call_contract_function(args).await?; diff --git a/core/lib/zksync_core/src/eth_watch/client.rs b/core/lib/zksync_core/src/eth_watch/client.rs index 08e62c3f4ea0..5c9866518b9b 100644 --- a/core/lib/zksync_core/src/eth_watch/client.rs +++ b/core/lib/zksync_core/src/eth_watch/client.rs @@ -8,7 +8,7 @@ use zksync_types::{ web3::{ self, contract::tokens::Detokenize, - types::{BlockId, BlockNumber, FilterBuilder, Log}, + types::{Block, BlockId, BlockNumber, FilterBuilder, Log}, }, Address, H256, }; @@ -44,6 +44,8 @@ pub trait EthClient: 'static + fmt::Debug + Send + Sync { async fn finalized_block_number(&self) -> Result; /// Returns scheduler verification key hash by verifier address. async fn scheduler_vk_hash(&self, verifier_address: Address) -> Result; + /// Gets block info by block hash. + async fn get_block(&self, block_hash: H256) -> Result>, Error>; /// Sets list of topics to return events for. fn set_topics(&mut self, topics: Vec); } @@ -57,6 +59,7 @@ pub struct EthHttpQueryClient { client: Box, topics: Vec, zksync_contract_addr: Address, + state_transition_manager_contract_addr: Address, /// Address of the `Governance` contract. It's optional because it is present only for post-boojum chains. /// If address is some then client will listen to events coming from it. governance_address: Option
, @@ -68,6 +71,7 @@ impl EthHttpQueryClient { pub fn new( client: Box, zksync_contract_addr: Address, + state_transition_manager_contract_addr: Address, governance_address: Option
, confirmations_for_eth_event: Option, ) -> Self { @@ -80,6 +84,7 @@ impl EthHttpQueryClient { client, topics: Vec::new(), zksync_contract_addr, + state_transition_manager_contract_addr, governance_address, verifier_contract_abi: verifier_contract(), confirmations_for_eth_event, @@ -94,11 +99,15 @@ impl EthHttpQueryClient { ) -> Result, Error> { let filter = FilterBuilder::default() .address( - [Some(self.zksync_contract_addr), self.governance_address] - .iter() - .flatten() - .copied() - .collect(), + [ + Some(self.zksync_contract_addr), + Some(self.state_transition_manager_contract_addr), + self.governance_address, + ] + .iter() + .flatten() + .copied() + .collect(), ) .from_block(from) .to_block(to) @@ -111,6 +120,13 @@ impl EthHttpQueryClient { #[async_trait::async_trait] impl EthClient for EthHttpQueryClient { + async fn get_block(&self, block_hash: H256) -> Result>, Error> { + self.client + .block(BlockId::Hash(block_hash), "watch") + .await + .map_err(Into::into) + } + async fn scheduler_vk_hash(&self, verifier_address: Address) -> Result { // This is here for backward compatibility with the old verifier: // Legacy verifier returns the full verification key; diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs index 0a068033f2bd..2d80d6ebed75 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs @@ -7,6 +7,7 @@ use crate::eth_watch::client::{Error, EthClient}; pub mod governance_upgrades; pub mod priority_ops; +pub mod set_chain_id; pub mod upgrades; #[async_trait::async_trait] diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs new file mode 100644 index 000000000000..b366d274a874 --- /dev/null +++ b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs @@ -0,0 +1,98 @@ +use zksync_dal::StorageProcessor; +use zksync_types::{web3::types::Log, Address, ProtocolUpgrade, H256}; + +use crate::eth_watch::{ + client::{Error, EthClient}, + event_processors::EventProcessor, + metrics::{PollStage, METRICS}, +}; + +/// Responsible for saving new protocol upgrade proposals to the database. +#[derive(Debug)] +pub struct SetChainIDEventProcessor { + diamond_proxy_address: Address, + set_chain_id_signature: H256, +} + +impl SetChainIDEventProcessor { + pub fn new(diamond_proxy_address: Address) -> Self { + Self { + diamond_proxy_address, + set_chain_id_signature: H256::default(), + // TODO: uncomment when we merge the Shared Bridge contracts. + // set_chain_id_signature: state_transition_manager_contract() + // .event("SetChainIdUpgrade") + // .expect("SetChainIdUpgrade event is missing in abi") + // .signature(), + } + } +} + +#[async_trait::async_trait] +impl EventProcessor for SetChainIDEventProcessor { + async fn process_events( + &mut self, + storage: &mut StorageProcessor<'_>, + client: &dyn EthClient, + events: Vec, + ) -> Result<(), Error> { + let mut upgrades = Vec::new(); + let events_iter = events.into_iter(); + + let filtered_events = events_iter.filter(|log| { + log.topics[0] == self.set_chain_id_signature + && log.topics[1] == self.diamond_proxy_address.into() + }); + + // SetChainId does not go throught the governance contract, so we need to parse it separately. + for event in filtered_events { + let timestamp = client + .get_block(event.block_hash.expect("event without block_hash")) + .await? + .expect("event's block not found") + .timestamp; + let upgrade = ProtocolUpgrade::decode_set_chain_id_event(event, timestamp.as_u64()) + .map_err(|err| Error::LogParse(format!("{:?}", err)))?; + + upgrades.push((upgrade, None)); + } + + if upgrades.is_empty() { + return Ok(()); + } + + let ids_str: Vec<_> = upgrades + .iter() + .map(|(u, _)| format!("{}", u.id as u16)) + .collect(); + tracing::debug!("Received set chain upgrade with id: {}", ids_str.join(", ")); + + let stage_latency = METRICS.poll_eth_node[&PollStage::PersistUpgrades].start(); + for (upgrade, scheduler_vk_hash) in upgrades { + let version_id = upgrade.id; + let previous_version = storage + .protocol_versions_dal() + .get_protocol_version(dbg!(version_id)) + .await + .expect("Expected the version to be in the DB"); + let new_version = previous_version.apply_upgrade(upgrade, scheduler_vk_hash); + + if let Some(tx) = new_version.tx.clone() { + storage + .transactions_dal() + .insert_system_transaction(tx.clone()) + .await; + storage + .protocol_versions_dal() + .save_genesis_upgrade_with_tx(version_id, tx) + .await; + } + } + stage_latency.observe(); + Ok(()) + } + + fn relevant_topic(&self) -> H256 { + self.set_chain_id_signature + } +} diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index 5aac8624d474..f6335e8f23a5 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -20,7 +20,8 @@ use self::{ client::{Error, EthClient, EthHttpQueryClient, RETRY_LIMIT}, event_processors::{ governance_upgrades::GovernanceUpgradesEventProcessor, - priority_ops::PriorityOpsEventProcessor, upgrades::UpgradesEventProcessor, EventProcessor, + priority_ops::PriorityOpsEventProcessor, set_chain_id::SetChainIDEventProcessor, + upgrades::UpgradesEventProcessor, EventProcessor, }, metrics::{PollStage, METRICS}, }; @@ -64,9 +65,11 @@ impl EthWatch { let priority_ops_processor = PriorityOpsEventProcessor::new(state.next_expected_priority_id); let upgrades_processor = UpgradesEventProcessor::new(state.last_seen_version_id); + let set_chain_id_processor = SetChainIDEventProcessor::new(diamond_proxy_address); let mut event_processors: Vec> = vec![ Box::new(priority_ops_processor), Box::new(upgrades_processor), + Box::new(set_chain_id_processor), ]; if let Some(governance_contract) = governance_contract { @@ -193,12 +196,14 @@ pub async fn start_eth_watch( pool: ConnectionPool, eth_gateway: Box, diamond_proxy_addr: Address, + state_transition_manager_contract_addr: Address, governance: (Contract, Address), stop_receiver: watch::Receiver, ) -> anyhow::Result>> { let eth_client = EthHttpQueryClient::new( eth_gateway, diamond_proxy_addr, + state_transition_manager_contract_addr, Some(governance.1), config.confirmations_for_eth_event, ); diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index 76b170ba365e..518a6e57fc2a 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -7,7 +7,7 @@ use zksync_types::{ ethabi::{encode, Hash, Token}, l1::{L1Tx, OpProcessingType, PriorityQueueType}, protocol_version::{ProtocolUpgradeTx, ProtocolUpgradeTxCommonData}, - web3::types::{Address, BlockNumber, Log}, + web3::types::{Address, Block, BlockNumber, Log}, Execute, L1TxCommonData, PriorityOpId, ProtocolUpgrade, ProtocolVersion, ProtocolVersionId, Transaction, H256, U256, }; @@ -113,6 +113,10 @@ impl FakeEthClient { #[async_trait::async_trait] impl EthClient for FakeEthClient { + async fn get_block(&self, _hash: H256) -> Result>, Error> { + unimplemented!() + } + async fn get_events( &self, from: BlockNumber, diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 8d7a9d630dc0..c88abaccd846 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -506,6 +506,8 @@ pub async fn initialize_components( } let main_zksync_contract_address = contracts_config.diamond_proxy_addr; + let state_transition_manager_contract = contracts_config.state_transition_proxy_addr; + if components.contains(&Component::EthWatcher) { let started_at = Instant::now(); tracing::info!("initializing ETH-Watcher"); @@ -524,6 +526,7 @@ pub async fn initialize_components( eth_watch_pool, Box::new(query_client.clone()), main_zksync_contract_address, + state_transition_manager_contract, governance, stop_receiver.clone(), ) diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 209809d33f95..0af420ff9f3c 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -7,8 +7,11 @@ use anyhow::Context as _; use multivm::interface::{Halt, L1BatchEnv, SystemEnv}; use tokio::sync::watch; use zksync_types::{ - block::MiniblockExecutionData, l2::TransactionType, protocol_version::ProtocolUpgradeTx, - storage_writes_deduplicator::StorageWritesDeduplicator, Transaction, + block::MiniblockExecutionData, + l2::TransactionType, + protocol_version::{ProtocolUpgradeTx, ProtocolVersionId}, + storage_writes_deduplicator::StorageWritesDeduplicator, + L1BatchNumber, Transaction, }; use super::{ @@ -136,25 +139,50 @@ impl ZkSyncStateKeeper { let previous_batch_protocol_version = self.io.load_previous_batch_version_id().await.unwrap(); + + let first_batch_in_shared_bridge = l1_batch_env.number == L1BatchNumber(1) + && protocol_version > ProtocolVersionId::Vm1_4_1; let version_changed = protocol_version != previous_batch_protocol_version; - let mut protocol_upgrade_tx = if pending_miniblocks.is_empty() && version_changed { - self.io.load_upgrade_tx(protocol_version).await - } else if !pending_miniblocks.is_empty() && version_changed { - // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block - // then it must be the first one in `txs_to_reexecute`. - if self.io.load_upgrade_tx(protocol_version).await.is_some() { - let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; - assert_eq!( - first_tx_to_reexecute.tx_format(), - TransactionType::ProtocolUpgradeTransaction - ) + let mut protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; + + // After the Shared Bridge is integrated, + // there has to be a setChainId upgrade transaction after the chain genesis. + // It has to be the first transaction of the first batch. + // If it's not present, we have to wait for it to be picked up by the event watcher. + // The setChainId upgrade does not bump the protocol version, rather attaches an upgrade + // transaction to the genesis protocol version. + while first_batch_in_shared_bridge && protocol_upgrade_tx.is_none() { + tracing::info!("Waiting for setChainId upgrade transaction to be picked up"); + if self.is_canceled().await { + return Err(Error::Canceled); } + tokio::time::sleep(Duration::from_secs(1)).await; + protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; + } - None - } else { - None - }; + let mut protocol_upgrade_tx = + if pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) { + tracing::info!("We have upgrade tx to be executed in empty miniblock"); + protocol_upgrade_tx + } else if !pending_miniblocks.is_empty() + && (version_changed || first_batch_in_shared_bridge) + { + // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block + // then it must be the first one in `txs_to_reexecute`. + if protocol_upgrade_tx.is_some() { + let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; + assert_eq!( + first_tx_to_reexecute.tx_format(), + TransactionType::ProtocolUpgradeTransaction + ) + } + tracing::info!("We have no upgrade tx to execute"); + None + } else { + tracing::info!("We are not changing protocol version"); + None + }; let mut batch_executor = self .batch_executor_base @@ -213,9 +241,10 @@ impl ZkSyncStateKeeper { .init_batch(l1_batch_env.clone(), system_env.clone()) .await; - let version_changed = system_env.version != sealed_batch_protocol_version; + let version_changed_or_first_batch = + system_env.version != sealed_batch_protocol_version || first_batch_in_shared_bridge; - protocol_upgrade_tx = if version_changed { + protocol_upgrade_tx = if version_changed_or_first_batch { self.io.load_upgrade_tx(system_env.version).await } else { None From e4d988882c8867c6d7803047eb3fc767fc2c3eae Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Wed, 24 Jan 2024 01:55:20 +0200 Subject: [PATCH 02/37] Fixes --- core/lib/zksync_core/src/state_keeper/keeper.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 0af420ff9f3c..65164d34d7ac 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -141,7 +141,7 @@ impl ZkSyncStateKeeper { self.io.load_previous_batch_version_id().await.unwrap(); let first_batch_in_shared_bridge = l1_batch_env.number == L1BatchNumber(1) - && protocol_version > ProtocolVersionId::Vm1_4_1; + && protocol_version > ProtocolVersionId::Version21; let version_changed = protocol_version != previous_batch_protocol_version; let mut protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; @@ -154,7 +154,7 @@ impl ZkSyncStateKeeper { // transaction to the genesis protocol version. while first_batch_in_shared_bridge && protocol_upgrade_tx.is_none() { tracing::info!("Waiting for setChainId upgrade transaction to be picked up"); - if self.is_canceled().await { + if self.is_canceled() { return Err(Error::Canceled); } tokio::time::sleep(Duration::from_secs(1)).await; From 613987e81350b09a74f0d646ee9a6b22702ba1a2 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Wed, 24 Jan 2024 02:17:37 +0200 Subject: [PATCH 03/37] Add dummy configs --- core/lib/env_config/src/contracts.rs | 5 +++++ etc/env/base/contracts.toml | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/core/lib/env_config/src/contracts.rs b/core/lib/env_config/src/contracts.rs index ba4d5f4a7f12..ca0f2d7f2308 100644 --- a/core/lib/env_config/src/contracts.rs +++ b/core/lib/env_config/src/contracts.rs @@ -105,6 +105,11 @@ CONTRACTS_FRI_RECURSION_NODE_LEVEL_VK_HASH="0x5a3ef282b21e12fe1f4438e5bb158fc506 CONTRACTS_FRI_RECURSION_LEAF_LEVEL_VK_HASH="0x72167c43a46cf38875b267d67716edc4563861364a3c03ab7aee73498421e828" CONTRACTS_PROVER_AT_GENESIS="fri" CONTRACTS_SNARK_WRAPPER_VK_HASH="0x4be443afd605a782b6e56d199df2460a025c81b3dea144e135bece83612563f2" +CONTRACTS_BRIDGEHUB_PROXY_ADDR="0x0000000000000000000000000000000000000000" +CONTRACTS_BRIDGEHUB_IMPL_ADDR="0x0000000000000000000000000000000000000000" +CONTRACTS_STATE_TRANSITION_PROXY_ADDR="0x0000000000000000000000000000000000000000" +CONTRACTS_STATE_TRANSITION_IMPL_ADDR="0x0000000000000000000000000000000000000000" +CONTRACTS_TRANSPARENT_PROXY_ADMIN_ADDR="0x0000000000000000000000000000000000000000" "#; lock.set_env(config); diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index bfc9b82aa715..0c8995023e98 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -48,6 +48,13 @@ PROVER_AT_GENESIS="fri" INITIAL_PROTOCOL_VERSION=18 +# These are currently not used, but will be used once the shared bridge is up +BRIDGEHUB_PROXY_ADDR = "0x0000000000000000000000000000000000000000" +BRIDGEHUB_IMPL_ADDR = "0x0000000000000000000000000000000000000000" +STATE_TRANSITION_PROXY_ADDR = "0x0000000000000000000000000000000000000000" +STATE_TRANSITION_IMPL_ADDR = "0x0000000000000000000000000000000000000000" +TRANSPARENT_PROXY_ADMIN_ADDR = "0x0000000000000000000000000000000000000000" + [contracts.test] dummy_verifier=true easy_priority_mode=false From 1d835be83215690f6ab6b48dcc35d2bf2bf04fc2 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Wed, 24 Jan 2024 12:11:58 +0200 Subject: [PATCH 04/37] Fix tests --- core/lib/env_config/src/chain.rs | 2 ++ core/lib/env_config/src/contracts.rs | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index c258c5092e51..b5028e991076 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -125,6 +125,8 @@ mod tests { CHAIN_STATE_KEEPER_SAVE_CALL_TRACES="false" CHAIN_STATE_KEEPER_UPLOAD_WITNESS_INPUTS_TO_GCS="false" CHAIN_STATE_KEEPER_ENUM_INDEX_MIGRATION_CHUNK_SIZE="2000" + CHAIN_STATE_KEEPER_VIRTUAL_BLOCKS_PER_MINIBLOCK="1" + CHAIN_STATE_KEEPER_VIRTUAL_BLOCKS_INTERVAL="1" "#; lock.set_env(config); diff --git a/core/lib/env_config/src/contracts.rs b/core/lib/env_config/src/contracts.rs index ca0f2d7f2308..42cd69c7c335 100644 --- a/core/lib/env_config/src/contracts.rs +++ b/core/lib/env_config/src/contracts.rs @@ -105,11 +105,11 @@ CONTRACTS_FRI_RECURSION_NODE_LEVEL_VK_HASH="0x5a3ef282b21e12fe1f4438e5bb158fc506 CONTRACTS_FRI_RECURSION_LEAF_LEVEL_VK_HASH="0x72167c43a46cf38875b267d67716edc4563861364a3c03ab7aee73498421e828" CONTRACTS_PROVER_AT_GENESIS="fri" CONTRACTS_SNARK_WRAPPER_VK_HASH="0x4be443afd605a782b6e56d199df2460a025c81b3dea144e135bece83612563f2" -CONTRACTS_BRIDGEHUB_PROXY_ADDR="0x0000000000000000000000000000000000000000" -CONTRACTS_BRIDGEHUB_IMPL_ADDR="0x0000000000000000000000000000000000000000" -CONTRACTS_STATE_TRANSITION_PROXY_ADDR="0x0000000000000000000000000000000000000000" -CONTRACTS_STATE_TRANSITION_IMPL_ADDR="0x0000000000000000000000000000000000000000" -CONTRACTS_TRANSPARENT_PROXY_ADMIN_ADDR="0x0000000000000000000000000000000000000000" +CONTRACTS_BRIDGEHUB_PROXY_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" +CONTRACTS_BRIDGEHUB_IMPL_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" +CONTRACTS_STATE_TRANSITION_PROXY_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" +CONTRACTS_STATE_TRANSITION_IMPL_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" +CONTRACTS_TRANSPARENT_PROXY_ADMIN_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" "#; lock.set_env(config); From bd49a6b317b5ec1a9b6a396f52ef764dafa2f109 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Wed, 24 Jan 2024 13:01:52 +0200 Subject: [PATCH 05/37] Spelling --- checks-config/era.dic | 4 ++++ core/lib/types/src/protocol_version.rs | 14 +++++++------- .../src/eth_watch/event_processors/set_chain_id.rs | 6 +++--- core/lib/zksync_core/src/state_keeper/keeper.rs | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/checks-config/era.dic b/checks-config/era.dic index 15f14a6e5f8c..f9cb21045f87 100644 --- a/checks-config/era.dic +++ b/checks-config/era.dic @@ -410,6 +410,10 @@ prode StorageBatchInfo CommitBatchInfo IExecutor +SetChainId +setChainId +SetChainIdUpgrade +state_transition_manager_contract // Names Vyper diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 0339f0b5a215..82deeb71b488 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -370,13 +370,13 @@ impl ProtocolUpgrade { timestamp: u64, ) -> Result>::Error> { let transaction_param_type = ParamType::Tuple(vec![ - ParamType::Uint(256), // txType + ParamType::Uint(256), // tx type ParamType::Uint(256), // sender ParamType::Uint(256), // to - ParamType::Uint(256), // gasLimit - ParamType::Uint(256), // gasPerPubdataLimit - ParamType::Uint(256), // maxFeePerGas - ParamType::Uint(256), // maxPriorityFeePerGas + ParamType::Uint(256), // gas limit + ParamType::Uint(256), // gas per pubdata limit + ParamType::Uint(256), // max fee per gas + ParamType::Uint(256), // max priority fee per gas ParamType::Uint(256), // paymaster ParamType::Uint(256), // nonce (serial ID) ParamType::Uint(256), // value @@ -385,7 +385,7 @@ impl ProtocolUpgrade { ParamType::Bytes, // signature ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps ParamType::Bytes, // paymaster input - ParamType::Bytes, // reservedDynamic + ParamType::Bytes, // reserved dynamic ]); let Token::Tuple(transaction) = decode(&[transaction_param_type], &event.data.0)?.remove(0) @@ -485,7 +485,7 @@ impl ProtocolUpgradeTx { let paymaster_input = transaction.remove(0).into_bytes().unwrap(); assert_eq!(paymaster_input.len(), 0); - // TODO (SMA-1621): check that reservedDynamic are constructed correctly. + // TODO (SMA-1621): check that `reservedDynamic` are constructed correctly. let reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); assert_eq!(reserved_dynamic.len(), 0); diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs index b366d274a874..b6eac098b1f0 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs @@ -20,9 +20,9 @@ impl SetChainIDEventProcessor { diamond_proxy_address, set_chain_id_signature: H256::default(), // TODO: uncomment when we merge the Shared Bridge contracts. - // set_chain_id_signature: state_transition_manager_contract() + // state_transition_manager_contract() // .event("SetChainIdUpgrade") - // .expect("SetChainIdUpgrade event is missing in abi") + // .expect("SetChainIdUpgrade event is missing in ABI") // .signature(), } } @@ -44,7 +44,7 @@ impl EventProcessor for SetChainIDEventProcessor { && log.topics[1] == self.diamond_proxy_address.into() }); - // SetChainId does not go throught the governance contract, so we need to parse it separately. + // SetChainId does not go through the governance contract, so we need to parse it separately. for event in filtered_events { let timestamp = client .get_block(event.block_hash.expect("event without block_hash")) diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 65164d34d7ac..08887cbe1679 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -141,7 +141,7 @@ impl ZkSyncStateKeeper { self.io.load_previous_batch_version_id().await.unwrap(); let first_batch_in_shared_bridge = l1_batch_env.number == L1BatchNumber(1) - && protocol_version > ProtocolVersionId::Version21; + && protocol_version >= ProtocolVersionId::Version21; let version_changed = protocol_version != previous_batch_protocol_version; let mut protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; From bb7c070e220846f94a1698577a30f463a96a35af Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Wed, 24 Jan 2024 19:49:19 +0200 Subject: [PATCH 06/37] Integrate new validator timelock --- core/lib/types/src/protocol_version.rs | 4 + .../src/eth_sender/eth_tx_aggregator.rs | 120 +++++++++--------- core/lib/zksync_core/src/eth_sender/tests.rs | 1 + .../src/eth_sender/zksync_functions.rs | 52 ++++---- core/lib/zksync_core/src/lib.rs | 5 + 5 files changed, 94 insertions(+), 88 deletions(-) diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 82deeb71b488..1ce786b1c658 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -93,6 +93,10 @@ impl ProtocolVersionId { self <= &Self::Version17 } + pub fn is_pre_shared_bridge(&self) -> bool { + self <= &Self::Version20 + } + pub fn is_1_4_0(&self) -> bool { self >= &ProtocolVersionId::Version18 && self < &ProtocolVersionId::Version20 } diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs index 588c1f368b6f..8e07cb6d919f 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs @@ -9,14 +9,13 @@ use zksync_types::{ aggregated_operations::AggregatedOperation, contracts::{Multicall3Call, Multicall3Result}, eth_sender::EthTx, - ethabi::{Contract, Token}, + ethabi::Token, protocol_version::{L1VerifierConfig, VerifierParams}, - vk_transform::l1_vk_commitment, web3::contract::{ tokens::{Detokenize, Tokenizable}, Error, }, - Address, ProtocolVersionId, H256, U256, + Address, L2ChainId, ProtocolVersionId, H256, U256, }; use crate::{ @@ -51,6 +50,7 @@ pub struct EthTxAggregator { pub(super) main_zksync_contract_address: Address, functions: ZkSyncFunctions, base_nonce: u64, + rollup_chain_id: L2ChainId, } impl EthTxAggregator { @@ -62,6 +62,7 @@ impl EthTxAggregator { l1_multicall3_address: Address, main_zksync_contract_address: Address, base_nonce: u64, + rollup_chain_id: L2ChainId, ) -> Self { let functions = ZkSyncFunctions::default(); Self { @@ -73,6 +74,7 @@ impl EthTxAggregator { main_zksync_contract_address, functions, base_nonce, + rollup_chain_id, } } @@ -291,32 +293,12 @@ impl EthTxAggregator { async fn get_recursion_scheduler_level_vk_hash( &mut self, verifier_address: Address, - contracts_are_pre_boojum: bool, ) -> Result { - // This is here for backward compatibility with the old verifier: - // Pre-boojum verifier returns the full verification key; - // New verifier returns the hash of the verification key - if contracts_are_pre_boojum { - let abi = Contract { - functions: [( - self.functions.get_verification_key.name.clone(), - vec![self.functions.get_verification_key.clone()], - )] - .into(), - ..Default::default() - }; - let args = CallFunctionArgs::new(&self.functions.get_verification_key.name, ()) - .for_contract(verifier_address, abi); - - let vk = self.eth_client.call_contract_function(args).await?; - Ok(l1_vk_commitment(Token::from_tokens(vk)?)) - } else { - let get_vk_hash = self.functions.verification_key_hash.as_ref(); - let args = CallFunctionArgs::new(&get_vk_hash.unwrap().name, ()) - .for_contract(verifier_address, self.functions.verifier_contract.clone()); - let vk_hash = self.eth_client.call_contract_function(args).await?; - Ok(H256::from_tokens(vk_hash)?) - } + let get_vk_hash = &self.functions.verification_key_hash; + let args = CallFunctionArgs::new(&get_vk_hash.name, ()) + .for_contract(verifier_address, self.functions.verifier_contract.clone()); + let vk_hash = self.eth_client.call_contract_function(args).await?; + Ok(H256::from_tokens(vk_hash)?) } #[tracing::instrument(skip(self, storage))] @@ -333,10 +315,10 @@ impl EthTxAggregator { tracing::error!("Failed to get multicall data {err:?}"); err })?; - let contracts_are_pre_boojum = protocol_version_id.is_pre_boojum(); + let contracts_are_pre_shared_bridge = protocol_version_id.is_pre_shared_bridge(); let recursion_scheduler_level_vk_hash = self - .get_recursion_scheduler_level_vk_hash(verifier_address, contracts_are_pre_boojum) + .get_recursion_scheduler_level_vk_hash(verifier_address) .await .map_err(|err| { tracing::error!("Failed to get VK hash from the Verifier {err:?}"); @@ -357,7 +339,7 @@ impl EthTxAggregator { .await { let tx = self - .save_eth_tx(storage, &agg_op, contracts_are_pre_boojum) + .save_eth_tx(storage, &agg_op, contracts_are_pre_shared_bridge) .await?; Self::report_eth_tx_saving(storage, agg_op, &tx).await; } @@ -398,47 +380,65 @@ impl EthTxAggregator { fn encode_aggregated_op( &self, op: &AggregatedOperation, - contracts_are_pre_boojum: bool, + contracts_are_pre_shared_bridge: bool, ) -> Vec { - let operation_is_pre_boojum = op.protocol_version().is_pre_boojum(); + let operation_is_pre_shared_bridge = op.protocol_version().is_pre_shared_bridge(); + assert_eq!( + contracts_are_pre_shared_bridge, + operation_is_pre_shared_bridge + ); + + let mut args = vec![Token::Uint(self.rollup_chain_id.as_u64().into())]; - // For "commit" and "prove" operations it's necessary that the contracts are of the same version as L1 batches are. - // For "execute" it's not required, i.e. we can "execute" pre-boojum batches with post-boojum contracts. match &op { AggregatedOperation::Commit(op) => { - assert_eq!(contracts_are_pre_boojum, operation_is_pre_boojum); - let f = if contracts_are_pre_boojum { - &self.functions.pre_boojum_commit - } else { + let op_args = op.get_eth_tx_args(); + if contracts_are_pre_shared_bridge { self.functions - .post_boojum_commit + .pre_shared_bridge_commit + .encode_input(&op_args) + } else { + let func = self + .functions + .post_shared_bridge_commit .as_ref() - .expect("Missing ABI for commitBatches") - }; - f.encode_input(&op.get_eth_tx_args()) + .expect("Missing ABI for commitBatchesSharedBridge"); + args.extend(op_args); + func.encode_input(&args) + } } AggregatedOperation::PublishProofOnchain(op) => { - assert_eq!(contracts_are_pre_boojum, operation_is_pre_boojum); - let f = if contracts_are_pre_boojum { - &self.functions.pre_boojum_prove - } else { + let op_args = op.get_eth_tx_args(); + if contracts_are_pre_shared_bridge { self.functions - .post_boojum_prove + .pre_shared_bridge_prove + .encode_input(&op_args) + } else { + let func = self + .functions + .post_shared_bridge_prove .as_ref() - .expect("Missing ABI for proveBatches") - }; - f.encode_input(&op.get_eth_tx_args()) + .expect("Missing ABI for proveBatchesSharedBridge"); + args.extend(op_args); + func.encode_input(&args) + } } AggregatedOperation::Execute(op) => { - let f = if contracts_are_pre_boojum { - &self.functions.pre_boojum_execute - } else { + let op_args = op.get_eth_tx_args(); + if contracts_are_pre_shared_bridge { self.functions - .post_boojum_execute + .pre_shared_bridge_execute + .encode_input(&op_args) + } else { + let func = self + .functions + .post_shared_bridge_execute .as_ref() - .expect("Missing ABI for executeBatches") - }; - f.encode_input(&op.get_eth_tx_args()) + .expect("Missing ABI for executeBatchesSharedBridge"); + + args.extend(op_args); + func.encode_input(&args) + } } } .expect("Failed to encode transaction data") @@ -448,11 +448,11 @@ impl EthTxAggregator { &self, storage: &mut StorageProcessor<'_>, aggregated_op: &AggregatedOperation, - contracts_are_pre_boojum: bool, + contracts_are_pre_shared_bridge: bool, ) -> Result { let mut transaction = storage.start_transaction().await.unwrap(); let nonce = self.get_next_nonce(&mut transaction).await?; - let calldata = self.encode_aggregated_op(aggregated_op, contracts_are_pre_boojum); + let calldata = self.encode_aggregated_op(aggregated_op, contracts_are_pre_shared_bridge); let l1_batch_number_range = aggregated_op.l1_batch_range(); let op_type = aggregated_op.get_action_type(); diff --git a/core/lib/zksync_core/src/eth_sender/tests.rs b/core/lib/zksync_core/src/eth_sender/tests.rs index 73f484a1fd77..d64acfafb0e3 100644 --- a/core/lib/zksync_core/src/eth_sender/tests.rs +++ b/core/lib/zksync_core/src/eth_sender/tests.rs @@ -111,6 +111,7 @@ impl EthSenderTester { contracts_config.l1_multicall3_addr, Address::random(), 0, + 270.into(), ); let manager = EthTxManager::new( diff --git a/core/lib/zksync_core/src/eth_sender/zksync_functions.rs b/core/lib/zksync_core/src/eth_sender/zksync_functions.rs index 8e27af5b628d..00ca15707638 100644 --- a/core/lib/zksync_core/src/eth_sender/zksync_functions.rs +++ b/core/lib/zksync_core/src/eth_sender/zksync_functions.rs @@ -1,17 +1,14 @@ -use zksync_contracts::{ - multicall_contract, verifier_contract, zksync_contract, PRE_BOOJUM_COMMIT_FUNCTION, - PRE_BOOJUM_EXECUTE_FUNCTION, PRE_BOOJUM_GET_VK_FUNCTION, PRE_BOOJUM_PROVE_FUNCTION, -}; +use zksync_contracts::{multicall_contract, verifier_contract, zksync_contract}; use zksync_types::ethabi::{Contract, Function}; #[derive(Debug)] pub(super) struct ZkSyncFunctions { - pub(super) pre_boojum_commit: Function, - pub(super) post_boojum_commit: Option, - pub(super) pre_boojum_prove: Function, - pub(super) post_boojum_prove: Option, - pub(super) pre_boojum_execute: Function, - pub(super) post_boojum_execute: Option, + pub(super) pre_shared_bridge_commit: Function, + pub(super) post_shared_bridge_commit: Option, + pub(super) pre_shared_bridge_prove: Function, + pub(super) post_shared_bridge_prove: Option, + pub(super) pre_shared_bridge_execute: Function, + pub(super) post_shared_bridge_execute: Option, pub(super) get_l2_bootloader_bytecode_hash: Function, pub(super) get_l2_default_account_bytecode_hash: Function, pub(super) get_verifier: Function, @@ -19,8 +16,7 @@ pub(super) struct ZkSyncFunctions { pub(super) get_protocol_version: Function, pub(super) verifier_contract: Contract, - pub(super) get_verification_key: Function, - pub(super) verification_key_hash: Option, + pub(super) verification_key_hash: Function, pub(super) multicall_contract: Contract, pub(super) aggregate3: Function, @@ -50,12 +46,15 @@ impl Default for ZkSyncFunctions { let verifier_contract = verifier_contract(); let multicall_contract = multicall_contract(); - let pre_boojum_commit = PRE_BOOJUM_COMMIT_FUNCTION.clone(); - let post_boojum_commit = get_optional_function(&zksync_contract, "commitBatches"); - let pre_boojum_prove = PRE_BOOJUM_PROVE_FUNCTION.clone(); - let post_boojum_prove = get_optional_function(&zksync_contract, "proveBatches"); - let pre_boojum_execute = PRE_BOOJUM_EXECUTE_FUNCTION.clone(); - let post_boojum_execute = get_optional_function(&zksync_contract, "executeBatches"); + let pre_shared_bridge_commit = get_function(&zksync_contract, "commitBatches"); + let post_shared_bridge_commit = + get_optional_function(&zksync_contract, "commitBatchesSharedBridge"); + let pre_shared_bridge_prove = get_function(&zksync_contract, "proveBatches"); + let post_shared_bridge_prove = + get_optional_function(&zksync_contract, "proveBatchesSharedBridge"); + let pre_shared_bridge_execute = get_function(&zksync_contract, "executeBatches"); + let post_shared_bridge_execute = + get_optional_function(&zksync_contract, "executeBatchesSharedBridge"); let get_l2_bootloader_bytecode_hash = get_function(&zksync_contract, "getL2BootloaderBytecodeHash"); let get_l2_default_account_bytecode_hash = @@ -63,25 +62,22 @@ impl Default for ZkSyncFunctions { let get_verifier = get_function(&zksync_contract, "getVerifier"); let get_verifier_params = get_function(&zksync_contract, "getVerifierParams"); let get_protocol_version = get_function(&zksync_contract, "getProtocolVersion"); - let get_verification_key = PRE_BOOJUM_GET_VK_FUNCTION.clone(); let aggregate3 = get_function(&multicall_contract, "aggregate3"); - let verification_key_hash = - get_optional_function(&verifier_contract, "verificationKeyHash"); + let verification_key_hash = get_function(&verifier_contract, "verificationKeyHash"); ZkSyncFunctions { - pre_boojum_commit, - post_boojum_commit, - pre_boojum_prove, - post_boojum_prove, - pre_boojum_execute, - post_boojum_execute, + pre_shared_bridge_commit, + post_shared_bridge_commit, + pre_shared_bridge_prove, + post_shared_bridge_prove, + pre_shared_bridge_execute, + post_shared_bridge_execute, get_l2_bootloader_bytecode_hash, get_l2_default_account_bytecode_hash, get_verifier, get_verifier_params, get_protocol_version, verifier_contract, - get_verification_key, verification_key_hash, multicall_contract, aggregate3, diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index c88abaccd846..92b64bd51ff8 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -564,6 +564,11 @@ pub async fn initialize_components( contracts_config.l1_multicall3_addr, main_zksync_contract_address, nonce.as_u64(), + configs + .network_config + .as_ref() + .context("netowrk_config")? + .zksync_network_id, ); task_futures.push(tokio::spawn( eth_tx_aggregator_actor.run(eth_sender_pool, stop_receiver.clone()), From 78467e0e3bf50c294bbb77168268b5798032324c Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 25 Jan 2024 14:38:17 +0200 Subject: [PATCH 07/37] Apply some review suggestions --- core/lib/config/src/configs/contracts.rs | 20 ++-- core/lib/dal/src/protocol_versions_dal.rs | 4 +- core/lib/env_config/src/contracts.rs | 20 ++-- core/lib/types/src/protocol_version.rs | 100 ++++++++---------- core/lib/web3_decl/src/namespaces/zks.rs | 2 +- .../web3/backend_jsonrpsee/namespaces/zks.rs | 2 +- .../src/api_server/web3/namespaces/zks.rs | 2 +- .../zksync_core/src/api_server/web3/state.rs | 2 +- core/lib/zksync_core/src/eth_watch/client.rs | 19 ++-- .../event_processors/set_chain_id.rs | 63 ++++------- core/lib/zksync_core/src/eth_watch/mod.rs | 2 +- core/lib/zksync_core/src/eth_watch/tests.rs | 6 +- .../zksync_core/src/state_keeper/keeper.rs | 4 +- 13 files changed, 104 insertions(+), 142 deletions(-) diff --git a/core/lib/config/src/configs/contracts.rs b/core/lib/config/src/configs/contracts.rs index 26fad9ff70b6..aaa16fe86a83 100644 --- a/core/lib/config/src/configs/contracts.rs +++ b/core/lib/config/src/configs/contracts.rs @@ -15,11 +15,11 @@ pub struct ContractsConfig { pub governance_addr: Address, pub mailbox_facet_addr: Address, - pub bridgehub_proxy_addr: Address, - pub bridgehub_impl_addr: Address, - pub state_transition_proxy_addr: Address, - pub state_transition_impl_addr: Address, - pub transparent_proxy_admin_addr: Address, + pub bridgehub_proxy_addr: Option
, + pub bridgehub_impl_addr: Option
, + pub state_transition_proxy_addr: Option
, + pub state_transition_impl_addr: Option
, + pub transparent_proxy_admin_addr: Option
, pub executor_facet_addr: Address, pub admin_facet_addr: Address, @@ -56,19 +56,15 @@ impl ContractsConfig { /// Same goes for hashes. pub fn for_tests() -> Self { Self { - bridgehub_proxy_addr: Address::repeat_byte(0x01), - bridgehub_impl_addr: Address::repeat_byte(0x01), - state_transition_proxy_addr: Address::repeat_byte(0x01), - state_transition_impl_addr: Address::repeat_byte(0x01), mailbox_facet_addr: Address::repeat_byte(0x01), executor_facet_addr: Address::repeat_byte(0x02), admin_facet_addr: Address::repeat_byte(0x03), + transparent_proxy_admin_addr: Some(Address::repeat_byte(0x04)), getters_facet_addr: Address::repeat_byte(0x05), verifier_addr: Address::repeat_byte(0x06), diamond_init_addr: Address::repeat_byte(0x07), diamond_upgrade_init_addr: Address::repeat_byte(0x08), diamond_proxy_addr: Address::repeat_byte(0x09), - transparent_proxy_admin_addr: Address::repeat_byte(0x09), validator_timelock_addr: Address::repeat_byte(0x0a), genesis_tx_hash: H256::repeat_byte(0x01), l1_erc20_bridge_proxy_addr: Address::repeat_byte(0x0b), @@ -89,6 +85,10 @@ impl ContractsConfig { governance_addr: Address::repeat_byte(0x13), prover_at_genesis: ProverAtGenesis::Fri, snark_wrapper_vk_hash: H256::repeat_byte(0x09), + bridgehub_proxy_addr: Some(Address::repeat_byte(0x14)), + bridgehub_impl_addr: Some(Address::repeat_byte(0x15)), + state_transition_proxy_addr: Some(Address::repeat_byte(0x16)), + state_transition_impl_addr: Some(Address::repeat_byte(0x17)), } } } diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 400a973c66a4..7f7e194ace28 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -98,7 +98,7 @@ impl ProtocolVersionsDal<'_, '_> { db_transaction.commit().await.unwrap(); } - pub async fn save_genesis_upgrade(&mut self, id: ProtocolVersionId, tx_hash: Option) { + async fn save_genesis_upgrade(&mut self, id: ProtocolVersionId, tx_hash: Option) { sqlx::query!( r#" UPDATE protocol_versions @@ -115,6 +115,8 @@ impl ProtocolVersionsDal<'_, '_> { .unwrap(); } + /// Attaches a transaction used to set chainId to the genesis protocol version. + /// Also inserts that transaction into the database. pub async fn save_genesis_upgrade_with_tx( &mut self, id: ProtocolVersionId, diff --git a/core/lib/env_config/src/contracts.rs b/core/lib/env_config/src/contracts.rs index 42cd69c7c335..456002ca11be 100644 --- a/core/lib/env_config/src/contracts.rs +++ b/core/lib/env_config/src/contracts.rs @@ -19,10 +19,10 @@ mod tests { fn expected_config() -> ContractsConfig { ContractsConfig { - bridgehub_proxy_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), - bridgehub_impl_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), - state_transition_proxy_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), - state_transition_impl_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), + bridgehub_proxy_addr: addr("35ea7f92f4c5f433efe15284e99c040110cf6297"), + bridgehub_impl_addr: addr("87d456da9ed212eb49d80d96afb44afddf36adf8"), + state_transition_proxy_addr: addr("d90f1c081c6117241624e97cb6147257c3cb2097"), + state_transition_impl_addr: addr("c957c0e82d3bafb5ad46ffbcc66900648784eb05"), governance_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), mailbox_facet_addr: addr("0f6Fa881EF414Fc6E818180657c2d5CD7Ac6cCAd"), executor_facet_addr: addr("18B631537801963A964211C0E86645c1aBfbB2d3"), @@ -32,7 +32,7 @@ mod tests { diamond_init_addr: addr("FFC35A5e767BE36057c34586303498e3de7C62Ba"), diamond_upgrade_init_addr: addr("FFC35A5e767BE36057c34586303498e3de7C62Ba"), diamond_proxy_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"), - transparent_proxy_admin_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), + transparent_proxy_admin_addr: addr("dd6fa5c14e7550b4caf2aa2818d24c69cbc347e5"), validator_timelock_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"), genesis_tx_hash: hash( "b99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e", @@ -105,11 +105,11 @@ CONTRACTS_FRI_RECURSION_NODE_LEVEL_VK_HASH="0x5a3ef282b21e12fe1f4438e5bb158fc506 CONTRACTS_FRI_RECURSION_LEAF_LEVEL_VK_HASH="0x72167c43a46cf38875b267d67716edc4563861364a3c03ab7aee73498421e828" CONTRACTS_PROVER_AT_GENESIS="fri" CONTRACTS_SNARK_WRAPPER_VK_HASH="0x4be443afd605a782b6e56d199df2460a025c81b3dea144e135bece83612563f2" -CONTRACTS_BRIDGEHUB_PROXY_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" -CONTRACTS_BRIDGEHUB_IMPL_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" -CONTRACTS_STATE_TRANSITION_PROXY_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" -CONTRACTS_STATE_TRANSITION_IMPL_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" -CONTRACTS_TRANSPARENT_PROXY_ADMIN_ADDR="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" +CONTRACTS_BRIDGEHUB_PROXY_ADDR="0x35ea7f92f4c5f433efe15284e99c040110cf6297" +CONTRACTS_BRIDGEHUB_IMPL_ADDR="0x87d456da9ed212eb49d80d96afb44afddf36adf8" +CONTRACTS_STATE_TRANSITION_PROXY_ADDR="0xd90f1c081c6117241624e97cb6147257c3cb2097" +CONTRACTS_STATE_TRANSITION_IMPL_ADDR="0xc957c0e82d3bafb5ad46ffbcc66900648784eb05" +CONTRACTS_TRANSPARENT_PROXY_ADMIN_ADDR="0xdd6fa5c14e7550b4caf2aa2818d24c69cbc347e5" "#; lock.set_env(config); diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 1ce786b1c658..3cb9edca627e 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -368,61 +368,51 @@ impl TryFrom for ProtocolUpgrade { } } -impl ProtocolUpgrade { - pub fn decode_set_chain_id_event( - event: Log, - timestamp: u64, - ) -> Result>::Error> { - let transaction_param_type = ParamType::Tuple(vec![ - ParamType::Uint(256), // tx type - ParamType::Uint(256), // sender - ParamType::Uint(256), // to - ParamType::Uint(256), // gas limit - ParamType::Uint(256), // gas per pubdata limit - ParamType::Uint(256), // max fee per gas - ParamType::Uint(256), // max priority fee per gas - ParamType::Uint(256), // paymaster - ParamType::Uint(256), // nonce (serial ID) - ParamType::Uint(256), // value - ParamType::FixedArray(Box::new(ParamType::Uint(256)), 4), // reserved - ParamType::Bytes, // calldata - ParamType::Bytes, // signature - ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps - ParamType::Bytes, // paymaster input - ParamType::Bytes, // reserved dynamic - ]); - - let Token::Tuple(transaction) = decode(&[transaction_param_type], &event.data.0)?.remove(0) - else { - unreachable!() - }; - - let version_id = event.topics[2].to_low_u64_be(); - - let eth_hash = event - .transaction_hash - .expect("Event transaction hash is missing"); - let eth_block = event - .block_number - .expect("Event block number is missing") - .as_u64(); - - let factory_deps: Vec = Vec::new(); - - let upgrade_tx = - ProtocolUpgradeTx::decode_tx(transaction, eth_hash, eth_block, factory_deps); - - let upgrade = ProtocolUpgrade { - id: ProtocolVersionId::try_from(version_id as u16).expect("Version is not supported"), - bootloader_code_hash: None, - default_account_code_hash: None, - verifier_params: None, - verifier_address: None, - timestamp, - tx: upgrade_tx, - }; - Ok(upgrade) - } +pub fn decode_set_chain_id_event( + event: Log, +) -> Result<(ProtocolVersionId, ProtocolUpgradeTx), crate::ethabi::Error> { + let transaction_param_type = ParamType::Tuple(vec![ + ParamType::Uint(256), // tx type + ParamType::Uint(256), // sender + ParamType::Uint(256), // to + ParamType::Uint(256), // gas limit + ParamType::Uint(256), // gas per pubdata limit + ParamType::Uint(256), // max fee per gas + ParamType::Uint(256), // max priority fee per gas + ParamType::Uint(256), // paymaster + ParamType::Uint(256), // nonce (serial ID) + ParamType::Uint(256), // value + ParamType::FixedArray(Box::new(ParamType::Uint(256)), 4), // reserved + ParamType::Bytes, // calldata + ParamType::Bytes, // signature + ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps + ParamType::Bytes, // paymaster input + ParamType::Bytes, // reserved dynamic + ]); + + let Token::Tuple(transaction) = decode(&[transaction_param_type], &event.data.0)?.remove(0) + else { + unreachable!() + }; + + let version_id = event.topics[2].to_low_u64_be(); + + let eth_hash = event + .transaction_hash + .expect("Event transaction hash is missing"); + let eth_block = event + .block_number + .expect("Event block number is missing") + .as_u64(); + + let factory_deps: Vec = Vec::new(); + + let upgrade_tx = ProtocolUpgradeTx::decode_tx(transaction, eth_hash, eth_block, factory_deps) + .expect("Upgrade tx is missing"); + let version_id = + ProtocolVersionId::try_from(version_id as u16).expect("Version is not supported"); + + Ok((version_id, upgrade_tx)) } impl ProtocolUpgradeTx { diff --git a/core/lib/web3_decl/src/namespaces/zks.rs b/core/lib/web3_decl/src/namespaces/zks.rs index 0c808c043f18..d589210b90a3 100644 --- a/core/lib/web3_decl/src/namespaces/zks.rs +++ b/core/lib/web3_decl/src/namespaces/zks.rs @@ -35,7 +35,7 @@ pub trait ZksNamespace { async fn estimate_gas_l1_to_l2(&self, req: CallRequest) -> RpcResult; #[method(name = "getBridgehubContract")] - async fn get_bridgehub_contract(&self) -> RpcResult
; + async fn get_bridgehub_contract(&self) -> RpcResult>; #[method(name = "getMainContract")] async fn get_main_contract(&self) -> RpcResult
; diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs index 7a9fc8e46ccb..2a8bda7b9d6f 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs @@ -31,7 +31,7 @@ impl ZksNamespaceServer for ZksNamespace { .map_err(into_jsrpc_error) } - async fn get_bridgehub_contract(&self) -> RpcResult
{ + async fn get_bridgehub_contract(&self) -> RpcResult> { Ok(self.get_bridgehub_contract_impl()) } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs index ce610f8da98d..2bf9717caa98 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs @@ -124,7 +124,7 @@ impl ZksNamespace { } #[tracing::instrument(skip(self))] - pub fn get_bridgehub_contract_impl(&self) -> Address { + pub fn get_bridgehub_contract_impl(&self) -> Option
{ self.state.api_config.bridgehub_proxy_addr } diff --git a/core/lib/zksync_core/src/api_server/web3/state.rs b/core/lib/zksync_core/src/api_server/web3/state.rs index 0964f21c48bf..55974391bed4 100644 --- a/core/lib/zksync_core/src/api_server/web3/state.rs +++ b/core/lib/zksync_core/src/api_server/web3/state.rs @@ -81,7 +81,7 @@ pub struct InternalApiConfig { pub estimate_gas_scale_factor: f64, pub estimate_gas_acceptable_overestimation: u32, pub bridge_addresses: api::BridgeAddresses, - pub bridgehub_proxy_addr: Address, + pub bridgehub_proxy_addr: Option
, pub diamond_proxy_addr: Address, pub l2_testnet_paymaster_addr: Option
, pub req_entities_limit: usize, diff --git a/core/lib/zksync_core/src/eth_watch/client.rs b/core/lib/zksync_core/src/eth_watch/client.rs index 5c9866518b9b..5e6e81717c1a 100644 --- a/core/lib/zksync_core/src/eth_watch/client.rs +++ b/core/lib/zksync_core/src/eth_watch/client.rs @@ -8,7 +8,7 @@ use zksync_types::{ web3::{ self, contract::tokens::Detokenize, - types::{Block, BlockId, BlockNumber, FilterBuilder, Log}, + types::{BlockId, BlockNumber, FilterBuilder, Log}, }, Address, H256, }; @@ -44,8 +44,6 @@ pub trait EthClient: 'static + fmt::Debug + Send + Sync { async fn finalized_block_number(&self) -> Result; /// Returns scheduler verification key hash by verifier address. async fn scheduler_vk_hash(&self, verifier_address: Address) -> Result; - /// Gets block info by block hash. - async fn get_block(&self, block_hash: H256) -> Result>, Error>; /// Sets list of topics to return events for. fn set_topics(&mut self, topics: Vec); } @@ -59,7 +57,9 @@ pub struct EthHttpQueryClient { client: Box, topics: Vec, zksync_contract_addr: Address, - state_transition_manager_contract_addr: Address, + /// Address of the `StateTransitionManager` contract. It's optional because it is present only + /// for post shared brige chains. If address is some then client will listen to `SetChainId` events coming from it. + state_transition_manager_contract_addr: Option
, /// Address of the `Governance` contract. It's optional because it is present only for post-boojum chains. /// If address is some then client will listen to events coming from it. governance_address: Option
, @@ -71,7 +71,7 @@ impl EthHttpQueryClient { pub fn new( client: Box, zksync_contract_addr: Address, - state_transition_manager_contract_addr: Address, + state_transition_manager_contract_addr: Option
, governance_address: Option
, confirmations_for_eth_event: Option, ) -> Self { @@ -101,7 +101,7 @@ impl EthHttpQueryClient { .address( [ Some(self.zksync_contract_addr), - Some(self.state_transition_manager_contract_addr), + self.state_transition_manager_contract_addr, self.governance_address, ] .iter() @@ -120,13 +120,6 @@ impl EthHttpQueryClient { #[async_trait::async_trait] impl EthClient for EthHttpQueryClient { - async fn get_block(&self, block_hash: H256) -> Result>, Error> { - self.client - .block(BlockId::Hash(block_hash), "watch") - .await - .map_err(Into::into) - } - async fn scheduler_vk_hash(&self, verifier_address: Address) -> Result { // This is here for backward compatibility with the old verifier: // Legacy verifier returns the full verification key; diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs index b6eac098b1f0..9706b55e94ce 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs @@ -1,5 +1,5 @@ use zksync_dal::StorageProcessor; -use zksync_types::{web3::types::Log, Address, ProtocolUpgrade, H256}; +use zksync_types::{protocol_version::decode_set_chain_id_event, web3::types::Log, Address, H256}; use crate::eth_watch::{ client::{Error, EthClient}, @@ -33,29 +33,21 @@ impl EventProcessor for SetChainIDEventProcessor { async fn process_events( &mut self, storage: &mut StorageProcessor<'_>, - client: &dyn EthClient, + _client: &dyn EthClient, events: Vec, ) -> Result<(), Error> { - let mut upgrades = Vec::new(); - let events_iter = events.into_iter(); - - let filtered_events = events_iter.filter(|log| { - log.topics[0] == self.set_chain_id_signature - && log.topics[1] == self.diamond_proxy_address.into() - }); - // SetChainId does not go through the governance contract, so we need to parse it separately. - for event in filtered_events { - let timestamp = client - .get_block(event.block_hash.expect("event without block_hash")) - .await? - .expect("event's block not found") - .timestamp; - let upgrade = ProtocolUpgrade::decode_set_chain_id_event(event, timestamp.as_u64()) - .map_err(|err| Error::LogParse(format!("{:?}", err)))?; - - upgrades.push((upgrade, None)); - } + let upgrades = events + .into_iter() + .filter(|log| { + log.topics[0] == self.set_chain_id_signature + && log.topics[1] == self.diamond_proxy_address.into() + }) + .map(|event| { + decode_set_chain_id_event(event) + .map_err(|err| Error::LogParse(format!("{:?}", err))) + }) + .collect::, _>>()?; if upgrades.is_empty() { return Ok(()); @@ -63,30 +55,19 @@ impl EventProcessor for SetChainIDEventProcessor { let ids_str: Vec<_> = upgrades .iter() - .map(|(u, _)| format!("{}", u.id as u16)) + .map(|(id, _tx)| format!("{}", *id as u16)) .collect(); - tracing::debug!("Received set chain upgrade with id: {}", ids_str.join(", ")); + tracing::debug!( + "Received setChainId upgrade with version_id: {}", + ids_str.join(", ") + ); let stage_latency = METRICS.poll_eth_node[&PollStage::PersistUpgrades].start(); - for (upgrade, scheduler_vk_hash) in upgrades { - let version_id = upgrade.id; - let previous_version = storage + for (version_id, tx) in upgrades { + storage .protocol_versions_dal() - .get_protocol_version(dbg!(version_id)) - .await - .expect("Expected the version to be in the DB"); - let new_version = previous_version.apply_upgrade(upgrade, scheduler_vk_hash); - - if let Some(tx) = new_version.tx.clone() { - storage - .transactions_dal() - .insert_system_transaction(tx.clone()) - .await; - storage - .protocol_versions_dal() - .save_genesis_upgrade_with_tx(version_id, tx) - .await; - } + .save_genesis_upgrade_with_tx(version_id, tx) + .await; } stage_latency.observe(); Ok(()) diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index f6335e8f23a5..3eb9cce74a44 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -196,7 +196,7 @@ pub async fn start_eth_watch( pool: ConnectionPool, eth_gateway: Box, diamond_proxy_addr: Address, - state_transition_manager_contract_addr: Address, + state_transition_manager_contract_addr: Option
, governance: (Contract, Address), stop_receiver: watch::Receiver, ) -> anyhow::Result>> { diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index 518a6e57fc2a..76b170ba365e 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -7,7 +7,7 @@ use zksync_types::{ ethabi::{encode, Hash, Token}, l1::{L1Tx, OpProcessingType, PriorityQueueType}, protocol_version::{ProtocolUpgradeTx, ProtocolUpgradeTxCommonData}, - web3::types::{Address, Block, BlockNumber, Log}, + web3::types::{Address, BlockNumber, Log}, Execute, L1TxCommonData, PriorityOpId, ProtocolUpgrade, ProtocolVersion, ProtocolVersionId, Transaction, H256, U256, }; @@ -113,10 +113,6 @@ impl FakeEthClient { #[async_trait::async_trait] impl EthClient for FakeEthClient { - async fn get_block(&self, _hash: H256) -> Result>, Error> { - unimplemented!() - } - async fn get_events( &self, from: BlockNumber, diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 08887cbe1679..3e2fe74eca6c 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -140,8 +140,8 @@ impl ZkSyncStateKeeper { let previous_batch_protocol_version = self.io.load_previous_batch_version_id().await.unwrap(); - let first_batch_in_shared_bridge = l1_batch_env.number == L1BatchNumber(1) - && protocol_version >= ProtocolVersionId::Version21; + let first_batch_in_shared_bridge = + l1_batch_env.number == L1BatchNumber(1) && !protocol_version.is_pre_shared_bridge(); let version_changed = protocol_version != previous_batch_protocol_version; let mut protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; From 591308fbdf872c59536974e89f67f3ae1b56e8fb Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 25 Jan 2024 15:06:36 +0200 Subject: [PATCH 08/37] Fix --- core/lib/env_config/src/contracts.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/lib/env_config/src/contracts.rs b/core/lib/env_config/src/contracts.rs index 456002ca11be..bf2dc31d7bb3 100644 --- a/core/lib/env_config/src/contracts.rs +++ b/core/lib/env_config/src/contracts.rs @@ -19,10 +19,10 @@ mod tests { fn expected_config() -> ContractsConfig { ContractsConfig { - bridgehub_proxy_addr: addr("35ea7f92f4c5f433efe15284e99c040110cf6297"), - bridgehub_impl_addr: addr("87d456da9ed212eb49d80d96afb44afddf36adf8"), - state_transition_proxy_addr: addr("d90f1c081c6117241624e97cb6147257c3cb2097"), - state_transition_impl_addr: addr("c957c0e82d3bafb5ad46ffbcc66900648784eb05"), + bridgehub_proxy_addr: Some(addr("35ea7f92f4c5f433efe15284e99c040110cf6297")), + bridgehub_impl_addr: Some(addr("87d456da9ed212eb49d80d96afb44afddf36adf8")), + state_transition_proxy_addr: Some(addr("d90f1c081c6117241624e97cb6147257c3cb2097")), + state_transition_impl_addr: Some(addr("c957c0e82d3bafb5ad46ffbcc66900648784eb05")), governance_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), mailbox_facet_addr: addr("0f6Fa881EF414Fc6E818180657c2d5CD7Ac6cCAd"), executor_facet_addr: addr("18B631537801963A964211C0E86645c1aBfbB2d3"), @@ -32,7 +32,7 @@ mod tests { diamond_init_addr: addr("FFC35A5e767BE36057c34586303498e3de7C62Ba"), diamond_upgrade_init_addr: addr("FFC35A5e767BE36057c34586303498e3de7C62Ba"), diamond_proxy_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"), - transparent_proxy_admin_addr: addr("dd6fa5c14e7550b4caf2aa2818d24c69cbc347e5"), + transparent_proxy_admin_addr: Some(addr("dd6fa5c14e7550b4caf2aa2818d24c69cbc347e5")), validator_timelock_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"), genesis_tx_hash: hash( "b99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e", From 2e922be8fbe4d8d738d52fd19d89e7f096a0f9c5 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 25 Jan 2024 19:44:46 +0200 Subject: [PATCH 09/37] More improvements --- core/bin/external_node/src/config/mod.rs | 2 +- core/lib/contracts/src/lib.rs | 363 +++--------------- core/lib/dal/src/protocol_versions_dal.rs | 2 +- .../src/api_server/execution_sandbox/mod.rs | 2 +- .../src/consistency_checker/mod.rs | 2 +- core/lib/zksync_core/src/eth_watch/client.rs | 2 +- .../event_processors/set_chain_id.rs | 13 +- core/lib/zksync_core/src/eth_watch/tests.rs | 138 +++++-- .../zksync_core/src/state_keeper/keeper.rs | 7 +- 9 files changed, 186 insertions(+), 345 deletions(-) diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index d8d26eea8bb2..0452de27dac1 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -22,7 +22,7 @@ const BYTES_IN_MEGABYTE: usize = 1_024 * 1_024; /// This part of the external node config is fetched directly from the main node. #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct RemoteENConfig { - pub bridgehub_proxy_addr: Address, + pub bridgehub_proxy_addr: Option
, pub diamond_proxy_addr: Address, pub l1_erc20_bridge_proxy_addr: Address, pub l2_erc20_bridge_addr: Address, diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 3ed725baa7da..98a06bcde58c 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -11,7 +11,7 @@ use std::{ use ethabi::{ ethereum_types::{H256, U256}, - Contract, Function, + Contract, Event, Function, }; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; @@ -564,358 +564,113 @@ pub static PRE_BOOJUM_COMMIT_FUNCTION: Lazy = Lazy::new(|| { serde_json::from_str(abi).unwrap() }); -pub static PRE_BOOJUM_PROVE_FUNCTION: Lazy = Lazy::new(|| { - let abi = r#" - { +pub static SET_CHAIN_ID_EVENT: Lazy = Lazy::new(|| { + let abi = r#"{ + "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_stateTransitionChain", + "type": "address" + }, { "components": [ - { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "indexRepeatedStorageChanges", - "type": "uint64" - }, { "internalType": "uint256", - "name": "numberOfLayer1Txs", + "name": "txType", "type": "uint256" }, - { - "internalType": "bytes32", - "name": "priorityOperationsHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "l2LogsTreeRoot", - "type": "bytes32" - }, { "internalType": "uint256", - "name": "timestamp", + "name": "from", "type": "uint256" }, - { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - } - ], - "internalType": "struct IExecutor.StoredBlockInfo", - "name": "_prevBlock", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "indexRepeatedStorageChanges", - "type": "uint64" - }, { "internalType": "uint256", - "name": "numberOfLayer1Txs", + "name": "to", "type": "uint256" }, { - "internalType": "bytes32", - "name": "priorityOperationsHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "l2LogsTreeRoot", - "type": "bytes32" + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" }, { "internalType": "uint256", - "name": "timestamp", + "name": "gasPerPubdataByteLimit", "type": "uint256" }, { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - } - ], - "internalType": "struct IExecutor.StoredBlockInfo[]", - "name": "_committedBlocks", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "uint256[]", - "name": "recursiveAggregationInput", - "type": "uint256[]" + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" }, { - "internalType": "uint256[]", - "name": "serializedProof", - "type": "uint256[]" - } - ], - "internalType": "struct IExecutor.ProofInput", - "name": "_proof", - "type": "tuple" - } - ], - "name": "proveBlocks", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }"#; - serde_json::from_str(abi).unwrap() -}); - -pub static PRE_BOOJUM_EXECUTE_FUNCTION: Lazy = Lazy::new(|| { - let abi = r#" - { - "inputs": [ - { - "components": [ - { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" }, { - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" + "internalType": "uint256", + "name": "paymaster", + "type": "uint256" }, { - "internalType": "uint64", - "name": "indexRepeatedStorageChanges", - "type": "uint64" + "internalType": "uint256", + "name": "nonce", + "type": "uint256" }, { "internalType": "uint256", - "name": "numberOfLayer1Txs", + "name": "value", "type": "uint256" }, { - "internalType": "bytes32", - "name": "priorityOperationsHash", - "type": "bytes32" + "internalType": "uint256[4]", + "name": "reserved", + "type": "uint256[4]" }, { - "internalType": "bytes32", - "name": "l2LogsTreeRoot", - "type": "bytes32" + "internalType": "bytes", + "name": "data", + "type": "bytes" }, { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "bytes", + "name": "signature", + "type": "bytes" }, { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - } - ], - "internalType": "struct IExecutor.StoredBlockInfo[]", - "name": "_blocksData", - "type": "tuple[]" - } - ], - "name": "executeBlocks", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }"#; - serde_json::from_str(abi).unwrap() -}); - -pub static PRE_BOOJUM_GET_VK_FUNCTION: Lazy = Lazy::new(|| { - let abi = r#"{ - "inputs": [], - "name": "get_verification_key", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "domain_size", - "type": "uint256" + "internalType": "uint256[]", + "name": "factoryDeps", + "type": "uint256[]" }, { - "internalType": "uint256", - "name": "num_inputs", - "type": "uint256" + "internalType": "bytes", + "name": "paymasterInput", + "type": "bytes" }, { - "components": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.Fr", - "name": "omega", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point[2]", - "name": "gate_selectors_commitments", - "type": "tuple[2]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point[8]", - "name": "gate_setup_commitments", - "type": "tuple[8]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point[4]", - "name": "permutation_commitments", - "type": "tuple[4]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point", - "name": "lookup_selector_commitment", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point[4]", - "name": "lookup_tables_commitments", - "type": "tuple[4]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point", - "name": "lookup_table_type_commitment", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.Fr[3]", - "name": "non_residues", - "type": "tuple[3]" - }, - { - "components": [ - { - "internalType": "uint256[2]", - "name": "X", - "type": "uint256[2]" - }, - { - "internalType": "uint256[2]", - "name": "Y", - "type": "uint256[2]" - } - ], - "internalType": "struct PairingsBn254.G2Point[2]", - "name": "g2_elements", - "type": "tuple[2]" + "internalType": "bytes", + "name": "reservedDynamic", + "type": "bytes" } ], - "internalType": "struct VerificationKey", - "name": "vk", + "indexed": false, + "internalType": "struct L2CanonicalTransaction", + "name": "_l2Transaction", "type": "tuple" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_protocolVersion", + "type": "uint256" } ], - "stateMutability": "pure", - "type": "function" + "name": "SetChainIdUpgrade", + "type": "event" }"#; serde_json::from_str(abi).unwrap() }); diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 7f7e194ace28..2db89295f4f5 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -115,7 +115,7 @@ impl ProtocolVersionsDal<'_, '_> { .unwrap(); } - /// Attaches a transaction used to set chainId to the genesis protocol version. + /// Attaches a transaction used to set ChainId to the genesis protocol version. /// Also inserts that transaction into the database. pub async fn save_genesis_upgrade_with_tx( &mut self, diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs index 7ac18aae858a..3c3a8e9a36ad 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs @@ -284,7 +284,7 @@ pub(crate) struct BlockArgs { } impl BlockArgs { - pub async fn pending(connection: &mut StorageProcessor<'_>) -> anyhow::Result { + pub(crate) async fn pending(connection: &mut StorageProcessor<'_>) -> anyhow::Result { let (block_id, resolved_block_number) = get_pending_state(connection).await?; Ok(Self { block_id, diff --git a/core/lib/zksync_core/src/consistency_checker/mod.rs b/core/lib/zksync_core/src/consistency_checker/mod.rs index 768684e5fbaf..f7d49d0b8e34 100644 --- a/core/lib/zksync_core/src/consistency_checker/mod.rs +++ b/core/lib/zksync_core/src/consistency_checker/mod.rs @@ -174,7 +174,7 @@ impl ConsistencyChecker { .with_context(|| format!("Commit for tx {commit_tx_hash:?} not found on L1"))? .input; // TODO (PLA-721): Check receiving contract and selector - + // TODO: Add support for post shared bridge commits let commit_function = if local.is_pre_boojum { &*PRE_BOOJUM_COMMIT_FUNCTION } else { diff --git a/core/lib/zksync_core/src/eth_watch/client.rs b/core/lib/zksync_core/src/eth_watch/client.rs index 5e6e81717c1a..812181ac1404 100644 --- a/core/lib/zksync_core/src/eth_watch/client.rs +++ b/core/lib/zksync_core/src/eth_watch/client.rs @@ -58,7 +58,7 @@ pub struct EthHttpQueryClient { topics: Vec, zksync_contract_addr: Address, /// Address of the `StateTransitionManager` contract. It's optional because it is present only - /// for post shared brige chains. If address is some then client will listen to `SetChainId` events coming from it. + /// for post shared bridge chains. If address is some then client will listen to `SetChainId` events coming from it. state_transition_manager_contract_addr: Option
, /// Address of the `Governance` contract. It's optional because it is present only for post-boojum chains. /// If address is some then client will listen to events coming from it. diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs index 9706b55e94ce..523f8e36ab36 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs @@ -1,3 +1,4 @@ +use zksync_contracts::SET_CHAIN_ID_EVENT; use zksync_dal::StorageProcessor; use zksync_types::{protocol_version::decode_set_chain_id_event, web3::types::Log, Address, H256}; @@ -7,10 +8,13 @@ use crate::eth_watch::{ metrics::{PollStage, METRICS}, }; -/// Responsible for saving new protocol upgrade proposals to the database. +/// Responsible for saving `setChainId` upgrade transactions to the database. #[derive(Debug)] pub struct SetChainIDEventProcessor { + /// Address of the `DiamondProxy` contract of the chain that the `SetChainId` event is for. diamond_proxy_address: Address, + /// Signature of the `SetChainIdUpgrade` event. + /// The event is emitted by the `StateTransitionManager` contract. set_chain_id_signature: H256, } @@ -18,12 +22,7 @@ impl SetChainIDEventProcessor { pub fn new(diamond_proxy_address: Address) -> Self { Self { diamond_proxy_address, - set_chain_id_signature: H256::default(), - // TODO: uncomment when we merge the Shared Bridge contracts. - // state_transition_manager_contract() - // .event("SetChainIdUpgrade") - // .expect("SetChainIdUpgrade event is missing in ABI") - // .signature(), + set_chain_id_signature: SET_CHAIN_ID_EVENT.signature(), } } } diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index 76b170ba365e..5105219ef13d 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, convert::TryInto, sync::Arc}; use tokio::sync::RwLock; -use zksync_contracts::{governance_contract, zksync_contract}; +use zksync_contracts::{governance_contract, zksync_contract, SET_CHAIN_ID_EVENT}; use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_types::{ ethabi::{encode, Hash, Token}, @@ -22,6 +22,8 @@ struct FakeEthClientData { transactions: HashMap>, diamond_upgrades: HashMap>, governance_upgrades: HashMap>, + // Not `Vec` because there can be only one `setChainId` upgrade per chain. + set_chain_id_upgrades: HashMap, last_finalized_block_number: u64, } @@ -31,6 +33,7 @@ impl FakeEthClientData { transactions: Default::default(), diamond_upgrades: Default::default(), governance_upgrades: Default::default(), + set_chain_id_upgrades: Default::default(), last_finalized_block_number: 0, } } @@ -63,6 +66,12 @@ impl FakeEthClientData { } } + fn add_set_chain_id_upgrade(&mut self, upgrade: ProtocolUpgrade, eth_block: u64) { + self.set_chain_id_upgrades + .entry(eth_block) + .or_insert_with(|| upgrade_into_set_chain_id_log(upgrade, eth_block)); + } + fn set_last_finalized_block_number(&mut self, number: u64) { self.last_finalized_block_number = number; } @@ -92,6 +101,13 @@ impl FakeEthClient { self.inner.write().await.add_governance_upgrades(upgrades); } + async fn add_set_chain_id_upgrade(&mut self, upgrade: ProtocolUpgrade, eth_block: u64) { + self.inner + .write() + .await + .add_set_chain_id_upgrade(upgrade, eth_block); + } + async fn set_last_finalized_block_number(&mut self, number: u64) { self.inner .write() @@ -132,6 +148,9 @@ impl EthClient for FakeEthClient { if let Some(ops) = self.inner.read().await.governance_upgrades.get(&number) { logs.extend_from_slice(ops); } + if let Some(op) = self.inner.read().await.set_chain_id_upgrades.get(&number) { + logs.push(op.clone()); + } } Ok(logs) } @@ -523,6 +542,52 @@ async fn test_overlapping_batches() { assert_eq!(tx.common_data.serial_id.0, 4); } +#[tokio::test] +async fn test_set_chain_id_upgrade() { + let diamond_proxy_address = Address::repeat_byte(0x18); + let connection_pool = ConnectionPool::test_pool().await; + setup_db(&connection_pool).await; + + let mut client = FakeEthClient::new(); + let mut watcher = EthWatch::new( + diamond_proxy_address, + None, + Box::new(client.clone()), + &connection_pool, + std::time::Duration::from_nanos(1), + ) + .await; + + let tx_hash = H256::random(); + let mut upgrade_tx = build_upgrade_tx(ProtocolVersionId::latest(), 18); + upgrade_tx.common_data.canonical_tx_hash = tx_hash; + + let mut storage = connection_pool.access_storage().await.unwrap(); + client + .add_set_chain_id_upgrade( + ProtocolUpgrade { + id: ProtocolVersionId::next(), + tx: Some(upgrade_tx.clone()), + ..Default::default() + }, + 18, + ) + .await; + + client.set_last_finalized_block_number(18).await; + watcher.loop_iteration(&mut storage).await.unwrap(); + let db_txs = get_all_db_txs(&mut storage).await; + assert!(db_txs.contains(&upgrade_tx.into())); + + let protocol_upgrade_tx = storage + .protocol_versions_dal() + .get_protocol_upgrade_tx(ProtocolVersionId::latest()) + .await + .unwrap(); + + assert_eq!(protocol_upgrade_tx.common_data.hash(), tx_hash); +} + async fn get_all_db_txs(storage: &mut StorageProcessor<'_>) -> Vec { storage.transactions_dal().reset_mempool().await.unwrap(); let (txs, _) = storage @@ -604,6 +669,27 @@ fn upgrade_into_diamond_proxy_log(upgrade: ProtocolUpgrade, eth_block: u64) -> L } } +fn upgrade_into_set_chain_id_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { + let data = encode(&[tx_into_token(upgrade.tx.unwrap())]); + Log { + address: Address::repeat_byte(0x1), + topics: vec![ + SET_CHAIN_ID_EVENT.signature(), + Address::repeat_byte(0x18).into(), // diamond proxy address + H256::from_low_u64_be(ProtocolVersionId::latest() as u64).into(), + ], + data: data.into(), + block_hash: Some(H256::repeat_byte(0x11)), + block_number: Some(eth_block.into()), + transaction_hash: Some(H256::random()), + transaction_index: Some(0u64.into()), + log_index: Some(0u64.into()), + transaction_log_index: Some(0u64.into()), + log_type: None, + removed: None, + } +} + fn upgrade_into_governor_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { let diamond_cut = upgrade_into_diamond_cut(upgrade); let execute_upgrade_selector = zksync_contract() @@ -648,31 +734,35 @@ fn upgrade_into_governor_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { } } +fn tx_into_token(tx: ProtocolUpgradeTx) -> Token { + Token::Tuple(vec![ + Token::Uint(0xfe.into()), + Token::Address(tx.common_data.sender), + Token::Address(tx.execute.contract_address), + Token::Uint(tx.common_data.gas_limit), + Token::Uint(tx.common_data.gas_per_pubdata_limit), + Token::Uint(tx.common_data.max_fee_per_gas), + Token::Uint(U256::zero()), + Token::Address(Address::zero()), + Token::Uint((tx.common_data.upgrade_id as u16).into()), + Token::Uint(tx.execute.value), + Token::FixedArray(vec![ + Token::Uint(U256::zero()), + Token::Uint(U256::zero()), + Token::Uint(U256::zero()), + Token::Uint(U256::zero()), + ]), + Token::Bytes(tx.execute.calldata), + Token::Bytes(Vec::new()), + Token::Array(Vec::new()), + Token::Bytes(Vec::new()), + Token::Bytes(Vec::new()), + ]) +} + fn upgrade_into_diamond_cut(upgrade: ProtocolUpgrade) -> Token { let tx_data_token = if let Some(tx) = upgrade.tx { - Token::Tuple(vec![ - Token::Uint(0xfe.into()), - Token::Address(tx.common_data.sender), - Token::Address(tx.execute.contract_address), - Token::Uint(tx.common_data.gas_limit), - Token::Uint(tx.common_data.gas_per_pubdata_limit), - Token::Uint(tx.common_data.max_fee_per_gas), - Token::Uint(U256::zero()), - Token::Address(Address::zero()), - Token::Uint((tx.common_data.upgrade_id as u16).into()), - Token::Uint(tx.execute.value), - Token::FixedArray(vec![ - Token::Uint(U256::zero()), - Token::Uint(U256::zero()), - Token::Uint(U256::zero()), - Token::Uint(U256::zero()), - ]), - Token::Bytes(tx.execute.calldata), - Token::Bytes(Vec::new()), - Token::Array(Vec::new()), - Token::Bytes(Vec::new()), - Token::Bytes(Vec::new()), - ]) + tx_into_token(tx) } else { Token::Tuple(vec![ Token::Uint(0.into()), diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 3e2fe74eca6c..9b90631480f2 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -7,11 +7,8 @@ use anyhow::Context as _; use multivm::interface::{Halt, L1BatchEnv, SystemEnv}; use tokio::sync::watch; use zksync_types::{ - block::MiniblockExecutionData, - l2::TransactionType, - protocol_version::{ProtocolUpgradeTx, ProtocolVersionId}, - storage_writes_deduplicator::StorageWritesDeduplicator, - L1BatchNumber, Transaction, + block::MiniblockExecutionData, l2::TransactionType, protocol_version::ProtocolUpgradeTx, + storage_writes_deduplicator::StorageWritesDeduplicator, L1BatchNumber, Transaction, }; use super::{ From 150499a5d01f7b098abd837ef9d476d1167b30a2 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 30 Jan 2024 11:44:37 +0200 Subject: [PATCH 10/37] Fix tests --- core/lib/contracts/src/lib.rs | 19 ------ core/lib/types/src/protocol_version.rs | 4 +- .../src/eth_sender/eth_tx_aggregator.rs | 8 ++- core/lib/zksync_core/src/eth_sender/tests.rs | 6 +- core/lib/zksync_core/src/eth_watch/tests.rs | 60 +++++++++++++------ core/lib/zksync_core/src/lib.rs | 7 +-- 6 files changed, 56 insertions(+), 48 deletions(-) diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 98a06bcde58c..9d33a42ea010 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -570,101 +570,82 @@ pub static SET_CHAIN_ID_EVENT: Lazy = Lazy::new(|| { "inputs": [ { "indexed": true, - "internalType": "address", "name": "_stateTransitionChain", "type": "address" }, { "components": [ { - "internalType": "uint256", "name": "txType", "type": "uint256" }, { - "internalType": "uint256", "name": "from", "type": "uint256" }, { - "internalType": "uint256", "name": "to", "type": "uint256" }, { - "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, { - "internalType": "uint256", "name": "gasPerPubdataByteLimit", "type": "uint256" }, { - "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, { - "internalType": "uint256", "name": "maxPriorityFeePerGas", "type": "uint256" }, { - "internalType": "uint256", "name": "paymaster", "type": "uint256" }, { - "internalType": "uint256", "name": "nonce", "type": "uint256" }, { - "internalType": "uint256", "name": "value", "type": "uint256" }, { - "internalType": "uint256[4]", "name": "reserved", "type": "uint256[4]" }, { - "internalType": "bytes", "name": "data", "type": "bytes" }, { - "internalType": "bytes", "name": "signature", "type": "bytes" }, { - "internalType": "uint256[]", "name": "factoryDeps", "type": "uint256[]" }, { - "internalType": "bytes", "name": "paymasterInput", "type": "bytes" }, { - "internalType": "bytes", "name": "reservedDynamic", "type": "bytes" } ], "indexed": false, - "internalType": "struct L2CanonicalTransaction", "name": "_l2Transaction", "type": "tuple" }, { "indexed": true, - "internalType": "uint256", "name": "_protocolVersion", "type": "uint256" } diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 3cb9edca627e..c2d6b69b59c3 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -670,7 +670,7 @@ impl ProtocolVersion { } } -#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ProtocolUpgradeTxCommonData { /// Sender of the transaction. @@ -705,7 +705,7 @@ impl ProtocolUpgradeTxCommonData { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ProtocolUpgradeTx { pub execute: Execute, pub common_data: ProtocolUpgradeTxCommonData, diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs index 8e07cb6d919f..3aa468d13615 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs @@ -54,17 +54,21 @@ pub struct EthTxAggregator { } impl EthTxAggregator { - pub fn new( + pub async fn new( config: SenderConfig, aggregator: Aggregator, eth_client: Arc, timelock_contract_address: Address, l1_multicall3_address: Address, main_zksync_contract_address: Address, - base_nonce: u64, rollup_chain_id: L2ChainId, ) -> Self { let functions = ZkSyncFunctions::default(); + let base_nonce = eth_client + .pending_nonce("eth_sender") + .await + .unwrap() + .as_u64(); Self { config, aggregator, diff --git a/core/lib/zksync_core/src/eth_sender/tests.rs b/core/lib/zksync_core/src/eth_sender/tests.rs index d64acfafb0e3..98246281fdc4 100644 --- a/core/lib/zksync_core/src/eth_sender/tests.rs +++ b/core/lib/zksync_core/src/eth_sender/tests.rs @@ -110,9 +110,9 @@ impl EthSenderTester { Address::random(), contracts_config.l1_multicall3_addr, Address::random(), - 0, 270.into(), - ); + ) + .await; let manager = EthTxManager::new( eth_sender_config.sender, @@ -955,7 +955,7 @@ async fn send_operation( .save_eth_tx( &mut tester.conn.access_storage().await.unwrap(), &aggregated_operation, - false, + true, ) .await .unwrap(); diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index 5105219ef13d..be68ba523dee 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -7,7 +7,10 @@ use zksync_types::{ ethabi::{encode, Hash, Token}, l1::{L1Tx, OpProcessingType, PriorityQueueType}, protocol_version::{ProtocolUpgradeTx, ProtocolUpgradeTxCommonData}, - web3::types::{Address, BlockNumber, Log}, + web3::{ + signing::keccak256, + types::{Address, BlockNumber, Log}, + }, Execute, L1TxCommonData, PriorityOpId, ProtocolUpgrade, ProtocolVersion, ProtocolVersionId, Transaction, H256, U256, }; @@ -196,11 +199,11 @@ fn build_l1_tx(serial_id: u64, eth_block: u64) -> L1Tx { } fn build_upgrade_tx(id: ProtocolVersionId, eth_block: u64) -> ProtocolUpgradeTx { - ProtocolUpgradeTx { + let mut tx = ProtocolUpgradeTx { execute: Execute { contract_address: Address::repeat_byte(0x11), calldata: vec![1, 2, 3], - factory_deps: None, + factory_deps: Some(Vec::new()), value: U256::zero(), }, common_data: ProtocolUpgradeTxCommonData { @@ -216,7 +219,10 @@ fn build_upgrade_tx(id: ProtocolVersionId, eth_block: u64) -> ProtocolUpgradeTx canonical_tx_hash: H256::from_low_u64_be(id as u64), }, received_timestamp_ms: 0, - } + }; + + tx.common_data.canonical_tx_hash = H256(keccak256(&encode(&[tx_into_token(tx.clone())]))); + tx } #[tokio::test] @@ -544,9 +550,11 @@ async fn test_overlapping_batches() { #[tokio::test] async fn test_set_chain_id_upgrade() { + let protocol_version = ProtocolVersionId::latest(); let diamond_proxy_address = Address::repeat_byte(0x18); let connection_pool = ConnectionPool::test_pool().await; setup_db(&connection_pool).await; + let mut storage = connection_pool.access_storage().await.unwrap(); let mut client = FakeEthClient::new(); let mut watcher = EthWatch::new( @@ -558,16 +566,33 @@ async fn test_set_chain_id_upgrade() { ) .await; - let tx_hash = H256::random(); - let mut upgrade_tx = build_upgrade_tx(ProtocolVersionId::latest(), 18); - upgrade_tx.common_data.canonical_tx_hash = tx_hash; + // Set initial protocol version + storage + .protocol_versions_dal() + .save_protocol_version( + protocol_version, + 0, + Default::default(), + Default::default(), + Default::default(), + None, + ) + .await; + + assert_eq!( + storage + .protocol_versions_dal() + .get_protocol_upgrade_tx(protocol_version) + .await, + None + ); - let mut storage = connection_pool.access_storage().await.unwrap(); + let tx = build_upgrade_tx(protocol_version, 18); client .add_set_chain_id_upgrade( ProtocolUpgrade { - id: ProtocolVersionId::next(), - tx: Some(upgrade_tx.clone()), + id: protocol_version, + tx: Some(tx.clone()), ..Default::default() }, 18, @@ -576,16 +601,14 @@ async fn test_set_chain_id_upgrade() { client.set_last_finalized_block_number(18).await; watcher.loop_iteration(&mut storage).await.unwrap(); - let db_txs = get_all_db_txs(&mut storage).await; - assert!(db_txs.contains(&upgrade_tx.into())); - let protocol_upgrade_tx = storage + let upgrade_tx = storage .protocol_versions_dal() - .get_protocol_upgrade_tx(ProtocolVersionId::latest()) + .get_protocol_upgrade_tx(protocol_version) .await .unwrap(); - assert_eq!(protocol_upgrade_tx.common_data.hash(), tx_hash); + assert_eq!(tx.common_data.hash(), upgrade_tx.common_data.hash()); } async fn get_all_db_txs(storage: &mut StorageProcessor<'_>) -> Vec { @@ -670,18 +693,19 @@ fn upgrade_into_diamond_proxy_log(upgrade: ProtocolUpgrade, eth_block: u64) -> L } fn upgrade_into_set_chain_id_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { - let data = encode(&[tx_into_token(upgrade.tx.unwrap())]); + let tx = upgrade.tx.unwrap(); + let data = encode(&[tx_into_token(tx.clone())]); Log { address: Address::repeat_byte(0x1), topics: vec![ SET_CHAIN_ID_EVENT.signature(), Address::repeat_byte(0x18).into(), // diamond proxy address - H256::from_low_u64_be(ProtocolVersionId::latest() as u64).into(), + H256::from_low_u64_be(ProtocolVersionId::latest() as u64), ], data: data.into(), block_hash: Some(H256::repeat_byte(0x11)), block_number: Some(eth_block.into()), - transaction_hash: Some(H256::random()), + transaction_hash: Some([2; 32].into()), transaction_index: Some(0u64.into()), log_index: Some(0u64.into()), transaction_log_index: Some(0u64.into()), diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 92b64bd51ff8..a086719b1839 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -28,7 +28,7 @@ use zksync_contracts::{governance_contract, BaseSystemContracts}; use zksync_dal::{healthcheck::ConnectionPoolHealthCheck, ConnectionPool}; use zksync_eth_client::{ clients::{PKSigningClient, QueryClient}, - BoundEthInterface, CallFunctionArgs, EthInterface, + CallFunctionArgs, EthInterface, }; use zksync_health_check::{CheckHealth, HealthStatus, ReactiveHealthCheck}; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; @@ -552,7 +552,6 @@ pub async fn initialize_components( .context("eth_sender_config")?; let eth_client = PKSigningClient::from_config(ð_sender, &contracts_config, ð_client_config); - let nonce = eth_client.pending_nonce("eth_sender").await.unwrap(); let eth_tx_aggregator_actor = EthTxAggregator::new( eth_sender.sender.clone(), Aggregator::new( @@ -563,13 +562,13 @@ pub async fn initialize_components( contracts_config.validator_timelock_addr, contracts_config.l1_multicall3_addr, main_zksync_contract_address, - nonce.as_u64(), configs .network_config .as_ref() .context("netowrk_config")? .zksync_network_id, - ); + ) + .await; task_futures.push(tokio::spawn( eth_tx_aggregator_actor.run(eth_sender_pool, stop_receiver.clone()), )); From 6775a939e47c67c94c13db442485b0e253f965ad Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 30 Jan 2024 11:58:28 +0200 Subject: [PATCH 11/37] Fix compilation --- core/lib/config/src/testonly.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index 64a38ff51ae2..fe00e32db360 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -363,6 +363,11 @@ impl RandomConfig for configs::ContractsConfig { fri_recursion_leaf_level_vk_hash: g.gen(), prover_at_genesis: g.gen(), snark_wrapper_vk_hash: g.gen(), + bridgehub_impl_addr: g.gen(), + bridgehub_proxy_addr: g.gen(), + state_transition_proxy_addr: g.gen(), + state_transition_impl_addr: g.gen(), + transparent_proxy_admin_addr: g.gen(), } } } From b78178e58d933467c2a2a9cf0cd0e04b151a1c13 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 30 Jan 2024 12:55:33 +0200 Subject: [PATCH 12/37] Fix protobuf configs --- core/lib/config/src/configs/contracts.rs | 14 +-- core/lib/protobuf_config/src/contracts.rs | 25 ++++ .../protobuf_config/src/proto/contracts.proto | 5 + .../zksync_core/src/state_keeper/keeper.rs | 111 ++++++++++-------- 4 files changed, 102 insertions(+), 53 deletions(-) diff --git a/core/lib/config/src/configs/contracts.rs b/core/lib/config/src/configs/contracts.rs index aaa16fe86a83..70d4e685586f 100644 --- a/core/lib/config/src/configs/contracts.rs +++ b/core/lib/config/src/configs/contracts.rs @@ -14,13 +14,6 @@ pub enum ProverAtGenesis { pub struct ContractsConfig { pub governance_addr: Address, pub mailbox_facet_addr: Address, - - pub bridgehub_proxy_addr: Option
, - pub bridgehub_impl_addr: Option
, - pub state_transition_proxy_addr: Option
, - pub state_transition_impl_addr: Option
, - pub transparent_proxy_admin_addr: Option
, - pub executor_facet_addr: Address, pub admin_facet_addr: Address, pub getters_facet_addr: Address, @@ -47,6 +40,13 @@ pub struct ContractsConfig { pub fri_recursion_leaf_level_vk_hash: H256, pub prover_at_genesis: ProverAtGenesis, pub snark_wrapper_vk_hash: H256, + + // These contracts will be used after shared bridge integration. + pub bridgehub_proxy_addr: Option
, + pub bridgehub_impl_addr: Option
, + pub state_transition_proxy_addr: Option
, + pub state_transition_impl_addr: Option
, + pub transparent_proxy_admin_addr: Option
, } impl ContractsConfig { diff --git a/core/lib/protobuf_config/src/contracts.rs b/core/lib/protobuf_config/src/contracts.rs index 6521bd0bf810..959756efa936 100644 --- a/core/lib/protobuf_config/src/contracts.rs +++ b/core/lib/protobuf_config/src/contracts.rs @@ -122,6 +122,31 @@ impl ProtoRepr for proto::Contracts { snark_wrapper_vk_hash: required(&self.snark_wrapper_vk_hash) .and_then(|x| parse_h256(x)) .context("snark_wrapper_vk_hash")?, + bridgehub_proxy_addr: (&self.bridgehub_proxy_addr) + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("bridgehub_proxy_addr")?, + bridgeub_impl_addr: (&self.bridgeub_impl_addr) + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("bridgeub_impl_addr")?, + state_transition_proxy_addr: (&self.state_transition_proxy_addr) + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("state_transition_proxy_addr")?, + state_transition_impl_addr: (&self.state_transition_impl_addr) + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("state_transition_impl_addr")?, + transparent_proxy_admin_addr: (&self.transparent_proxy_admin_addr) + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("transparent_proxy_admin_addr")?, }) } diff --git a/core/lib/protobuf_config/src/proto/contracts.proto b/core/lib/protobuf_config/src/proto/contracts.proto index 1acda022cd90..87fd02b615c2 100644 --- a/core/lib/protobuf_config/src/proto/contracts.proto +++ b/core/lib/protobuf_config/src/proto/contracts.proto @@ -36,4 +36,9 @@ message Contracts { optional bytes fri_recursion_leaf_level_vk_hash = 26; // required; H256 optional ProverAtGenesis prover_at_genesis = 27; // required optional bytes snark_wrapper_vk_hash = 28; // required; H256 + optional bytes bridgehub_proxy_addr = 29; // optional; H160 + optional bytes bridgehub_impl_addr = 30; // optional; H160 + optional bytes state_transition_proxy_addr = 31; // optional; H160 + optional bytes state_transition_impl_addr = 32; // optional; H160 + optional bytes transparent_proxy_admin_addr = 33; // optional; H160 } diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index af6480bbd6b4..8f72442ba023 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -7,8 +7,11 @@ use anyhow::Context as _; use multivm::interface::{Halt, L1BatchEnv, SystemEnv}; use tokio::sync::watch; use zksync_types::{ - block::MiniblockExecutionData, l2::TransactionType, protocol_version::ProtocolUpgradeTx, - storage_writes_deduplicator::StorageWritesDeduplicator, L1BatchNumber, Transaction, + block::MiniblockExecutionData, + l2::TransactionType, + protocol_version::{ProtocolUpgradeTx, ProtocolVersionId}, + storage_writes_deduplicator::StorageWritesDeduplicator, + L1BatchNumber, Transaction, }; use super::{ @@ -134,52 +137,15 @@ impl ZkSyncStateKeeper { protocol_version, ); - let previous_batch_protocol_version = - self.io.load_previous_batch_version_id().await.unwrap(); - let first_batch_in_shared_bridge = l1_batch_env.number == L1BatchNumber(1) && !protocol_version.is_pre_shared_bridge(); - let version_changed = protocol_version != previous_batch_protocol_version; - - let mut protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; - - // After the Shared Bridge is integrated, - // there has to be a setChainId upgrade transaction after the chain genesis. - // It has to be the first transaction of the first batch. - // If it's not present, we have to wait for it to be picked up by the event watcher. - // The setChainId upgrade does not bump the protocol version, rather attaches an upgrade - // transaction to the genesis protocol version. - while first_batch_in_shared_bridge && protocol_upgrade_tx.is_none() { - tracing::info!("Waiting for setChainId upgrade transaction to be picked up"); - if self.is_canceled() { - return Err(Error::Canceled); - } - tokio::time::sleep(Duration::from_secs(1)).await; - protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; - } - - let mut protocol_upgrade_tx = - if pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) { - tracing::info!("We have upgrade tx to be executed in empty miniblock"); - protocol_upgrade_tx - } else if !pending_miniblocks.is_empty() - && (version_changed || first_batch_in_shared_bridge) - { - // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block - // then it must be the first one in `txs_to_reexecute`. - if protocol_upgrade_tx.is_some() { - let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; - assert_eq!( - first_tx_to_reexecute.tx_format(), - TransactionType::ProtocolUpgradeTransaction - ) - } - tracing::info!("We have no upgrade tx to execute"); - None - } else { - tracing::info!("We are not changing protocol version"); - None - }; + let mut protocol_upgrade_tx = self + .load_protocol_upgrade_tx( + &pending_miniblocks, + protocol_version, + first_batch_in_shared_bridge, + ) + .await?; let mut batch_executor = self .batch_executor_base @@ -260,6 +226,59 @@ impl ZkSyncStateKeeper { Err(Error::Canceled) } + async fn load_protocol_upgrade_tx( + &mut self, + pending_miniblocks: &[MiniblockExecutionData], + protocol_version: ProtocolVersionId, + first_batch_in_shared_bridge: bool, + ) -> Result, Error> { + let previous_batch_protocol_version = + self.io.load_previous_batch_version_id().await.unwrap(); + + let version_changed = protocol_version != previous_batch_protocol_version; + let mut protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; + + // After the Shared Bridge is integrated, + // there has to be a setChainId upgrade transaction after the chain genesis. + // It has to be the first transaction of the first batch. + // If it's not present, we have to wait for it to be picked up by the event watcher. + // The setChainId upgrade does not bump the protocol version, rather attaches an upgrade + // transaction to the genesis protocol version. + while first_batch_in_shared_bridge && protocol_upgrade_tx.is_none() { + tracing::info!("Waiting for setChainId upgrade transaction to be picked up"); + if self.is_canceled() { + return Err(Error::Canceled); + } + tokio::time::sleep(Duration::from_secs(1)).await; + protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; + } + + let protocol_upgrade_tx = + if pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) { + tracing::info!("We have upgrade tx to be executed in empty miniblock"); + protocol_upgrade_tx + } else if !pending_miniblocks.is_empty() + && (version_changed || first_batch_in_shared_bridge) + { + // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block + // then it must be the first one in `txs_to_reexecute`. + if protocol_upgrade_tx.is_some() { + let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; + assert_eq!( + first_tx_to_reexecute.tx_format(), + TransactionType::ProtocolUpgradeTransaction + ) + } + tracing::info!("We have no upgrade tx to execute"); + None + } else { + tracing::info!("We are not changing protocol version"); + None + }; + + Ok(protocol_upgrade_tx) + } + fn is_canceled(&self) -> bool { *self.stop_receiver.borrow() } From 467a7589115e7007eacdf612457c09887a6cb18b Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 30 Jan 2024 13:40:16 +0200 Subject: [PATCH 13/37] Fix protobuf --- core/lib/protobuf_config/src/contracts.rs | 35 +++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/core/lib/protobuf_config/src/contracts.rs b/core/lib/protobuf_config/src/contracts.rs index 959756efa936..b3a121c9df3d 100644 --- a/core/lib/protobuf_config/src/contracts.rs +++ b/core/lib/protobuf_config/src/contracts.rs @@ -122,27 +122,32 @@ impl ProtoRepr for proto::Contracts { snark_wrapper_vk_hash: required(&self.snark_wrapper_vk_hash) .and_then(|x| parse_h256(x)) .context("snark_wrapper_vk_hash")?, - bridgehub_proxy_addr: (&self.bridgehub_proxy_addr) + bridgehub_proxy_addr: self + .bridgehub_proxy_addr .as_ref() .map(|x| parse_h160(x)) .transpose() .context("bridgehub_proxy_addr")?, - bridgeub_impl_addr: (&self.bridgeub_impl_addr) + bridgehub_impl_addr: self + .bridgehub_impl_addr .as_ref() .map(|x| parse_h160(x)) .transpose() .context("bridgeub_impl_addr")?, - state_transition_proxy_addr: (&self.state_transition_proxy_addr) + state_transition_proxy_addr: self + .state_transition_proxy_addr .as_ref() .map(|x| parse_h160(x)) .transpose() .context("state_transition_proxy_addr")?, - state_transition_impl_addr: (&self.state_transition_impl_addr) + state_transition_impl_addr: self + .state_transition_impl_addr .as_ref() .map(|x| parse_h160(x)) .transpose() .context("state_transition_impl_addr")?, - transparent_proxy_admin_addr: (&self.transparent_proxy_admin_addr) + transparent_proxy_admin_addr: self + .transparent_proxy_admin_addr .as_ref() .map(|x| parse_h160(x)) .transpose() @@ -199,6 +204,26 @@ impl ProtoRepr for proto::Contracts { ), prover_at_genesis: Some(proto::ProverAtGenesis::new(&this.prover_at_genesis).into()), snark_wrapper_vk_hash: Some(this.snark_wrapper_vk_hash.as_bytes().into()), + bridgehub_proxy_addr: this + .bridgehub_proxy_addr + .as_ref() + .map(|x| x.as_bytes().into()), + bridgehub_impl_addr: this + .bridgehub_impl_addr + .as_ref() + .map(|x| x.as_bytes().into()), + state_transition_proxy_addr: this + .state_transition_proxy_addr + .as_ref() + .map(|x| x.as_bytes().into()), + state_transition_impl_addr: this + .state_transition_impl_addr + .as_ref() + .map(|x| x.as_bytes().into()), + transparent_proxy_admin_addr: this + .transparent_proxy_admin_addr + .as_ref() + .map(|x| x.as_bytes().into()), } } } From 4104ab4ce14150b4f79793cfac06987979589f7c Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 1 Feb 2024 14:20:47 +0200 Subject: [PATCH 14/37] Fix upgrade test --- core/lib/types/src/protocol_version.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index c2d6b69b59c3..f648b3daba30 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -94,7 +94,8 @@ impl ProtocolVersionId { } pub fn is_pre_shared_bridge(&self) -> bool { - self <= &Self::Version20 + // TODO: review this when we actually deploy shared bridge + self <= &Self::Version21 } pub fn is_1_4_0(&self) -> bool { From 6867f55a46feeeb0f5fb9fbb02abcc5738673cb3 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 1 Feb 2024 19:21:32 +0200 Subject: [PATCH 15/37] Add unit test --- core/lib/types/src/protocol_version.rs | 12 ++++- core/lib/types/src/tx/execute.rs | 2 +- .../zksync_core/src/state_keeper/keeper.rs | 4 +- .../seal_criteria/conditional_sealer.rs | 2 +- .../zksync_core/src/state_keeper/tests/mod.rs | 52 ++++++++++++++++++- .../src/state_keeper/tests/tester.rs | 28 ++++++++-- 6 files changed, 88 insertions(+), 12 deletions(-) diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index f648b3daba30..79f3c3c009cc 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -18,7 +18,17 @@ use crate::{ #[repr(u16)] #[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TryFromPrimitive, Serialize, Deserialize, + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + TryFromPrimitive, + Serialize, + Deserialize, )] pub enum ProtocolVersionId { Version0 = 0, diff --git a/core/lib/types/src/tx/execute.rs b/core/lib/types/src/tx/execute.rs index 21f0b401cce2..889c276a3e7a 100644 --- a/core/lib/types/src/tx/execute.rs +++ b/core/lib/types/src/tx/execute.rs @@ -5,7 +5,7 @@ use zksync_utils::ZeroPrefixHexSerde; use crate::{web3::ethabi, Address, EIP712TypedStructure, StructBuilder, H256, U256}; /// `Execute` transaction executes a previously deployed smart contract in the L2 rollup. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Execute { pub contract_address: Address, diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 326cddfe75d2..f3836e1270b0 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -31,7 +31,7 @@ pub(super) const POLL_WAIT_DURATION: Duration = Duration::from_secs(1); /// Structure used to indicate that task cancellation was requested. #[derive(thiserror::Error, Debug)] -enum Error { +pub(super) enum Error { #[error("canceled")] Canceled, #[error(transparent)] @@ -226,7 +226,7 @@ impl ZkSyncStateKeeper { Err(Error::Canceled) } - async fn load_protocol_upgrade_tx( + pub(super) async fn load_protocol_upgrade_tx( &mut self, pending_miniblocks: &[MiniblockExecutionData], protocol_version: ProtocolVersionId, diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs index cc7ba37ef9c8..9d6ea9728e92 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs @@ -39,7 +39,7 @@ pub trait ConditionalSealer: 'static + fmt::Debug + Send + Sync { /// /// The checks are deterministic, i.e., should depend solely on execution metrics and [`StateKeeperConfig`]. /// Non-deterministic seal criteria are expressed using [`IoSealCriteria`](super::IoSealCriteria). -#[derive(Debug)] +#[derive(Debug, Default)] pub struct SequencerSealer { config: StateKeeperConfig, sealers: Vec>, diff --git a/core/lib/zksync_core/src/state_keeper/tests/mod.rs b/core/lib/zksync_core/src/state_keeper/tests/mod.rs index bfcfc524ffa0..1c357d72cce0 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/mod.rs @@ -5,6 +5,7 @@ use std::{ }, time::Instant, }; +use tokio::sync::watch; use multivm::{ interface::{ @@ -30,8 +31,8 @@ use zksync_types::{ mod tester; use self::tester::{ - bootloader_tip_out_of_gas, pending_batch_data, random_tx, rejected_exec, successful_exec, - successful_exec_with_metrics, TestScenario, + bootloader_tip_out_of_gas, pending_batch_data, random_tx, random_upgrade_tx, rejected_exec, + successful_exec, successful_exec_with_metrics, TestIO, TestScenario, }; pub(crate) use self::tester::{MockBatchExecutorBuilder, TestBatchExecutorBuilder}; use crate::{ @@ -44,6 +45,7 @@ use crate::{ }, types::ExecutionMetricsForCriteria, updates::UpdatesManager, + ZkSyncStateKeeper, }, utils::testonly::create_l2_transaction, }; @@ -440,6 +442,52 @@ async fn pending_batch_is_applied() { .await; } +/// Load protocol upgrade transactions +#[tokio::test] +async fn load_upgrade_tx() { + let sealer = SequencerSealer::default(); + let scenario = TestScenario::new(); + let batch_executor_base = TestBatchExecutorBuilder::new(&scenario); + let (stop_sender, stop_receiver) = watch::channel(false); + + let mut io = TestIO::new(stop_sender, scenario); + io.add_upgrade_tx(ProtocolVersionId::latest(), random_upgrade_tx(1)); + io.add_upgrade_tx(ProtocolVersionId::next(), random_upgrade_tx(2)); + + let mut sk = ZkSyncStateKeeper::new( + stop_receiver, + Box::new(io), + Box::new(batch_executor_base), + Box::new(sealer), + ); + + // Since the version hasn't changed, and we are not using shared bridge, we should not load any + // upgrade transactions. + assert_eq!( + sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::latest(), false) + .await + .unwrap(), + None + ); + + // If the protocol version has changed, we should load the upgrade transaction. + assert_eq!( + sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::next(), false) + .await + .unwrap(), + Some(random_upgrade_tx(2)) + ); + + // If we are processing the 1st batch while using the shared bridge, + // we should load the upgrade transaction -- that's the `SetChainIdUpgrade`. + assert_eq!( + sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::latest(), true) + .await + .unwrap(), + Some(random_upgrade_tx(1)) + ); +} + /// Unconditionally seal the batch without triggering specific criteria. #[tokio::test] async fn unconditional_sealing() { diff --git a/core/lib/zksync_core/src/state_keeper/tests/tester.rs b/core/lib/zksync_core/src/state_keeper/tests/tester.rs index ca65b1653260..14d5491fe8b1 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/tester.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/tester.rs @@ -233,6 +233,18 @@ pub(crate) fn random_tx(tx_number: u64) -> Transaction { tx.into() } +/// Creates a random protocol upgrade transaction. Provided tx number would be used as a transaction hash, +/// so it's easier to understand which transaction caused test to fail. +pub(crate) fn random_upgrade_tx(tx_number: u64) -> ProtocolUpgradeTx { + let mut tx = ProtocolUpgradeTx { + execute: Default::default(), + common_data: Default::default(), + received_timestamp_ms: 0, + }; + tx.common_data.canonical_tx_hash = H256::from_low_u64_be(tx_number); + tx +} + /// Creates a `TxExecutionResult` object denoting a successful tx execution. pub(crate) fn successful_exec() -> TxExecutionResult { TxExecutionResult::Success { @@ -382,7 +394,7 @@ pub(crate) struct TestBatchExecutorBuilder { } impl TestBatchExecutorBuilder { - fn new(scenario: &TestScenario) -> Self { + pub(super) fn new(scenario: &TestScenario) -> Self { let mut txs = VecDeque::new(); let mut batch_txs = HashMap::new(); let mut rollback_set = HashSet::new(); @@ -540,7 +552,7 @@ impl TestBatchExecutor { } #[derive(Debug)] -pub(crate) struct TestIO { +pub(super) struct TestIO { stop_sender: watch::Sender, batch_number: L1BatchNumber, timestamp: u64, @@ -553,10 +565,11 @@ pub(crate) struct TestIO { skipping_txs: bool, protocol_version: ProtocolVersionId, previous_batch_protocol_version: ProtocolVersionId, + protocol_upgrade_txs: HashMap, } impl TestIO { - fn new(stop_sender: watch::Sender, scenario: TestScenario) -> Self { + pub(super) fn new(stop_sender: watch::Sender, scenario: TestScenario) -> Self { Self { stop_sender, batch_number: L1BatchNumber(1), @@ -568,9 +581,14 @@ impl TestIO { skipping_txs: false, protocol_version: ProtocolVersionId::latest(), previous_batch_protocol_version: ProtocolVersionId::latest(), + protocol_upgrade_txs: HashMap::default(), } } + pub(super) fn add_upgrade_tx(&mut self, version: ProtocolVersionId, tx: ProtocolUpgradeTx) { + self.protocol_upgrade_txs.insert(version, tx); + } + fn pop_next_item(&mut self, request: &str) -> ScenarioItem { if self.scenario.actions.is_empty() { panic!( @@ -764,9 +782,9 @@ impl StateKeeperIO for TestIO { async fn load_upgrade_tx( &mut self, - _version_id: ProtocolVersionId, + version_id: ProtocolVersionId, ) -> Option { - None + self.protocol_upgrade_txs.get(&version_id).cloned() } } From e49efae5d1fa51f92227a3e002e42263ed4468c3 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 1 Feb 2024 19:39:55 +0200 Subject: [PATCH 16/37] Review suggestions --- core/lib/types/src/protocol_version.rs | 2 +- .../src/eth_sender/eth_tx_aggregator.rs | 27 +++++----- core/lib/zksync_core/src/eth_watch/tests.rs | 1 + .../zksync_core/src/state_keeper/keeper.rs | 52 +++++++++++-------- .../zksync_core/src/state_keeper/tests/mod.rs | 2 +- 5 files changed, 45 insertions(+), 39 deletions(-) diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 79f3c3c009cc..80405dc1fe8c 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -105,7 +105,7 @@ impl ProtocolVersionId { pub fn is_pre_shared_bridge(&self) -> bool { // TODO: review this when we actually deploy shared bridge - self <= &Self::Version21 + true } pub fn is_1_4_0(&self) -> bool { diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs index aa4e7d0fd0cc..e0c4a54c9623 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs @@ -405,13 +405,12 @@ impl EthTxAggregator { .encode_input(&op.into_tokens()) .expect("Failed to encode commit transaction data") } else { - let func = self - .functions + args.extend(op.into_tokens()); + self.functions .post_shared_bridge_commit .as_ref() - .expect("Missing ABI for commitBatchesSharedBridge"); - args.extend(op.into_tokens()); - func.encode_input(&args) + .expect("Missing ABI for commitBatchesSharedBridge") + .encode_input(&args) .expect("Failed to encode commit transaction data") } } @@ -422,13 +421,12 @@ impl EthTxAggregator { .encode_input(&op.into_tokens()) .expect("Failed to encode prove transaction data") } else { - let func = self - .functions + args.extend(op.into_tokens()); + self.functions .post_shared_bridge_prove .as_ref() - .expect("Missing ABI for proveBatchesSharedBridge"); - args.extend(op.into_tokens()); - func.encode_input(&args) + .expect("Missing ABI for proveBatchesSharedBridge") + .encode_input(&args) .expect("Failed to encode prove transaction data") } } @@ -439,13 +437,12 @@ impl EthTxAggregator { .encode_input(&op.into_tokens()) .expect("Failed to encode execute transaction data") } else { - let func = self - .functions + args.extend(op.into_tokens()); + self.functions .post_shared_bridge_execute .as_ref() - .expect("Missing ABI for executeBatchesSharedBridge"); - args.extend(op.into_tokens()); - func.encode_input(&args) + .expect("Missing ABI for executeBatchesSharedBridge") + .encode_input(&args) .expect("Failed to encode execute transaction data") } } diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index be68ba523dee..e42c8b69c768 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -758,6 +758,7 @@ fn upgrade_into_governor_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { } } +/// Encoding of `L2CanonicalTransaction` from IMailbox.sol. fn tx_into_token(tx: ProtocolUpgradeTx) -> Token { Token::Tuple(vec![ Token::Uint(0xfe.into()), diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index f3836e1270b0..52222fcdf582 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -253,28 +253,36 @@ impl ZkSyncStateKeeper { protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; } - let protocol_upgrade_tx = - if pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) { - tracing::info!("We have upgrade tx to be executed in empty miniblock"); - protocol_upgrade_tx - } else if !pending_miniblocks.is_empty() - && (version_changed || first_batch_in_shared_bridge) - { - // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block - // then it must be the first one in `txs_to_reexecute`. - if protocol_upgrade_tx.is_some() { - let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; - assert_eq!( - first_tx_to_reexecute.tx_format(), - TransactionType::ProtocolUpgradeTransaction - ) - } - tracing::info!("We have no upgrade tx to execute"); - None - } else { - tracing::info!("We are not changing protocol version"); - None - }; + let protocol_upgrade_tx = if pending_miniblocks.is_empty() + && (version_changed || first_batch_in_shared_bridge) + { + tracing::info!("We have upgrade tx to be executed in empty miniblock"); + assert!( + protocol_upgrade_tx.is_some(), + "Expected upgrade transaction to be present for version {:?}", + protocol_version + ); + protocol_upgrade_tx + } else if !pending_miniblocks.is_empty() + && (version_changed || first_batch_in_shared_bridge) + { + // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block + // then it must be the first one in `txs_to_reexecute`. + if protocol_upgrade_tx.is_some() { + let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; + assert_eq!( + first_tx_to_reexecute.tx_format(), + TransactionType::ProtocolUpgradeTransaction, + "Expected an upgrade transaction to be the first one in pending_miniblocks, but found {:?}", + first_tx_to_reexecute.hash() + ); + } + tracing::info!("We have no upgrade tx to execute"); + None + } else { + tracing::info!("We are not changing protocol version"); + None + }; Ok(protocol_upgrade_tx) } diff --git a/core/lib/zksync_core/src/state_keeper/tests/mod.rs b/core/lib/zksync_core/src/state_keeper/tests/mod.rs index 1c357d72cce0..2fd6559d44db 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/mod.rs @@ -5,7 +5,6 @@ use std::{ }, time::Instant, }; -use tokio::sync::watch; use multivm::{ interface::{ @@ -15,6 +14,7 @@ use multivm::{ vm_latest::{constants::BLOCK_GAS_LIMIT, VmExecutionLogs}, }; use once_cell::sync::Lazy; +use tokio::sync::watch; use zksync_config::configs::chain::StateKeeperConfig; use zksync_contracts::{BaseSystemContracts, BaseSystemContractsHashes}; use zksync_system_constants::ZKPORTER_IS_AVAILABLE; From c2788854e5a3ded2b6a22111c9f5e5b548feab5d Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 1 Feb 2024 19:59:42 +0200 Subject: [PATCH 17/37] More fixes --- core/lib/zksync_core/src/eth_watch/tests.rs | 2 +- core/lib/zksync_core/src/state_keeper/keeper.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index e42c8b69c768..f7ded7afa708 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -758,7 +758,7 @@ fn upgrade_into_governor_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { } } -/// Encoding of `L2CanonicalTransaction` from IMailbox.sol. +/// Encoding of `L2CanonicalTransaction` from `IMailbox.sol`. fn tx_into_token(tx: ProtocolUpgradeTx) -> Token { Token::Tuple(vec![ Token::Uint(0xfe.into()), diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 52222fcdf582..4da136b042e1 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -214,10 +214,8 @@ impl ZkSyncStateKeeper { .await .ok_or(Error::Canceled)?; - let version_changed_or_first_batch = - system_env.version != sealed_batch_protocol_version || first_batch_in_shared_bridge; - - protocol_upgrade_tx = if version_changed_or_first_batch { + let version_changed = system_env.version != sealed_batch_protocol_version; + protocol_upgrade_tx = if version_changed { self.io.load_upgrade_tx(system_env.version).await } else { None From 4deaeadfe44ac336b0c24b68d52a2e26bf207e91 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 2 Feb 2024 15:01:53 +0200 Subject: [PATCH 18/37] More comments --- core/lib/zksync_core/src/state_keeper/keeper.rs | 15 +++++++-------- .../lib/zksync_core/src/state_keeper/tests/mod.rs | 11 +++-------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 4da136b042e1..b3a489ffbca5 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -137,14 +137,8 @@ impl ZkSyncStateKeeper { protocol_version, ); - let first_batch_in_shared_bridge = - l1_batch_env.number == L1BatchNumber(1) && !protocol_version.is_pre_shared_bridge(); let mut protocol_upgrade_tx = self - .load_protocol_upgrade_tx( - &pending_miniblocks, - protocol_version, - first_batch_in_shared_bridge, - ) + .load_protocol_upgrade_tx(&pending_miniblocks, protocol_version, l1_batch_env.number) .await?; let mut batch_executor = self @@ -224,12 +218,17 @@ impl ZkSyncStateKeeper { Err(Error::Canceled) } + /// This function is meant to be called only once during the state-keeper initialization. + /// It will check if we should load a protocol upgrade transaction, wait for it to be picked up + /// by the event watcher if it's a `SetChainIdUpgrade`, perform some checks and return it. pub(super) async fn load_protocol_upgrade_tx( &mut self, pending_miniblocks: &[MiniblockExecutionData], protocol_version: ProtocolVersionId, - first_batch_in_shared_bridge: bool, + l1_batch_number: L1BatchNumber, ) -> Result, Error> { + let first_batch_in_shared_bridge = + l1_batch_number == L1BatchNumber(1) && !protocol_version.is_pre_shared_bridge(); let previous_batch_protocol_version = self.io.load_previous_batch_version_id().await.unwrap(); diff --git a/core/lib/zksync_core/src/state_keeper/tests/mod.rs b/core/lib/zksync_core/src/state_keeper/tests/mod.rs index 2fd6559d44db..4265b6660f72 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/mod.rs @@ -464,7 +464,7 @@ async fn load_upgrade_tx() { // Since the version hasn't changed, and we are not using shared bridge, we should not load any // upgrade transactions. assert_eq!( - sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::latest(), false) + sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::latest(), L1BatchNumber(2)) .await .unwrap(), None @@ -472,20 +472,15 @@ async fn load_upgrade_tx() { // If the protocol version has changed, we should load the upgrade transaction. assert_eq!( - sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::next(), false) + sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::next(), L1BatchNumber(2)) .await .unwrap(), Some(random_upgrade_tx(2)) ); + // TODO: add one more test case for the shared bridge after it's integrated. // If we are processing the 1st batch while using the shared bridge, // we should load the upgrade transaction -- that's the `SetChainIdUpgrade`. - assert_eq!( - sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::latest(), true) - .await - .unwrap(), - Some(random_upgrade_tx(1)) - ); } /// Unconditionally seal the batch without triggering specific criteria. From 288b569aa5994443b33648ccce0cfc8b046749cc Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Mon, 5 Feb 2024 13:53:53 +0200 Subject: [PATCH 19/37] Fix EN backward-compatibility --- core/bin/external_node/src/config/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index 289daa57f253..3cc08c35c47d 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -47,10 +47,8 @@ impl RemoteENConfig { .get_testnet_paymaster() .await .context("Failed to fetch paymaster")?; - let bridgehub_proxy_addr = client - .get_bridgehub_contract() - .await - .context("Failed to fetch L1 bridgehub contract address")?; + // In case EN is connected to the old server version without `get_bridgehub_contract` method. + let bridgehub_proxy_addr = client.get_bridgehub_contract().await.ok().flatten(); let diamond_proxy_addr = client .get_main_contract() .await From 674d1015eb5a8a64e9a386f9db52a74689e6620a Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 8 Feb 2024 14:55:46 +0200 Subject: [PATCH 20/37] Minor fixes --- core/lib/protobuf_config/src/contracts.rs | 2 +- core/lib/types/rustfmt.toml | 1 + core/lib/types/src/l2/mod.rs | 3 +- core/lib/types/src/protocol_version.rs | 190 +++++++++--------- core/lib/types/src/storage/mod.rs | 3 +- core/lib/types/src/zk_evm_types.rs | 8 +- core/lib/zksync_core/src/eth_sender/tests.rs | 2 +- .../event_processors/set_chain_id.rs | 10 +- .../eth_watch/event_processors/upgrades.rs | 7 +- .../zksync_core/src/state_keeper/keeper.rs | 31 +-- 10 files changed, 114 insertions(+), 143 deletions(-) create mode 100644 core/lib/types/rustfmt.toml diff --git a/core/lib/protobuf_config/src/contracts.rs b/core/lib/protobuf_config/src/contracts.rs index b3a121c9df3d..0a55f9b1145f 100644 --- a/core/lib/protobuf_config/src/contracts.rs +++ b/core/lib/protobuf_config/src/contracts.rs @@ -133,7 +133,7 @@ impl ProtoRepr for proto::Contracts { .as_ref() .map(|x| parse_h160(x)) .transpose() - .context("bridgeub_impl_addr")?, + .context("bridgehub_impl_addr")?, state_transition_proxy_addr: self .state_transition_proxy_addr .as_ref() diff --git a/core/lib/types/rustfmt.toml b/core/lib/types/rustfmt.toml new file mode 100644 index 000000000000..d4fcd2a3e948 --- /dev/null +++ b/core/lib/types/rustfmt.toml @@ -0,0 +1 @@ +merge_derives = false diff --git a/core/lib/types/src/l2/mod.rs b/core/lib/types/src/l2/mod.rs index 2498f3490462..a14374728e33 100644 --- a/core/lib/types/src/l2/mod.rs +++ b/core/lib/types/src/l2/mod.rs @@ -22,7 +22,8 @@ use crate::{ pub mod error; -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, TryFromPrimitive)] #[repr(u32)] pub enum TransactionType { // Native ECDSA Transaction diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 80405dc1fe8c..9ddbcc5ce379 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -17,19 +17,8 @@ use crate::{ }; #[repr(u16)] -#[derive( - Debug, - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - TryFromPrimitive, - Serialize, - Deserialize, -)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(TryFromPrimitive, Serialize, Deserialize)] pub enum ProtocolVersionId { Version0 = 0, Version1, @@ -138,9 +127,8 @@ impl TryFrom for ProtocolVersionId { } #[repr(u16)] -#[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TryFromPrimitive, Serialize, Deserialize, -)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(TryFromPrimitive, Serialize, Deserialize)] pub enum FriProtocolVersionId { Version0 = 0, Version1, @@ -434,102 +422,106 @@ impl ProtocolUpgradeTx { factory_deps: Vec, ) -> Option { let canonical_tx_hash = H256(keccak256(&encode(&[Token::Tuple(transaction.clone())]))); - assert_eq!(transaction.len(), 16); let tx_type = transaction.remove(0).into_uint().unwrap(); - if tx_type == PROTOCOL_UPGRADE_TX_TYPE.into() { - // There is an upgrade tx. Decoding it. - let sender = transaction.remove(0).into_uint().unwrap(); - let sender = u256_to_account_address(&sender); + if tx_type == U256::zero() { + // There is no upgrade tx. + return None; + } - let contract_address = transaction.remove(0).into_uint().unwrap(); - let contract_address = u256_to_account_address(&contract_address); + assert_eq!( + tx_type, + PROTOCOL_UPGRADE_TX_TYPE.into(), + "Unexpected tx type {} when decoding upgrade", + tx_type + ); - let gas_limit = transaction.remove(0).into_uint().unwrap(); + // There is an upgrade tx. Decoding it. + let sender = transaction.remove(0).into_uint().unwrap(); + let sender = u256_to_account_address(&sender); - let gas_per_pubdata_limit = transaction.remove(0).into_uint().unwrap(); + let contract_address = transaction.remove(0).into_uint().unwrap(); + let contract_address = u256_to_account_address(&contract_address); - let max_fee_per_gas = transaction.remove(0).into_uint().unwrap(); + let gas_limit = transaction.remove(0).into_uint().unwrap(); - let max_priority_fee_per_gas = transaction.remove(0).into_uint().unwrap(); - assert_eq!(max_priority_fee_per_gas, U256::zero()); + let gas_per_pubdata_limit = transaction.remove(0).into_uint().unwrap(); - let paymaster = transaction.remove(0).into_uint().unwrap(); - let paymaster = u256_to_account_address(&paymaster); - assert_eq!(paymaster, Address::zero()); + let max_fee_per_gas = transaction.remove(0).into_uint().unwrap(); - let upgrade_id = transaction.remove(0).into_uint().unwrap(); + let max_priority_fee_per_gas = transaction.remove(0).into_uint().unwrap(); + assert_eq!(max_priority_fee_per_gas, U256::zero()); - let msg_value = transaction.remove(0).into_uint().unwrap(); + let paymaster = transaction.remove(0).into_uint().unwrap(); + let paymaster = u256_to_account_address(&paymaster); + assert_eq!(paymaster, Address::zero()); - let reserved = transaction - .remove(0) - .into_fixed_array() - .unwrap() - .into_iter() - .map(|token| token.into_uint().unwrap()) - .collect::>(); - assert_eq!(reserved.len(), 4); - - let to_mint = reserved[0]; - let refund_recipient = u256_to_account_address(&reserved[1]); - - // All other reserved fields should be zero - for item in reserved.iter().skip(2) { - assert_eq!(item, &U256::zero()); - } - - let calldata = transaction.remove(0).into_bytes().unwrap(); - - let signature = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(signature.len(), 0); - - let _factory_deps_hashes = transaction.remove(0).into_array().unwrap(); - - let paymaster_input = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(paymaster_input.len(), 0); - - // TODO (SMA-1621): check that `reservedDynamic` are constructed correctly. - let reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(reserved_dynamic.len(), 0); - - let common_data = ProtocolUpgradeTxCommonData { - canonical_tx_hash, - sender, - upgrade_id: (upgrade_id.as_u32() as u16).try_into().unwrap(), - to_mint, - refund_recipient, - gas_limit, - max_fee_per_gas, - gas_per_pubdata_limit, - eth_hash, - eth_block, - }; - - let factory_deps = factory_deps - .into_iter() - .map(|t| t.into_bytes().unwrap()) - .collect(); - - let execute = Execute { - contract_address, - calldata: calldata.to_vec(), - factory_deps: Some(factory_deps), - value: msg_value, - }; - - Some(ProtocolUpgradeTx { - common_data, - execute, - received_timestamp_ms: unix_timestamp_ms(), - }) - } else if tx_type == U256::zero() { - // There is no upgrade tx. - None - } else { - panic!("Unexpected tx type {} when decoding upgrade", tx_type); + let upgrade_id = transaction.remove(0).into_uint().unwrap(); + + let msg_value = transaction.remove(0).into_uint().unwrap(); + + let reserved = transaction + .remove(0) + .into_fixed_array() + .unwrap() + .into_iter() + .map(|token| token.into_uint().unwrap()) + .collect::>(); + assert_eq!(reserved.len(), 4); + + let to_mint = reserved[0]; + let refund_recipient = u256_to_account_address(&reserved[1]); + + // All other reserved fields should be zero + for item in reserved.iter().skip(2) { + assert_eq!(item, &U256::zero()); } + + let calldata = transaction.remove(0).into_bytes().unwrap(); + + let signature = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(signature.len(), 0); + + let _factory_deps_hashes = transaction.remove(0).into_array().unwrap(); + + let paymaster_input = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(paymaster_input.len(), 0); + + // TODO (SMA-1621): check that `reservedDynamic` are constructed correctly. + let reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(reserved_dynamic.len(), 0); + + let common_data = ProtocolUpgradeTxCommonData { + canonical_tx_hash, + sender, + upgrade_id: (upgrade_id.as_u32() as u16).try_into().unwrap(), + to_mint, + refund_recipient, + gas_limit, + max_fee_per_gas, + gas_per_pubdata_limit, + eth_hash, + eth_block, + }; + + let factory_deps = factory_deps + .into_iter() + .map(|t| t.into_bytes().unwrap()) + .collect(); + + let execute = Execute { + contract_address, + calldata: calldata.to_vec(), + factory_deps: Some(factory_deps), + value: msg_value, + }; + + Some(ProtocolUpgradeTx { + common_data, + execute, + received_timestamp_ms: unix_timestamp_ms(), + }) } } diff --git a/core/lib/types/src/storage/mod.rs b/core/lib/types/src/storage/mod.rs index 54694f63c504..9d558d013fa0 100644 --- a/core/lib/types/src/storage/mod.rs +++ b/core/lib/types/src/storage/mod.rs @@ -15,7 +15,8 @@ pub use zksync_system_constants::*; use zksync_utils::address_to_h256; /// Typed fully qualified key of the storage slot in global state tree. -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Serialize, Deserialize)] pub struct StorageKey { account: AccountTreeId, key: H256, diff --git a/core/lib/types/src/zk_evm_types.rs b/core/lib/types/src/zk_evm_types.rs index a7973ab36fec..f165df0c57f5 100644 --- a/core/lib/types/src/zk_evm_types.rs +++ b/core/lib/types/src/zk_evm_types.rs @@ -1,3 +1,4 @@ +use serde::{Deserialize, Serialize}; use zksync_basic_types::{Address, U256}; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -9,12 +10,11 @@ pub enum FarCallOpcode { } /// Struct representing the VM timestamp -#[derive( - Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, PartialOrd, Ord, -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Serialize, Deserialize)] pub struct Timestamp(pub u32); -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct LogQuery { pub timestamp: Timestamp, pub tx_number_in_block: u16, diff --git a/core/lib/zksync_core/src/eth_sender/tests.rs b/core/lib/zksync_core/src/eth_sender/tests.rs index 63b766c8d7c8..cc35aae231da 100644 --- a/core/lib/zksync_core/src/eth_sender/tests.rs +++ b/core/lib/zksync_core/src/eth_sender/tests.rs @@ -111,7 +111,7 @@ impl EthSenderTester { Address::random(), contracts_config.l1_multicall3_addr, Address::random(), - 270.into(), + Default::default(), ) .await; diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs index 523f8e36ab36..35233399cab5 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs @@ -52,14 +52,8 @@ impl EventProcessor for SetChainIDEventProcessor { return Ok(()); } - let ids_str: Vec<_> = upgrades - .iter() - .map(|(id, _tx)| format!("{}", *id as u16)) - .collect(); - tracing::debug!( - "Received setChainId upgrade with version_id: {}", - ids_str.join(", ") - ); + let ids: Vec<_> = upgrades.iter().map(|(id, _tx)| *id as u16).collect(); + tracing::debug!("Received setChainId upgrade with version_id: {:?}", ids); let stage_latency = METRICS.poll_eth_node[&PollStage::PersistUpgrades].start(); for (version_id, tx) in upgrades { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs index e7f906cdf070..a98321988907 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs @@ -56,11 +56,8 @@ impl EventProcessor for UpgradesEventProcessor { return Ok(()); } - let ids_str: Vec<_> = upgrades - .iter() - .map(|(u, _)| format!("{}", u.id as u16)) - .collect(); - tracing::debug!("Received upgrades with ids: {}", ids_str.join(", ")); + let ids: Vec<_> = upgrades.iter().map(|(u, _)| u.id as u16).collect(); + tracing::debug!("Received upgrades with ids: {:?}", ids); let new_upgrades: Vec<_> = upgrades .into_iter() diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index b3a489ffbca5..7076a247a951 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -219,46 +219,31 @@ impl ZkSyncStateKeeper { } /// This function is meant to be called only once during the state-keeper initialization. - /// It will check if we should load a protocol upgrade transaction, wait for it to be picked up - /// by the event watcher if it's a `SetChainIdUpgrade`, perform some checks and return it. + /// It will check if we should load a protocol upgrade or a `setChainId` transaction, + /// perform some checks and return it. pub(super) async fn load_protocol_upgrade_tx( &mut self, pending_miniblocks: &[MiniblockExecutionData], protocol_version: ProtocolVersionId, l1_batch_number: L1BatchNumber, ) -> Result, Error> { + // After the Shared Bridge is integrated, + // there has to be a setChainId upgrade transaction after the chain genesis. + // It has to be the first transaction of the first batch. + // The setChainId upgrade does not bump the protocol version, but attaches an upgrade + // transaction to the genesis protocol version version. let first_batch_in_shared_bridge = l1_batch_number == L1BatchNumber(1) && !protocol_version.is_pre_shared_bridge(); let previous_batch_protocol_version = self.io.load_previous_batch_version_id().await.unwrap(); let version_changed = protocol_version != previous_batch_protocol_version; - let mut protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; - - // After the Shared Bridge is integrated, - // there has to be a setChainId upgrade transaction after the chain genesis. - // It has to be the first transaction of the first batch. - // If it's not present, we have to wait for it to be picked up by the event watcher. - // The setChainId upgrade does not bump the protocol version, rather attaches an upgrade - // transaction to the genesis protocol version. - while first_batch_in_shared_bridge && protocol_upgrade_tx.is_none() { - tracing::info!("Waiting for setChainId upgrade transaction to be picked up"); - if self.is_canceled() { - return Err(Error::Canceled); - } - tokio::time::sleep(Duration::from_secs(1)).await; - protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; - } + let protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; let protocol_upgrade_tx = if pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) { tracing::info!("We have upgrade tx to be executed in empty miniblock"); - assert!( - protocol_upgrade_tx.is_some(), - "Expected upgrade transaction to be present for version {:?}", - protocol_version - ); protocol_upgrade_tx } else if !pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) From b04051f276dfd77a51ed6e8515922f22a7cedc5f Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Thu, 8 Feb 2024 20:29:50 +0200 Subject: [PATCH 21/37] Refactor eth_watch a bit --- .../event_processors/governance_upgrades.rs | 22 +++--- .../src/eth_watch/event_processors/mod.rs | 4 +- .../event_processors/priority_ops.rs | 9 +-- .../event_processors/set_chain_id.rs | 7 +- .../eth_watch/event_processors/upgrades.rs | 18 +++-- core/lib/zksync_core/src/eth_watch/mod.rs | 69 ++++++++++++++----- 6 files changed, 79 insertions(+), 50 deletions(-) diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs index 6008f4a05e96..c849001add89 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs @@ -44,7 +44,7 @@ impl EventProcessor for GovernanceUpgradesEventProcessor { storage: &mut StorageProcessor<'_>, client: &dyn EthClient, events: Vec, - ) -> Result<(), Error> { + ) -> Result { let mut upgrades = Vec::new(); for event in events .into_iter() @@ -76,22 +76,17 @@ impl EventProcessor for GovernanceUpgradesEventProcessor { } } - if upgrades.is_empty() { - return Ok(()); - } - - let ids_str: Vec<_> = upgrades - .iter() - .map(|(u, _)| format!("{}", u.id as u16)) - .collect(); - tracing::debug!("Received upgrades with ids: {}", ids_str.join(", ")); - let new_upgrades: Vec<_> = upgrades .into_iter() .skip_while(|(v, _)| v.id as u16 <= self.last_seen_version_id as u16) .collect(); + + let new_upgrades_count = new_upgrades.len(); + let ids: Vec<_> = new_upgrades.iter().map(|(u, _)| u.id as u16).collect(); + tracing::debug!("Received new upgrades with ids: {:?}", ids); + if new_upgrades.is_empty() { - return Ok(()); + return Ok(0); } let last_id = new_upgrades.last().unwrap().0.id; @@ -116,8 +111,7 @@ impl EventProcessor for GovernanceUpgradesEventProcessor { metrics::histogram!("eth_watcher.poll_eth_node", stage_start.elapsed(), "stage" => "persist_upgrades"); self.last_seen_version_id = last_id; - - Ok(()) + Ok(new_upgrades_count) } fn relevant_topic(&self) -> H256 { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs index 2d80d6ebed75..2ca99ae3acc6 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs @@ -12,13 +12,13 @@ pub mod upgrades; #[async_trait::async_trait] pub trait EventProcessor: 'static + fmt::Debug + Send + Sync { - /// Processes given events + /// Processes given events. If `Ok`, returns the number of processed events of interest. async fn process_events( &mut self, storage: &mut StorageProcessor<'_>, client: &dyn EthClient, events: Vec, - ) -> Result<(), Error>; + ) -> Result; /// Relevant topic which defines what events to be processed fn relevant_topic(&self) -> H256; diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs b/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs index ad24eba1791b..331d29c3c053 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs @@ -39,7 +39,7 @@ impl EventProcessor for PriorityOpsEventProcessor { storage: &mut StorageProcessor<'_>, _client: &dyn EthClient, events: Vec, - ) -> Result<(), Error> { + ) -> Result { let mut priority_ops = Vec::new(); for event in events .into_iter() @@ -50,7 +50,7 @@ impl EventProcessor for PriorityOpsEventProcessor { } if priority_ops.is_empty() { - return Ok(()); + return Ok(0); } let first = &priority_ops[0]; @@ -72,8 +72,9 @@ impl EventProcessor for PriorityOpsEventProcessor { .into_iter() .skip_while(|tx| tx.serial_id() < self.next_expected_priority_id) .collect(); + let new_ops_count = new_ops.len(); if new_ops.is_empty() { - return Ok(()); + return Ok(0); } let first_new = &new_ops[0]; @@ -96,7 +97,7 @@ impl EventProcessor for PriorityOpsEventProcessor { } stage_latency.observe(); self.next_expected_priority_id = last_new.serial_id().next(); - Ok(()) + Ok(new_ops_count) } fn relevant_topic(&self) -> H256 { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs index 35233399cab5..f832f4b15d3a 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs @@ -34,7 +34,7 @@ impl EventProcessor for SetChainIDEventProcessor { storage: &mut StorageProcessor<'_>, _client: &dyn EthClient, events: Vec, - ) -> Result<(), Error> { + ) -> Result { // SetChainId does not go through the governance contract, so we need to parse it separately. let upgrades = events .into_iter() @@ -48,8 +48,9 @@ impl EventProcessor for SetChainIDEventProcessor { }) .collect::, _>>()?; + let upgrades_count = upgrades.len(); if upgrades.is_empty() { - return Ok(()); + return Ok(0); } let ids: Vec<_> = upgrades.iter().map(|(id, _tx)| *id as u16).collect(); @@ -63,7 +64,7 @@ impl EventProcessor for SetChainIDEventProcessor { .await; } stage_latency.observe(); - Ok(()) + Ok(upgrades_count) } fn relevant_topic(&self) -> H256 { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs index a98321988907..a2bd65c3d0d4 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs @@ -35,7 +35,7 @@ impl EventProcessor for UpgradesEventProcessor { storage: &mut StorageProcessor<'_>, client: &dyn EthClient, events: Vec, - ) -> Result<(), Error> { + ) -> Result { let mut upgrades = Vec::new(); for event in events .into_iter() @@ -52,19 +52,17 @@ impl EventProcessor for UpgradesEventProcessor { upgrades.push((upgrade, scheduler_vk_hash)); } - if upgrades.is_empty() { - return Ok(()); - } - - let ids: Vec<_> = upgrades.iter().map(|(u, _)| u.id as u16).collect(); - tracing::debug!("Received upgrades with ids: {:?}", ids); - let new_upgrades: Vec<_> = upgrades .into_iter() .skip_while(|(v, _)| v.id as u16 <= self.last_seen_version_id as u16) .collect(); + let new_upgrades_count = new_upgrades.len(); + + let ids: Vec<_> = new_upgrades.iter().map(|(u, _)| u.id as u16).collect(); + tracing::debug!("Received new upgrades with ids: {:?}", ids); + if new_upgrades.is_empty() { - return Ok(()); + return Ok(0); } let last_id = new_upgrades.last().unwrap().0.id; @@ -83,7 +81,7 @@ impl EventProcessor for UpgradesEventProcessor { } stage_latency.observe(); self.last_seen_version_id = last_id; - Ok(()) + Ok(new_upgrades_count) } fn relevant_topic(&self) -> H256 { diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index 3eb9cce74a44..0b7e02cb743d 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -65,11 +65,11 @@ impl EthWatch { let priority_ops_processor = PriorityOpsEventProcessor::new(state.next_expected_priority_id); let upgrades_processor = UpgradesEventProcessor::new(state.last_seen_version_id); - let set_chain_id_processor = SetChainIDEventProcessor::new(diamond_proxy_address); + // let set_chain_id_processor = SetChainIDEventProcessor::new(diamond_proxy_address); let mut event_processors: Vec> = vec![ Box::new(priority_ops_processor), Box::new(upgrades_processor), - Box::new(set_chain_id_processor), + // Box::new(set_chain_id_processor), ]; if let Some(governance_contract) = governance_contract { @@ -95,6 +95,31 @@ impl EthWatch { } } + /// EthWatch is only meant to be created this way during genesis, since + /// we only need to save the `setChainId` event once -- after the chain creation. + pub async fn new_set_chain_id_watch( + diamond_proxy_address: Address, + mut client: Box, + poll_interval: Duration, + ) -> Self { + // To be safe, scan the last 50k blocks. + let last_processed_ethereum_block = client + .finalized_block_number() + .await + .expect("cannot initialize eth watch: cannot get current ETH block") + .saturating_sub(PRIORITY_EXPIRATION); + + let set_chain_id_processor = SetChainIDEventProcessor::new(diamond_proxy_address); + client.set_topics(vec![set_chain_id_processor.relevant_topic()]); + + Self { + client, + poll_interval, + event_processors: vec![Box::new(set_chain_id_processor)], + last_processed_ethereum_block, + } + } + async fn initialize_state( client: &dyn EthClient, storage: &mut StorageProcessor<'_>, @@ -134,13 +159,15 @@ impl EthWatch { } } - pub async fn run( + async fn run( &mut self, pool: ConnectionPool, stop_receiver: watch::Receiver, + limit: Option, ) -> anyhow::Result<()> { let mut timer = tokio::time::interval(self.poll_interval); - loop { + let mut processed_events = 0; + while limit.map(|l| processed_events < l).unwrap_or(true) { if *stop_receiver.borrow() { tracing::info!("Stop signal received, eth_watch is shutting down"); break; @@ -150,25 +177,32 @@ impl EthWatch { METRICS.eth_poll.inc(); let mut storage = pool.access_storage_tagged("eth_watch").await.unwrap(); - if let Err(error) = self.loop_iteration(&mut storage).await { - // This is an error because otherwise we could potentially miss a priority operation - // thus entering priority mode, which is not desired. - tracing::error!("Failed to process new blocks {}", error); - self.last_processed_ethereum_block = - Self::initialize_state(&*self.client, &mut storage) - .await - .last_processed_ethereum_block; + match self.loop_iteration(&mut storage).await { + Ok(events) => { + tracing::info!("Processed {:?} events", events); + processed_events += events; + } + Err(error) => { + // This is an error because otherwise we could potentially miss a priority operation + // thus entering priority mode, which is not desired. + tracing::error!("Failed to process new blocks {}", error); + self.last_processed_ethereum_block = + Self::initialize_state(&*self.client, &mut storage) + .await + .last_processed_ethereum_block; + } } } Ok(()) } + /// If `Ok`, returns the number of processed events. #[tracing::instrument(skip(self, storage))] - async fn loop_iteration(&mut self, storage: &mut StorageProcessor<'_>) -> Result<(), Error> { + async fn loop_iteration(&mut self, storage: &mut StorageProcessor<'_>) -> Result { let stage_latency = METRICS.poll_eth_node[&PollStage::Request].start(); let to_block = self.client.finalized_block_number().await?; if to_block <= self.last_processed_ethereum_block { - return Ok(()); + return Ok(0); } let events = self @@ -181,13 +215,14 @@ impl EthWatch { .await?; stage_latency.observe(); + let mut processed_events = 0; for processor in self.event_processors.iter_mut() { - processor + processed_events += processor .process_events(storage, &*self.client, events.clone()) .await?; } self.last_processed_ethereum_block = to_block; - Ok(()) + Ok(processed_events) } } @@ -218,6 +253,6 @@ pub async fn start_eth_watch( .await; Ok(tokio::spawn(async move { - eth_watch.run(pool, stop_receiver).await + eth_watch.run(pool, stop_receiver, None).await })) } From 966283c1df488f4ed67a46d807be670d76dca2f2 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 02:29:21 +0200 Subject: [PATCH 22/37] Wait for setChainId during genesis --- core/bin/zksync_server/src/main.rs | 7 ++++++ core/lib/zksync_core/src/eth_watch/mod.rs | 29 +++++++++++++++++++++++ core/lib/zksync_core/src/lib.rs | 20 ++++++++++++++-- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/core/bin/zksync_server/src/main.rs b/core/bin/zksync_server/src/main.rs index f9f18a11c05c..4979f2514609 100644 --- a/core/bin/zksync_server/src/main.rs +++ b/core/bin/zksync_server/src/main.rs @@ -37,6 +37,10 @@ struct Cli { /// Generate genesis block for the first contract deployment using temporary DB. #[arg(long)] genesis: bool, + /// Wait for the `setChainId` event during genesis. + /// If `--genesis` is not set, this flag is ignored. + #[arg(long)] + set_chain_id: bool, /// Rebuild tree. #[arg(long)] rebuild_tree: bool, @@ -136,12 +140,15 @@ async fn main() -> anyhow::Result<()> { let eth_sender = ETHSenderConfig::from_env().context("ETHSenderConfig")?; let contracts = ContractsConfig::from_env().context("ContractsConfig")?; let eth_client = ETHClientConfig::from_env().context("EthClientConfig")?; + let eth_watch = ETHWatchConfig::from_env().context("EthWatchConfig")?; genesis_init( &postgres_config, ð_sender, &network, &contracts, + ð_watch, ð_client.web3_url, + opt.set_chain_id, ) .await .context("genesis_init")?; diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index 0b7e02cb743d..e157d14f417e 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -226,6 +226,35 @@ impl EthWatch { } } +/// This method creates an `EthWatch` instance that only looks for the `setChainId` event and runs +/// it. Once the event is found and the tx is saved into the db, it will exit. +pub async fn wait_for_set_chain_id( + config: ETHWatchConfig, + pool: ConnectionPool, + eth_gateway: Box, + diamond_proxy_addr: Address, + state_transition_manager_addr: Address, +) -> anyhow::Result<()> { + let eth_client = EthHttpQueryClient::new( + eth_gateway, + diamond_proxy_addr, + Some(state_transition_manager_addr), + None, + config.confirmations_for_eth_event, + ); + + let mut eth_watch = EthWatch::new_set_chain_id_watch( + diamond_proxy_addr, + Box::new(eth_client), + config.poll_interval(), + ) + .await; + + let (_stop_sender, stop_receiver) = watch::channel(false); + // We want to exit after 1 event is found, hence the limit is `Some(1)`. + eth_watch.run(pool, stop_receiver, Some(1)).await +} + pub async fn start_eth_watch( config: ETHWatchConfig, pool: ConnectionPool, diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index f6f550d09f75..a6af4a1d4424 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -23,7 +23,7 @@ use zksync_config::{ contracts::ProverAtGenesis, database::{MerkleTreeConfig, MerkleTreeMode}, }, - ApiConfig, ContractsConfig, DBConfig, ETHSenderConfig, PostgresConfig, + ApiConfig, ContractsConfig, DBConfig, ETHSenderConfig, ETHWatchConfig, PostgresConfig, }; use zksync_contracts::{governance_contract, BaseSystemContracts}; use zksync_dal::{healthcheck::ConnectionPoolHealthCheck, ConnectionPool}; @@ -102,7 +102,9 @@ pub async fn genesis_init( eth_sender: ÐSenderConfig, network_config: &NetworkConfig, contracts_config: &ContractsConfig, + ethwatch_config: ÐWatchConfig, eth_client_url: &str, + wait_for_set_chain_id: bool, ) -> anyhow::Result<()> { let db_url = postgres_config.master_url()?; let pool = ConnectionPool::singleton(db_url) @@ -117,6 +119,7 @@ pub async fn genesis_init( .context("Private key is required for genesis init")?, ) .context("Failed to restore operator address from private key")?; + let eth_client = QueryClient::new(eth_client_url)?; // Select the first prover to be used during genesis. // Later we can change provers using the system upgrades, but for genesis @@ -132,7 +135,6 @@ pub async fn genesis_init( recursion_scheduler_level_vk_hash: contracts_config.snark_wrapper_vk_hash, }; - let eth_client = QueryClient::new(eth_client_url)?; let args = CallFunctionArgs::new("verificationKeyHash", ()).for_contract( contracts_config.verifier_addr, zksync_contracts::verifier_contract(), @@ -174,6 +176,20 @@ pub async fn genesis_init( }, ) .await?; + + if wait_for_set_chain_id { + eth_watch::wait_for_set_chain_id( + ethwatch_config.clone(), + pool.clone(), + Box::new(eth_client), + contracts_config.diamond_proxy_addr, + contracts_config + .state_transition_proxy_addr + .expect("state_transition_proxy_addr is not set, but needed for genesis"), + ) + .await?; + } + Ok(()) } From d0356a27f8755b817e84793c0f2b32c080cd446a Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 02:36:28 +0200 Subject: [PATCH 23/37] Fix eth-watch test --- core/lib/zksync_core/src/eth_watch/mod.rs | 2 -- core/lib/zksync_core/src/eth_watch/tests.rs | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index e157d14f417e..06dd9bc47e5f 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -65,11 +65,9 @@ impl EthWatch { let priority_ops_processor = PriorityOpsEventProcessor::new(state.next_expected_priority_id); let upgrades_processor = UpgradesEventProcessor::new(state.last_seen_version_id); - // let set_chain_id_processor = SetChainIDEventProcessor::new(diamond_proxy_address); let mut event_processors: Vec> = vec![ Box::new(priority_ops_processor), Box::new(upgrades_processor), - // Box::new(set_chain_id_processor), ]; if let Some(governance_contract) = governance_contract { diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index f7ded7afa708..47c7cc2e9211 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -557,11 +557,9 @@ async fn test_set_chain_id_upgrade() { let mut storage = connection_pool.access_storage().await.unwrap(); let mut client = FakeEthClient::new(); - let mut watcher = EthWatch::new( + let mut watcher = EthWatch::new_set_chain_id_watch( diamond_proxy_address, - None, Box::new(client.clone()), - &connection_pool, std::time::Duration::from_nanos(1), ) .await; From 01d3ebf999b681157e5e19d75f0cbc63e50242a9 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 09:53:16 +0200 Subject: [PATCH 24/37] Fix sqlx --- ...b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json} | 4 ++-- ...6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json} | 4 ++-- core/lib/zksync_core/src/eth_watch/mod.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename core/lib/dal/.sqlx/{query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json => query-2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json} (74%) rename core/lib/dal/.sqlx/{query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json => query-ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json} (71%) diff --git a/core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json b/core/lib/dal/.sqlx/query-2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json similarity index 74% rename from core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json rename to core/lib/dal/.sqlx/query-2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json index 4b69afd7e9cd..b6d026081cf8 100644 --- a/core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json +++ b/core/lib/dal/.sqlx/query-2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE miniblocks\n SET\n fee_account_address = (\n SELECT\n l1_batches.fee_account_address\n FROM\n l1_batches\n ORDER BY\n l1_batches.number DESC\n LIMIT\n 1\n )\n WHERE\n l1_batch_number IS NULL\n AND fee_account_address = '\\x0000000000000000000000000000000000000000'::bytea\n ", + "query": "\n UPDATE miniblocks\n SET\n fee_account_address = (\n SELECT\n l1_batches.fee_account_address\n FROM\n l1_batches\n ORDER BY\n l1_batches.number DESC\n LIMIT\n 1\n )\n WHERE\n l1_batch_number IS NULL\n AND fee_account_address = 'x0000000000000000000000000000000000000000'::bytea\n ", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df" + "hash": "2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65" } diff --git a/core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json b/core/lib/dal/.sqlx/query-ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json similarity index 71% rename from core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json rename to core/lib/dal/.sqlx/query-ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json index 2e83c0036b95..6e301ac63237 100644 --- a/core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json +++ b/core/lib/dal/.sqlx/query-ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE miniblocks\n SET\n fee_account_address = l1_batches.fee_account_address\n FROM\n l1_batches\n WHERE\n l1_batches.number = miniblocks.l1_batch_number\n AND miniblocks.number BETWEEN $1 AND $2\n AND miniblocks.fee_account_address = '\\x0000000000000000000000000000000000000000'::bytea\n ", + "query": "\n UPDATE miniblocks\n SET\n fee_account_address = l1_batches.fee_account_address\n FROM\n l1_batches\n WHERE\n l1_batches.number = miniblocks.l1_batch_number\n AND miniblocks.number BETWEEN $1 AND $2\n AND miniblocks.fee_account_address = 'x0000000000000000000000000000000000000000'::bytea\n ", "describe": { "columns": [], "parameters": { @@ -11,5 +11,5 @@ }, "nullable": [] }, - "hash": "08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf" + "hash": "ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff" } diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index 06dd9bc47e5f..a81322513c1c 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -93,7 +93,7 @@ impl EthWatch { } } - /// EthWatch is only meant to be created this way during genesis, since + /// `EthWatch` is only meant to be created this way during genesis, since /// we only need to save the `setChainId` event once -- after the chain creation. pub async fn new_set_chain_id_watch( diamond_proxy_address: Address, From 98f63c48eb0bdf53ff61bef56acb5a9cf4148d79 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 10:43:01 +0200 Subject: [PATCH 25/37] Fix after merge --- ...067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json} | 4 ++-- ...e720673485e3b59c116162becce06841476128f864b6028129df.json} | 4 ++-- core/lib/dal/src/blocks_dal.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename core/lib/dal/.sqlx/{query-ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json => query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json} (71%) rename core/lib/dal/.sqlx/{query-2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json => query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json} (74%) diff --git a/core/lib/dal/.sqlx/query-ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json b/core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json similarity index 71% rename from core/lib/dal/.sqlx/query-ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json rename to core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json index 6e301ac63237..2e83c0036b95 100644 --- a/core/lib/dal/.sqlx/query-ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff.json +++ b/core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE miniblocks\n SET\n fee_account_address = l1_batches.fee_account_address\n FROM\n l1_batches\n WHERE\n l1_batches.number = miniblocks.l1_batch_number\n AND miniblocks.number BETWEEN $1 AND $2\n AND miniblocks.fee_account_address = 'x0000000000000000000000000000000000000000'::bytea\n ", + "query": "\n UPDATE miniblocks\n SET\n fee_account_address = l1_batches.fee_account_address\n FROM\n l1_batches\n WHERE\n l1_batches.number = miniblocks.l1_batch_number\n AND miniblocks.number BETWEEN $1 AND $2\n AND miniblocks.fee_account_address = '\\x0000000000000000000000000000000000000000'::bytea\n ", "describe": { "columns": [], "parameters": { @@ -11,5 +11,5 @@ }, "nullable": [] }, - "hash": "ecd925393f2c6b5722ec5f126afa428c6c4b5ce38b38db2dedf9b374269de7ff" + "hash": "08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf" } diff --git a/core/lib/dal/.sqlx/query-2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json b/core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json similarity index 74% rename from core/lib/dal/.sqlx/query-2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json rename to core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json index b6d026081cf8..4b69afd7e9cd 100644 --- a/core/lib/dal/.sqlx/query-2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65.json +++ b/core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE miniblocks\n SET\n fee_account_address = (\n SELECT\n l1_batches.fee_account_address\n FROM\n l1_batches\n ORDER BY\n l1_batches.number DESC\n LIMIT\n 1\n )\n WHERE\n l1_batch_number IS NULL\n AND fee_account_address = 'x0000000000000000000000000000000000000000'::bytea\n ", + "query": "\n UPDATE miniblocks\n SET\n fee_account_address = (\n SELECT\n l1_batches.fee_account_address\n FROM\n l1_batches\n ORDER BY\n l1_batches.number DESC\n LIMIT\n 1\n )\n WHERE\n l1_batch_number IS NULL\n AND fee_account_address = '\\x0000000000000000000000000000000000000000'::bytea\n ", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "2532a8617823b170a24d1614c66175f8b667e3b38bdaca60863f1ce6ecc5ca65" + "hash": "c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df" } diff --git a/core/lib/dal/src/blocks_dal.rs b/core/lib/dal/src/blocks_dal.rs index ee5306744852..ee7598d6ed30 100644 --- a/core/lib/dal/src/blocks_dal.rs +++ b/core/lib/dal/src/blocks_dal.rs @@ -2218,7 +2218,7 @@ impl BlocksDal<'_, '_> { ) WHERE l1_batch_number IS NULL - AND fee_account_address = 'x0000000000000000000000000000000000000000'::bytea + AND fee_account_address = '\x0000000000000000000000000000000000000000'::bytea "# ) .execute(self.storage.conn()) @@ -2258,7 +2258,7 @@ impl BlocksDal<'_, '_> { WHERE l1_batches.number = miniblocks.l1_batch_number AND miniblocks.number BETWEEN $1 AND $2 - AND miniblocks.fee_account_address = 'x0000000000000000000000000000000000000000'::bytea + AND miniblocks.fee_account_address = '\x0000000000000000000000000000000000000000'::bytea "#, numbers.start().0 as i64, numbers.end().0 as i64 From 6dc68f12dd1f32e62f67beea4eee4a1de5bd8d56 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 11:11:28 +0200 Subject: [PATCH 26/37] cargo-deny fix --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12077df924b9..4daadd69bc20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6159,9 +6159,9 @@ dependencies = [ [[package]] name = "snow" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58021967fd0a5eeeb23b08df6cc244a4d4a5b4aec1d27c9e02fad1a58b4cd74e" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" dependencies = [ "aes-gcm", "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", From c30bb70555ccf2389f0414184c491fbc22ca6f03 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 15:55:27 +0200 Subject: [PATCH 27/37] Fix nits --- core/lib/dal/src/protocol_versions_dal.rs | 4 ++-- core/lib/zksync_core/src/eth_watch/mod.rs | 2 +- core/lib/zksync_core/src/state_keeper/keeper.rs | 13 +++++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index f0ed4a1aee4b..0c88e97a77df 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -98,7 +98,7 @@ impl ProtocolVersionsDal<'_, '_> { db_transaction.commit().await.unwrap(); } - async fn save_genesis_upgrade(&mut self, id: ProtocolVersionId, tx_hash: Option) { + async fn save_genesis_upgrade_tx_hash(&mut self, id: ProtocolVersionId, tx_hash: Option) { sqlx::query!( r#" UPDATE protocol_versions @@ -133,7 +133,7 @@ impl ProtocolVersionsDal<'_, '_> { db_transaction .protocol_versions_dal() - .save_genesis_upgrade(id, tx_hash) + .save_genesis_upgrade_tx_hash(id, tx_hash) .await; db_transaction.commit().await.unwrap(); diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index a81322513c1c..c793fe7108ee 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -95,7 +95,7 @@ impl EthWatch { /// `EthWatch` is only meant to be created this way during genesis, since /// we only need to save the `setChainId` event once -- after the chain creation. - pub async fn new_set_chain_id_watch( + async fn new_set_chain_id_watch( diamond_proxy_address: Address, mut client: Box, poll_interval: Duration, diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index b25a816deed7..b3359e86ddb6 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -150,7 +150,7 @@ impl ZkSyncStateKeeper { let protocol_version = system_env.version; let mut updates_manager = UpdatesManager::new(&l1_batch_env, &system_env); - let mut protocol_upgrade_tx = self + let mut protocol_upgrade_tx: Option = self .load_protocol_upgrade_tx(&pending_miniblocks, protocol_version, l1_batch_env.number) .await?; @@ -250,11 +250,13 @@ impl ZkSyncStateKeeper { let protocol_upgrade_tx = if pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) { - tracing::info!("We have upgrade tx to be executed in empty miniblock"); + // We have a new upgrade transaction - either a regular protocol upgrade or a `setChainId` upgrade. + tracing::info!("There is an new upgrade tx to be executed in this batch"); protocol_upgrade_tx } else if !pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) { + // We already processed the upgrade tx but did not seal the batch it was in. // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block // then it must be the first one in `txs_to_reexecute`. if protocol_upgrade_tx.is_some() { @@ -266,10 +268,13 @@ impl ZkSyncStateKeeper { first_tx_to_reexecute.hash() ); } - tracing::info!("We have no upgrade tx to execute"); + tracing::info!( + "There is a protocol upgrade in this batch, upgrade tx already processed" + ); None } else { - tracing::info!("We are not changing protocol version"); + // We do not have any upgrade transactins in this batch. + tracing::info!("There is no protocol upgrade in this batch"); None }; From 16936adfd6559966bf373a301ec3b69e6ad19367 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 17:59:56 +0200 Subject: [PATCH 28/37] Fix more nits --- core/lib/dal/src/protocol_versions_dal.rs | 4 ++-- core/lib/zksync_core/src/eth_watch/mod.rs | 2 +- core/lib/zksync_core/src/lib.rs | 2 +- core/lib/zksync_core/src/state_keeper/keeper.rs | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 0c88e97a77df..7c2079ec4268 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -65,7 +65,7 @@ impl ProtocolVersionsDal<'_, '_> { base_system_contracts_hashes.bootloader.as_bytes(), base_system_contracts_hashes.default_aa.as_bytes(), verifier_address.as_bytes(), - tx_hash.map(|tx_hash| tx_hash.0.to_vec()), + tx_hash.as_ref().map(H256::as_bytes), ) .execute(self.storage.conn()) .await @@ -107,7 +107,7 @@ impl ProtocolVersionsDal<'_, '_> { WHERE id = $2 "#, - tx_hash.map(|tx_hash| tx_hash.0.to_vec()), + tx_hash.as_ref().map(H256::as_bytes), id as i32, ) .execute(self.storage.conn()) diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index c793fe7108ee..d930f9215a80 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -165,7 +165,7 @@ impl EthWatch { ) -> anyhow::Result<()> { let mut timer = tokio::time::interval(self.poll_interval); let mut processed_events = 0; - while limit.map(|l| processed_events < l).unwrap_or(true) { + while limit.map_or(true, |l| processed_events < l) { if *stop_receiver.borrow() { tracing::info!("Stop signal received, eth_watch is shutting down"); break; diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 49fee19f928c..6529a2f348e2 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -618,7 +618,7 @@ pub async fn initialize_components( configs .network_config .as_ref() - .context("netowrk_config")? + .context("network_config")? .zksync_network_id, ) .await; diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index b3359e86ddb6..6fd4641c61f4 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -251,6 +251,7 @@ impl ZkSyncStateKeeper { && (version_changed || first_batch_in_shared_bridge) { // We have a new upgrade transaction - either a regular protocol upgrade or a `setChainId` upgrade. + // If we are running an EN, `protocol_upgrade_tx` will be `None` here since it is fetched from the main node. tracing::info!("There is an new upgrade tx to be executed in this batch"); protocol_upgrade_tx } else if !pending_miniblocks.is_empty() @@ -273,7 +274,7 @@ impl ZkSyncStateKeeper { ); None } else { - // We do not have any upgrade transactins in this batch. + // We do not have any upgrade transactions in this batch. tracing::info!("There is no protocol upgrade in this batch"); None }; From 3aeeb9180742da2dc180f50c2636d4ea3dc2142e Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 18:06:13 +0200 Subject: [PATCH 29/37] Revert "Refactor eth_watch a bit" This reverts commit b04051f276dfd77a51ed6e8515922f22a7cedc5f. --- .../event_processors/governance_upgrades.rs | 22 +++-- .../src/eth_watch/event_processors/mod.rs | 4 +- .../event_processors/priority_ops.rs | 9 +- .../event_processors/set_chain_id.rs | 7 +- .../eth_watch/event_processors/upgrades.rs | 18 ++-- core/lib/zksync_core/src/eth_watch/mod.rs | 97 +++---------------- 6 files changed, 49 insertions(+), 108 deletions(-) diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs index c849001add89..6008f4a05e96 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs @@ -44,7 +44,7 @@ impl EventProcessor for GovernanceUpgradesEventProcessor { storage: &mut StorageProcessor<'_>, client: &dyn EthClient, events: Vec, - ) -> Result { + ) -> Result<(), Error> { let mut upgrades = Vec::new(); for event in events .into_iter() @@ -76,17 +76,22 @@ impl EventProcessor for GovernanceUpgradesEventProcessor { } } + if upgrades.is_empty() { + return Ok(()); + } + + let ids_str: Vec<_> = upgrades + .iter() + .map(|(u, _)| format!("{}", u.id as u16)) + .collect(); + tracing::debug!("Received upgrades with ids: {}", ids_str.join(", ")); + let new_upgrades: Vec<_> = upgrades .into_iter() .skip_while(|(v, _)| v.id as u16 <= self.last_seen_version_id as u16) .collect(); - - let new_upgrades_count = new_upgrades.len(); - let ids: Vec<_> = new_upgrades.iter().map(|(u, _)| u.id as u16).collect(); - tracing::debug!("Received new upgrades with ids: {:?}", ids); - if new_upgrades.is_empty() { - return Ok(0); + return Ok(()); } let last_id = new_upgrades.last().unwrap().0.id; @@ -111,7 +116,8 @@ impl EventProcessor for GovernanceUpgradesEventProcessor { metrics::histogram!("eth_watcher.poll_eth_node", stage_start.elapsed(), "stage" => "persist_upgrades"); self.last_seen_version_id = last_id; - Ok(new_upgrades_count) + + Ok(()) } fn relevant_topic(&self) -> H256 { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs index 2ca99ae3acc6..2d80d6ebed75 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs @@ -12,13 +12,13 @@ pub mod upgrades; #[async_trait::async_trait] pub trait EventProcessor: 'static + fmt::Debug + Send + Sync { - /// Processes given events. If `Ok`, returns the number of processed events of interest. + /// Processes given events async fn process_events( &mut self, storage: &mut StorageProcessor<'_>, client: &dyn EthClient, events: Vec, - ) -> Result; + ) -> Result<(), Error>; /// Relevant topic which defines what events to be processed fn relevant_topic(&self) -> H256; diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs b/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs index 331d29c3c053..ad24eba1791b 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs @@ -39,7 +39,7 @@ impl EventProcessor for PriorityOpsEventProcessor { storage: &mut StorageProcessor<'_>, _client: &dyn EthClient, events: Vec, - ) -> Result { + ) -> Result<(), Error> { let mut priority_ops = Vec::new(); for event in events .into_iter() @@ -50,7 +50,7 @@ impl EventProcessor for PriorityOpsEventProcessor { } if priority_ops.is_empty() { - return Ok(0); + return Ok(()); } let first = &priority_ops[0]; @@ -72,9 +72,8 @@ impl EventProcessor for PriorityOpsEventProcessor { .into_iter() .skip_while(|tx| tx.serial_id() < self.next_expected_priority_id) .collect(); - let new_ops_count = new_ops.len(); if new_ops.is_empty() { - return Ok(0); + return Ok(()); } let first_new = &new_ops[0]; @@ -97,7 +96,7 @@ impl EventProcessor for PriorityOpsEventProcessor { } stage_latency.observe(); self.next_expected_priority_id = last_new.serial_id().next(); - Ok(new_ops_count) + Ok(()) } fn relevant_topic(&self) -> H256 { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs index f832f4b15d3a..35233399cab5 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs @@ -34,7 +34,7 @@ impl EventProcessor for SetChainIDEventProcessor { storage: &mut StorageProcessor<'_>, _client: &dyn EthClient, events: Vec, - ) -> Result { + ) -> Result<(), Error> { // SetChainId does not go through the governance contract, so we need to parse it separately. let upgrades = events .into_iter() @@ -48,9 +48,8 @@ impl EventProcessor for SetChainIDEventProcessor { }) .collect::, _>>()?; - let upgrades_count = upgrades.len(); if upgrades.is_empty() { - return Ok(0); + return Ok(()); } let ids: Vec<_> = upgrades.iter().map(|(id, _tx)| *id as u16).collect(); @@ -64,7 +63,7 @@ impl EventProcessor for SetChainIDEventProcessor { .await; } stage_latency.observe(); - Ok(upgrades_count) + Ok(()) } fn relevant_topic(&self) -> H256 { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs index a2bd65c3d0d4..a98321988907 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs @@ -35,7 +35,7 @@ impl EventProcessor for UpgradesEventProcessor { storage: &mut StorageProcessor<'_>, client: &dyn EthClient, events: Vec, - ) -> Result { + ) -> Result<(), Error> { let mut upgrades = Vec::new(); for event in events .into_iter() @@ -52,17 +52,19 @@ impl EventProcessor for UpgradesEventProcessor { upgrades.push((upgrade, scheduler_vk_hash)); } + if upgrades.is_empty() { + return Ok(()); + } + + let ids: Vec<_> = upgrades.iter().map(|(u, _)| u.id as u16).collect(); + tracing::debug!("Received upgrades with ids: {:?}", ids); + let new_upgrades: Vec<_> = upgrades .into_iter() .skip_while(|(v, _)| v.id as u16 <= self.last_seen_version_id as u16) .collect(); - let new_upgrades_count = new_upgrades.len(); - - let ids: Vec<_> = new_upgrades.iter().map(|(u, _)| u.id as u16).collect(); - tracing::debug!("Received new upgrades with ids: {:?}", ids); - if new_upgrades.is_empty() { - return Ok(0); + return Ok(()); } let last_id = new_upgrades.last().unwrap().0.id; @@ -81,7 +83,7 @@ impl EventProcessor for UpgradesEventProcessor { } stage_latency.observe(); self.last_seen_version_id = last_id; - Ok(new_upgrades_count) + Ok(()) } fn relevant_topic(&self) -> H256 { diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index d930f9215a80..a34b794942d8 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -20,8 +20,7 @@ use self::{ client::{Error, EthClient, EthHttpQueryClient, RETRY_LIMIT}, event_processors::{ governance_upgrades::GovernanceUpgradesEventProcessor, - priority_ops::PriorityOpsEventProcessor, set_chain_id::SetChainIDEventProcessor, - upgrades::UpgradesEventProcessor, EventProcessor, + priority_ops::PriorityOpsEventProcessor, upgrades::UpgradesEventProcessor, EventProcessor, }, metrics::{PollStage, METRICS}, }; @@ -93,31 +92,6 @@ impl EthWatch { } } - /// `EthWatch` is only meant to be created this way during genesis, since - /// we only need to save the `setChainId` event once -- after the chain creation. - async fn new_set_chain_id_watch( - diamond_proxy_address: Address, - mut client: Box, - poll_interval: Duration, - ) -> Self { - // To be safe, scan the last 50k blocks. - let last_processed_ethereum_block = client - .finalized_block_number() - .await - .expect("cannot initialize eth watch: cannot get current ETH block") - .saturating_sub(PRIORITY_EXPIRATION); - - let set_chain_id_processor = SetChainIDEventProcessor::new(diamond_proxy_address); - client.set_topics(vec![set_chain_id_processor.relevant_topic()]); - - Self { - client, - poll_interval, - event_processors: vec![Box::new(set_chain_id_processor)], - last_processed_ethereum_block, - } - } - async fn initialize_state( client: &dyn EthClient, storage: &mut StorageProcessor<'_>, @@ -157,15 +131,13 @@ impl EthWatch { } } - async fn run( + pub async fn run( &mut self, pool: ConnectionPool, stop_receiver: watch::Receiver, - limit: Option, ) -> anyhow::Result<()> { let mut timer = tokio::time::interval(self.poll_interval); - let mut processed_events = 0; - while limit.map_or(true, |l| processed_events < l) { + loop { if *stop_receiver.borrow() { tracing::info!("Stop signal received, eth_watch is shutting down"); break; @@ -175,32 +147,25 @@ impl EthWatch { METRICS.eth_poll.inc(); let mut storage = pool.access_storage_tagged("eth_watch").await.unwrap(); - match self.loop_iteration(&mut storage).await { - Ok(events) => { - tracing::info!("Processed {:?} events", events); - processed_events += events; - } - Err(error) => { - // This is an error because otherwise we could potentially miss a priority operation - // thus entering priority mode, which is not desired. - tracing::error!("Failed to process new blocks {}", error); - self.last_processed_ethereum_block = - Self::initialize_state(&*self.client, &mut storage) - .await - .last_processed_ethereum_block; - } + if let Err(error) = self.loop_iteration(&mut storage).await { + // This is an error because otherwise we could potentially miss a priority operation + // thus entering priority mode, which is not desired. + tracing::error!("Failed to process new blocks {}", error); + self.last_processed_ethereum_block = + Self::initialize_state(&*self.client, &mut storage) + .await + .last_processed_ethereum_block; } } Ok(()) } - /// If `Ok`, returns the number of processed events. #[tracing::instrument(skip(self, storage))] - async fn loop_iteration(&mut self, storage: &mut StorageProcessor<'_>) -> Result { + async fn loop_iteration(&mut self, storage: &mut StorageProcessor<'_>) -> Result<(), Error> { let stage_latency = METRICS.poll_eth_node[&PollStage::Request].start(); let to_block = self.client.finalized_block_number().await?; if to_block <= self.last_processed_ethereum_block { - return Ok(0); + return Ok(()); } let events = self @@ -213,46 +178,16 @@ impl EthWatch { .await?; stage_latency.observe(); - let mut processed_events = 0; for processor in self.event_processors.iter_mut() { - processed_events += processor + processor .process_events(storage, &*self.client, events.clone()) .await?; } self.last_processed_ethereum_block = to_block; - Ok(processed_events) + Ok(()) } } -/// This method creates an `EthWatch` instance that only looks for the `setChainId` event and runs -/// it. Once the event is found and the tx is saved into the db, it will exit. -pub async fn wait_for_set_chain_id( - config: ETHWatchConfig, - pool: ConnectionPool, - eth_gateway: Box, - diamond_proxy_addr: Address, - state_transition_manager_addr: Address, -) -> anyhow::Result<()> { - let eth_client = EthHttpQueryClient::new( - eth_gateway, - diamond_proxy_addr, - Some(state_transition_manager_addr), - None, - config.confirmations_for_eth_event, - ); - - let mut eth_watch = EthWatch::new_set_chain_id_watch( - diamond_proxy_addr, - Box::new(eth_client), - config.poll_interval(), - ) - .await; - - let (_stop_sender, stop_receiver) = watch::channel(false); - // We want to exit after 1 event is found, hence the limit is `Some(1)`. - eth_watch.run(pool, stop_receiver, Some(1)).await -} - pub async fn start_eth_watch( config: ETHWatchConfig, pool: ConnectionPool, @@ -280,6 +215,6 @@ pub async fn start_eth_watch( .await; Ok(tokio::spawn(async move { - eth_watch.run(pool, stop_receiver, None).await + eth_watch.run(pool, stop_receiver).await })) } From e6569e5f487178474a64010cb968b11240df5f75 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 19:11:48 +0200 Subject: [PATCH 30/37] Refactor set_chain_id event processing --- core/bin/zksync_server/src/main.rs | 2 - .../event_processors/governance_upgrades.rs | 14 ++-- .../src/eth_watch/event_processors/mod.rs | 1 - .../event_processors/set_chain_id.rs | 72 ------------------- .../eth_watch/event_processors/upgrades.rs | 11 ++- core/lib/zksync_core/src/eth_watch/tests.rs | 61 ---------------- core/lib/zksync_core/src/genesis.rs | 42 ++++++++++- core/lib/zksync_core/src/lib.rs | 15 ++-- 8 files changed, 55 insertions(+), 163 deletions(-) delete mode 100644 core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs diff --git a/core/bin/zksync_server/src/main.rs b/core/bin/zksync_server/src/main.rs index 4979f2514609..2f916f8bb2d5 100644 --- a/core/bin/zksync_server/src/main.rs +++ b/core/bin/zksync_server/src/main.rs @@ -140,13 +140,11 @@ async fn main() -> anyhow::Result<()> { let eth_sender = ETHSenderConfig::from_env().context("ETHSenderConfig")?; let contracts = ContractsConfig::from_env().context("ContractsConfig")?; let eth_client = ETHClientConfig::from_env().context("EthClientConfig")?; - let eth_watch = ETHWatchConfig::from_env().context("EthWatchConfig")?; genesis_init( &postgres_config, ð_sender, &network, &contracts, - ð_watch, ð_client.web3_url, opt.set_chain_id, ) diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs index 6008f4a05e96..7066838fee88 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs @@ -76,24 +76,18 @@ impl EventProcessor for GovernanceUpgradesEventProcessor { } } - if upgrades.is_empty() { - return Ok(()); - } - - let ids_str: Vec<_> = upgrades - .iter() - .map(|(u, _)| format!("{}", u.id as u16)) - .collect(); - tracing::debug!("Received upgrades with ids: {}", ids_str.join(", ")); - let new_upgrades: Vec<_> = upgrades .into_iter() .skip_while(|(v, _)| v.id as u16 <= self.last_seen_version_id as u16) .collect(); + if new_upgrades.is_empty() { return Ok(()); } + let ids: Vec<_> = new_upgrades.iter().map(|(u, _)| u.id as u16).collect(); + tracing::debug!("Received upgrades with ids: {:?}", ids); + let last_id = new_upgrades.last().unwrap().0.id; let stage_start = Instant::now(); for (upgrade, scheduler_vk_hash) in new_upgrades { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs index 2d80d6ebed75..0a068033f2bd 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs @@ -7,7 +7,6 @@ use crate::eth_watch::client::{Error, EthClient}; pub mod governance_upgrades; pub mod priority_ops; -pub mod set_chain_id; pub mod upgrades; #[async_trait::async_trait] diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs b/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs deleted file mode 100644 index 35233399cab5..000000000000 --- a/core/lib/zksync_core/src/eth_watch/event_processors/set_chain_id.rs +++ /dev/null @@ -1,72 +0,0 @@ -use zksync_contracts::SET_CHAIN_ID_EVENT; -use zksync_dal::StorageProcessor; -use zksync_types::{protocol_version::decode_set_chain_id_event, web3::types::Log, Address, H256}; - -use crate::eth_watch::{ - client::{Error, EthClient}, - event_processors::EventProcessor, - metrics::{PollStage, METRICS}, -}; - -/// Responsible for saving `setChainId` upgrade transactions to the database. -#[derive(Debug)] -pub struct SetChainIDEventProcessor { - /// Address of the `DiamondProxy` contract of the chain that the `SetChainId` event is for. - diamond_proxy_address: Address, - /// Signature of the `SetChainIdUpgrade` event. - /// The event is emitted by the `StateTransitionManager` contract. - set_chain_id_signature: H256, -} - -impl SetChainIDEventProcessor { - pub fn new(diamond_proxy_address: Address) -> Self { - Self { - diamond_proxy_address, - set_chain_id_signature: SET_CHAIN_ID_EVENT.signature(), - } - } -} - -#[async_trait::async_trait] -impl EventProcessor for SetChainIDEventProcessor { - async fn process_events( - &mut self, - storage: &mut StorageProcessor<'_>, - _client: &dyn EthClient, - events: Vec, - ) -> Result<(), Error> { - // SetChainId does not go through the governance contract, so we need to parse it separately. - let upgrades = events - .into_iter() - .filter(|log| { - log.topics[0] == self.set_chain_id_signature - && log.topics[1] == self.diamond_proxy_address.into() - }) - .map(|event| { - decode_set_chain_id_event(event) - .map_err(|err| Error::LogParse(format!("{:?}", err))) - }) - .collect::, _>>()?; - - if upgrades.is_empty() { - return Ok(()); - } - - let ids: Vec<_> = upgrades.iter().map(|(id, _tx)| *id as u16).collect(); - tracing::debug!("Received setChainId upgrade with version_id: {:?}", ids); - - let stage_latency = METRICS.poll_eth_node[&PollStage::PersistUpgrades].start(); - for (version_id, tx) in upgrades { - storage - .protocol_versions_dal() - .save_genesis_upgrade_with_tx(version_id, tx) - .await; - } - stage_latency.observe(); - Ok(()) - } - - fn relevant_topic(&self) -> H256 { - self.set_chain_id_signature - } -} diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs index a98321988907..393dad5afcda 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs @@ -52,21 +52,18 @@ impl EventProcessor for UpgradesEventProcessor { upgrades.push((upgrade, scheduler_vk_hash)); } - if upgrades.is_empty() { - return Ok(()); - } - - let ids: Vec<_> = upgrades.iter().map(|(u, _)| u.id as u16).collect(); - tracing::debug!("Received upgrades with ids: {:?}", ids); - let new_upgrades: Vec<_> = upgrades .into_iter() .skip_while(|(v, _)| v.id as u16 <= self.last_seen_version_id as u16) .collect(); + if new_upgrades.is_empty() { return Ok(()); } + let ids: Vec<_> = new_upgrades.iter().map(|(u, _)| u.id as u16).collect(); + tracing::debug!("Received upgrades with ids: {:?}", ids); + let last_id = new_upgrades.last().unwrap().0.id; let stage_latency = METRICS.poll_eth_node[&PollStage::PersistUpgrades].start(); for (upgrade, scheduler_vk_hash) in new_upgrades { diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index 63faac4c7347..49eb695ee9c8 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -548,67 +548,6 @@ async fn test_overlapping_batches() { assert_eq!(tx.common_data.serial_id.0, 4); } -#[tokio::test] -async fn test_set_chain_id_upgrade() { - let protocol_version = ProtocolVersionId::latest(); - let diamond_proxy_address = Address::repeat_byte(0x18); - let connection_pool = ConnectionPool::test_pool().await; - setup_db(&connection_pool).await; - let mut storage = connection_pool.access_storage().await.unwrap(); - - let mut client = FakeEthClient::new(); - let mut watcher = EthWatch::new_set_chain_id_watch( - diamond_proxy_address, - Box::new(client.clone()), - std::time::Duration::from_nanos(1), - ) - .await; - - // Set initial protocol version - storage - .protocol_versions_dal() - .save_protocol_version( - protocol_version, - 0, - Default::default(), - Default::default(), - Default::default(), - None, - ) - .await; - - assert_eq!( - storage - .protocol_versions_dal() - .get_protocol_upgrade_tx(protocol_version) - .await, - None - ); - - let tx = build_upgrade_tx(protocol_version, 18); - client - .add_set_chain_id_upgrade( - ProtocolUpgrade { - id: protocol_version, - tx: Some(tx.clone()), - ..Default::default() - }, - 18, - ) - .await; - - client.set_last_finalized_block_number(18).await; - watcher.loop_iteration(&mut storage).await.unwrap(); - - let upgrade_tx = storage - .protocol_versions_dal() - .get_protocol_upgrade_tx(protocol_version) - .await - .unwrap(); - - assert_eq!(tx.common_data.hash(), upgrade_tx.common_data.hash()); -} - async fn get_all_db_txs(storage: &mut StorageProcessor<'_>) -> Vec { storage.transactions_dal().reset_mempool().await.unwrap(); storage diff --git a/core/lib/zksync_core/src/genesis.rs b/core/lib/zksync_core/src/genesis.rs index 8e1725d11a7f..48d57224b92c 100644 --- a/core/lib/zksync_core/src/genesis.rs +++ b/core/lib/zksync_core/src/genesis.rs @@ -8,16 +8,19 @@ use multivm::{ zk_evm_latest::aux_structures::{LogQuery as MultiVmLogQuery, Timestamp as MultiVMTimestamp}, zkevm_test_harness_latest::witness::sort_storage_access::sort_storage_access_queries, }; -use zksync_contracts::BaseSystemContracts; +use zksync_contracts::{BaseSystemContracts, SET_CHAIN_ID_EVENT}; use zksync_dal::StorageProcessor; +use zksync_eth_client::{clients::QueryClient, EthInterface}; use zksync_merkle_tree::domain::ZkSyncTree; +use zksync_system_constants::PRIORITY_EXPIRATION; use zksync_types::{ block::{BlockGasCount, DeployedContract, L1BatchHeader, MiniblockHasher, MiniblockHeader}, commitment::{L1BatchCommitment, L1BatchMetadata}, fee_model::BatchFeeInput, get_code_key, get_system_context_init_logs, - protocol_version::{L1VerifierConfig, ProtocolVersion}, + protocol_version::{decode_set_chain_id_event, L1VerifierConfig, ProtocolVersion}, tokens::{TokenInfo, TokenMetadata, ETHEREUM_ADDRESS}, + web3::types::{BlockNumber, FilterBuilder}, zk_evm_types::{LogQuery, Timestamp}, AccountTreeId, Address, L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, StorageKey, StorageLog, StorageLogKind, H256, @@ -419,6 +422,41 @@ pub(crate) async fn save_genesis_l1_batch_metadata( .unwrap(); } +pub(crate) async fn save_set_chain_id_tx( + eth_client_url: &str, + diamond_proxy_address: Address, + state_transition_manager_address: Address, + storage: &mut StorageProcessor<'_>, +) -> anyhow::Result<()> { + let eth_client = QueryClient::new(eth_client_url)?; + let to = eth_client.block_number("fetch_chain_id_tx").await?.as_u64(); + let from = to - PRIORITY_EXPIRATION; + let filter = FilterBuilder::default() + .address(vec![state_transition_manager_address]) + .topics( + Some(vec![SET_CHAIN_ID_EVENT.signature()]), + Some(vec![diamond_proxy_address.into()]), + None, + None, + ) + .from_block(from.into()) + .to_block(BlockNumber::Latest) + .build(); + let mut logs = eth_client.logs(filter, "fetch_chain_id_tx").await?; + assert_eq!( + logs.len(), + 1, + "Expected a single set_chain_id event, got {:?}", + logs.len() + ); + let (version_id, upgrade_tx) = decode_set_chain_id_event(logs.remove(0))?; + storage + .protocol_versions_dal() + .save_genesis_upgrade_with_tx(version_id, upgrade_tx) + .await; + Ok(()) +} + #[cfg(test)] mod tests { use zksync_dal::ConnectionPool; diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 6529a2f348e2..bc0015781784 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -23,7 +23,7 @@ use zksync_config::{ contracts::ProverAtGenesis, database::{MerkleTreeConfig, MerkleTreeMode}, }, - ApiConfig, ContractsConfig, DBConfig, ETHSenderConfig, ETHWatchConfig, PostgresConfig, + ApiConfig, ContractsConfig, DBConfig, ETHSenderConfig, PostgresConfig, }; use zksync_contracts::{governance_contract, BaseSystemContracts}; use zksync_dal::{healthcheck::ConnectionPoolHealthCheck, ConnectionPool}; @@ -102,7 +102,6 @@ pub async fn genesis_init( eth_sender: ÐSenderConfig, network_config: &NetworkConfig, contracts_config: &ContractsConfig, - ethwatch_config: ÐWatchConfig, eth_client_url: &str, wait_for_set_chain_id: bool, ) -> anyhow::Result<()> { @@ -119,7 +118,6 @@ pub async fn genesis_init( .context("Private key is required for genesis init")?, ) .context("Failed to restore operator address from private key")?; - let eth_client = QueryClient::new(eth_client_url)?; // Select the first prover to be used during genesis. // Later we can change provers using the system upgrades, but for genesis @@ -135,6 +133,7 @@ pub async fn genesis_init( recursion_scheduler_level_vk_hash: contracts_config.snark_wrapper_vk_hash, }; + let eth_client = QueryClient::new(eth_client_url)?; let args = CallFunctionArgs::new("verificationKeyHash", ()).for_contract( contracts_config.verifier_addr, zksync_contracts::verifier_contract(), @@ -178,16 +177,16 @@ pub async fn genesis_init( .await?; if wait_for_set_chain_id { - eth_watch::wait_for_set_chain_id( - ethwatch_config.clone(), - pool.clone(), - Box::new(eth_client), + genesis::save_set_chain_id_tx( + eth_client_url, contracts_config.diamond_proxy_addr, contracts_config .state_transition_proxy_addr .expect("state_transition_proxy_addr is not set, but needed for genesis"), + &mut storage, ) - .await?; + .await + .context("Failed to save SetChainId upgrade transaction")?; } Ok(()) From 5915873fc84ca1f5e61c8335e5e5f4e3f0245e82 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 19:45:22 +0200 Subject: [PATCH 31/37] Revert eth_watch tests --- core/lib/zksync_core/src/eth_watch/tests.rs | 108 +++++--------------- 1 file changed, 28 insertions(+), 80 deletions(-) diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index 49eb695ee9c8..aaa24746edd3 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -1,16 +1,13 @@ use std::{collections::HashMap, convert::TryInto, sync::Arc}; use tokio::sync::RwLock; -use zksync_contracts::{governance_contract, zksync_contract, SET_CHAIN_ID_EVENT}; +use zksync_contracts::{governance_contract, zksync_contract}; use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_types::{ ethabi::{encode, Hash, Token}, l1::{L1Tx, OpProcessingType, PriorityQueueType}, protocol_version::{ProtocolUpgradeTx, ProtocolUpgradeTxCommonData}, - web3::{ - signing::keccak256, - types::{Address, BlockNumber, Log}, - }, + web3::types::{Address, BlockNumber, Log}, Execute, L1TxCommonData, PriorityOpId, ProtocolUpgrade, ProtocolVersion, ProtocolVersionId, Transaction, H256, U256, }; @@ -25,8 +22,6 @@ struct FakeEthClientData { transactions: HashMap>, diamond_upgrades: HashMap>, governance_upgrades: HashMap>, - // Not `Vec` because there can be only one `setChainId` upgrade per chain. - set_chain_id_upgrades: HashMap, last_finalized_block_number: u64, } @@ -36,7 +31,6 @@ impl FakeEthClientData { transactions: Default::default(), diamond_upgrades: Default::default(), governance_upgrades: Default::default(), - set_chain_id_upgrades: Default::default(), last_finalized_block_number: 0, } } @@ -69,12 +63,6 @@ impl FakeEthClientData { } } - fn add_set_chain_id_upgrade(&mut self, upgrade: ProtocolUpgrade, eth_block: u64) { - self.set_chain_id_upgrades - .entry(eth_block) - .or_insert_with(|| upgrade_into_set_chain_id_log(upgrade, eth_block)); - } - fn set_last_finalized_block_number(&mut self, number: u64) { self.last_finalized_block_number = number; } @@ -104,13 +92,6 @@ impl FakeEthClient { self.inner.write().await.add_governance_upgrades(upgrades); } - async fn add_set_chain_id_upgrade(&mut self, upgrade: ProtocolUpgrade, eth_block: u64) { - self.inner - .write() - .await - .add_set_chain_id_upgrade(upgrade, eth_block); - } - async fn set_last_finalized_block_number(&mut self, number: u64) { self.inner .write() @@ -151,9 +132,6 @@ impl EthClient for FakeEthClient { if let Some(ops) = self.inner.read().await.governance_upgrades.get(&number) { logs.extend_from_slice(ops); } - if let Some(op) = self.inner.read().await.set_chain_id_upgrades.get(&number) { - logs.push(op.clone()); - } } Ok(logs) } @@ -199,11 +177,11 @@ fn build_l1_tx(serial_id: u64, eth_block: u64) -> L1Tx { } fn build_upgrade_tx(id: ProtocolVersionId, eth_block: u64) -> ProtocolUpgradeTx { - let mut tx = ProtocolUpgradeTx { + ProtocolUpgradeTx { execute: Execute { contract_address: Address::repeat_byte(0x11), calldata: vec![1, 2, 3], - factory_deps: Some(Vec::new()), + factory_deps: None, value: U256::zero(), }, common_data: ProtocolUpgradeTxCommonData { @@ -219,10 +197,7 @@ fn build_upgrade_tx(id: ProtocolVersionId, eth_block: u64) -> ProtocolUpgradeTx canonical_tx_hash: H256::from_low_u64_be(id as u64), }, received_timestamp_ms: 0, - }; - - tx.common_data.canonical_tx_hash = H256(keccak256(&encode(&[tx_into_token(tx.clone())]))); - tx + } } #[tokio::test] @@ -628,28 +603,6 @@ fn upgrade_into_diamond_proxy_log(upgrade: ProtocolUpgrade, eth_block: u64) -> L } } -fn upgrade_into_set_chain_id_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { - let tx = upgrade.tx.unwrap(); - let data = encode(&[tx_into_token(tx.clone())]); - Log { - address: Address::repeat_byte(0x1), - topics: vec![ - SET_CHAIN_ID_EVENT.signature(), - Address::repeat_byte(0x18).into(), // diamond proxy address - H256::from_low_u64_be(ProtocolVersionId::latest() as u64), - ], - data: data.into(), - block_hash: Some(H256::repeat_byte(0x11)), - block_number: Some(eth_block.into()), - transaction_hash: Some([2; 32].into()), - transaction_index: Some(0u64.into()), - log_index: Some(0u64.into()), - transaction_log_index: Some(0u64.into()), - log_type: None, - removed: None, - } -} - fn upgrade_into_governor_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { let diamond_cut = upgrade_into_diamond_cut(upgrade); let execute_upgrade_selector = zksync_contract() @@ -694,36 +647,31 @@ fn upgrade_into_governor_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log { } } -/// Encoding of `L2CanonicalTransaction` from `IMailbox.sol`. -fn tx_into_token(tx: ProtocolUpgradeTx) -> Token { - Token::Tuple(vec![ - Token::Uint(0xfe.into()), - Token::Address(tx.common_data.sender), - Token::Address(tx.execute.contract_address), - Token::Uint(tx.common_data.gas_limit), - Token::Uint(tx.common_data.gas_per_pubdata_limit), - Token::Uint(tx.common_data.max_fee_per_gas), - Token::Uint(U256::zero()), - Token::Address(Address::zero()), - Token::Uint((tx.common_data.upgrade_id as u16).into()), - Token::Uint(tx.execute.value), - Token::FixedArray(vec![ - Token::Uint(U256::zero()), - Token::Uint(U256::zero()), - Token::Uint(U256::zero()), - Token::Uint(U256::zero()), - ]), - Token::Bytes(tx.execute.calldata), - Token::Bytes(Vec::new()), - Token::Array(Vec::new()), - Token::Bytes(Vec::new()), - Token::Bytes(Vec::new()), - ]) -} - fn upgrade_into_diamond_cut(upgrade: ProtocolUpgrade) -> Token { let tx_data_token = if let Some(tx) = upgrade.tx { - tx_into_token(tx) + Token::Tuple(vec![ + Token::Uint(0xfe.into()), + Token::Address(tx.common_data.sender), + Token::Address(tx.execute.contract_address), + Token::Uint(tx.common_data.gas_limit), + Token::Uint(tx.common_data.gas_per_pubdata_limit), + Token::Uint(tx.common_data.max_fee_per_gas), + Token::Uint(U256::zero()), + Token::Address(Address::zero()), + Token::Uint((tx.common_data.upgrade_id as u16).into()), + Token::Uint(tx.execute.value), + Token::FixedArray(vec![ + Token::Uint(U256::zero()), + Token::Uint(U256::zero()), + Token::Uint(U256::zero()), + Token::Uint(U256::zero()), + ]), + Token::Bytes(tx.execute.calldata), + Token::Bytes(Vec::new()), + Token::Array(Vec::new()), + Token::Bytes(Vec::new()), + Token::Bytes(Vec::new()), + ]) } else { Token::Tuple(vec![ Token::Uint(0.into()), From 1782671c3dc001a0de6931d7399b03066dba3ad0 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 9 Feb 2024 19:53:49 +0200 Subject: [PATCH 32/37] Remove extra argument in eth_watch client --- core/lib/zksync_core/src/eth_watch/client.rs | 19 +++++-------------- core/lib/zksync_core/src/eth_watch/mod.rs | 2 -- core/lib/zksync_core/src/lib.rs | 2 -- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/core/lib/zksync_core/src/eth_watch/client.rs b/core/lib/zksync_core/src/eth_watch/client.rs index 0845a25e9121..28707ce4a4c5 100644 --- a/core/lib/zksync_core/src/eth_watch/client.rs +++ b/core/lib/zksync_core/src/eth_watch/client.rs @@ -57,9 +57,6 @@ pub struct EthHttpQueryClient { client: Box, topics: Vec, zksync_contract_addr: Address, - /// Address of the `StateTransitionManager` contract. It's optional because it is present only - /// for post shared bridge chains. If address is some then client will listen to `SetChainId` events coming from it. - state_transition_manager_contract_addr: Option
, /// Address of the `Governance` contract. It's optional because it is present only for post-boojum chains. /// If address is some then client will listen to events coming from it. governance_address: Option
, @@ -71,7 +68,6 @@ impl EthHttpQueryClient { pub fn new( client: Box, zksync_contract_addr: Address, - state_transition_manager_contract_addr: Option
, governance_address: Option
, confirmations_for_eth_event: Option, ) -> Self { @@ -84,7 +80,6 @@ impl EthHttpQueryClient { client, topics: Vec::new(), zksync_contract_addr, - state_transition_manager_contract_addr, governance_address, verifier_contract_abi: verifier_contract(), confirmations_for_eth_event, @@ -99,15 +94,11 @@ impl EthHttpQueryClient { ) -> Result, Error> { let filter = FilterBuilder::default() .address( - [ - Some(self.zksync_contract_addr), - self.state_transition_manager_contract_addr, - self.governance_address, - ] - .iter() - .flatten() - .copied() - .collect(), + [Some(self.zksync_contract_addr), self.governance_address] + .iter() + .flatten() + .copied() + .collect(), ) .from_block(from) .to_block(to) diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index a34b794942d8..5aac8624d474 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -193,14 +193,12 @@ pub async fn start_eth_watch( pool: ConnectionPool, eth_gateway: Box, diamond_proxy_addr: Address, - state_transition_manager_contract_addr: Option
, governance: (Contract, Address), stop_receiver: watch::Receiver, ) -> anyhow::Result>> { let eth_client = EthHttpQueryClient::new( eth_gateway, diamond_proxy_addr, - state_transition_manager_contract_addr, Some(governance.1), config.confirmations_for_eth_event, ); diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index bc0015781784..50ee43296e4e 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -558,7 +558,6 @@ pub async fn initialize_components( } let main_zksync_contract_address = contracts_config.diamond_proxy_addr; - let state_transition_manager_contract = contracts_config.state_transition_proxy_addr; if components.contains(&Component::EthWatcher) { let started_at = Instant::now(); @@ -578,7 +577,6 @@ pub async fn initialize_components( eth_watch_pool, Box::new(query_client.clone()), main_zksync_contract_address, - state_transition_manager_contract, governance, stop_receiver.clone(), ) From 527f0409ae746921d91659cbfebc4209a87c9578 Mon Sep 17 00:00:00 2001 From: Bence Haromi Date: Mon, 12 Feb 2024 17:50:04 +0000 Subject: [PATCH 33/37] get_transaction_param_type function --- core/lib/types/src/protocol_version.rs | 59 ++++++++++---------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 9ddbcc5ce379..639ff7f6192b 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -234,6 +234,27 @@ pub struct ProtocolUpgrade { pub tx: Option, } +fn get_transaction_param_type() -> ParamType { + ParamType::Tuple(vec![ + ParamType::Uint(256), // `txType` + ParamType::Uint(256), // sender + ParamType::Uint(256), // to + ParamType::Uint(256), // gasLimit + ParamType::Uint(256), // `gasPerPubdataLimit` + ParamType::Uint(256), // maxFeePerGas + ParamType::Uint(256), // maxPriorityFeePerGas + ParamType::Uint(256), // paymaster + ParamType::Uint(256), // nonce (serial ID) + ParamType::Uint(256), // value + ParamType::FixedArray(Box::new(ParamType::Uint(256)), 4), // reserved + ParamType::Bytes, // calldata + ParamType::Bytes, // signature + ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps + ParamType::Bytes, // paymaster input + ParamType::Bytes, // `reservedDynamic` + ]) +} + impl TryFrom for ProtocolUpgrade { type Error = crate::ethabi::Error; @@ -259,24 +280,7 @@ impl TryFrom for ProtocolUpgrade { _ => unreachable!(), }; - let transaction_param_type = ParamType::Tuple(vec![ - ParamType::Uint(256), // `txType` - ParamType::Uint(256), // sender - ParamType::Uint(256), // to - ParamType::Uint(256), // gasLimit - ParamType::Uint(256), // `gasPerPubdataLimit` - ParamType::Uint(256), // maxFeePerGas - ParamType::Uint(256), // maxPriorityFeePerGas - ParamType::Uint(256), // paymaster - ParamType::Uint(256), // nonce (serial ID) - ParamType::Uint(256), // value - ParamType::FixedArray(Box::new(ParamType::Uint(256)), 4), // reserved - ParamType::Bytes, // calldata - ParamType::Bytes, // signature - ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps - ParamType::Bytes, // paymaster input - ParamType::Bytes, // `reservedDynamic` - ]); + let transaction_param_type: ParamType = get_transaction_param_type(); let verifier_params_type = ParamType::Tuple(vec![ ParamType::FixedBytes(32), ParamType::FixedBytes(32), @@ -370,24 +374,7 @@ impl TryFrom for ProtocolUpgrade { pub fn decode_set_chain_id_event( event: Log, ) -> Result<(ProtocolVersionId, ProtocolUpgradeTx), crate::ethabi::Error> { - let transaction_param_type = ParamType::Tuple(vec![ - ParamType::Uint(256), // tx type - ParamType::Uint(256), // sender - ParamType::Uint(256), // to - ParamType::Uint(256), // gas limit - ParamType::Uint(256), // gas per pubdata limit - ParamType::Uint(256), // max fee per gas - ParamType::Uint(256), // max priority fee per gas - ParamType::Uint(256), // paymaster - ParamType::Uint(256), // nonce (serial ID) - ParamType::Uint(256), // value - ParamType::FixedArray(Box::new(ParamType::Uint(256)), 4), // reserved - ParamType::Bytes, // calldata - ParamType::Bytes, // signature - ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps - ParamType::Bytes, // paymaster input - ParamType::Bytes, // reserved dynamic - ]); + let transaction_param_type: ParamType = get_transaction_param_type(); let Token::Tuple(transaction) = decode(&[transaction_param_type], &event.data.0)?.remove(0) else { From 834d22e3f7959417a062854242dea44e5879c437 Mon Sep 17 00:00:00 2001 From: Bence Haromi Date: Fri, 16 Feb 2024 18:33:30 +0000 Subject: [PATCH 34/37] nit: batch number added to log messages --- core/lib/zksync_core/src/state_keeper/keeper.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 7e0786cde31e..e331aec9763a 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -253,7 +253,10 @@ impl ZkSyncStateKeeper { { // We have a new upgrade transaction - either a regular protocol upgrade or a `setChainId` upgrade. // If we are running an EN, `protocol_upgrade_tx` will be `None` here since it is fetched from the main node. - tracing::info!("There is an new upgrade tx to be executed in this batch"); + tracing::info!( + "There is an new upgrade tx to be executed in batch #{}", + l1_batch_number + ); protocol_upgrade_tx } else if !pending_miniblocks.is_empty() && (version_changed || first_batch_in_shared_bridge) @@ -271,12 +274,13 @@ impl ZkSyncStateKeeper { ); } tracing::info!( - "There is a protocol upgrade in this batch, upgrade tx already processed" + "There is a protocol upgrade in batch #{}, upgrade tx already processed", + l1_batch_number ); None } else { // We do not have any upgrade transactions in this batch. - tracing::info!("There is no protocol upgrade in this batch"); + tracing::info!("There is no protocol upgrade in batch #{}", l1_batch_number); None }; From 0640d4bbc70363a7c5935cea6d0c87e078dd403a Mon Sep 17 00:00:00 2001 From: Bence Haromi Date: Fri, 16 Feb 2024 18:35:07 +0000 Subject: [PATCH 35/37] nit: anyhow::ensure instead of assert_eq --- core/lib/zksync_core/src/genesis.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/lib/zksync_core/src/genesis.rs b/core/lib/zksync_core/src/genesis.rs index 45d2d96ba088..861371ec7a35 100644 --- a/core/lib/zksync_core/src/genesis.rs +++ b/core/lib/zksync_core/src/genesis.rs @@ -445,9 +445,8 @@ pub(crate) async fn save_set_chain_id_tx( .to_block(BlockNumber::Latest) .build(); let mut logs = eth_client.logs(filter, "fetch_chain_id_tx").await?; - assert_eq!( - logs.len(), - 1, + anyhow::ensure!( + logs.len() == 1, "Expected a single set_chain_id event, got {:?}", logs.len() ); From 7f896c7d261b9cef3a662b06f35be6aee2241e3d Mon Sep 17 00:00:00 2001 From: Bence Haromi Date: Fri, 16 Feb 2024 18:47:19 +0000 Subject: [PATCH 36/37] lint fix --- core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs | 2 +- core/lib/zksync_core/src/state_keeper/tests/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs index 58f4da1db0e5..13045119875a 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs @@ -12,7 +12,7 @@ use zksync_l1_contract_interface::{ use zksync_types::{ commitment::SerializeCommitment, eth_sender::EthTx, - ethabi::{Contract, Token}, + ethabi::Token, l2_to_l1_log::UserL2ToL1Log, protocol_version::{L1VerifierConfig, VerifierParams}, web3::contract::Error as Web3ContractError, diff --git a/core/lib/zksync_core/src/state_keeper/tests/mod.rs b/core/lib/zksync_core/src/state_keeper/tests/mod.rs index 3f7bd601ea33..4de8c3d5ca7f 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/mod.rs @@ -455,7 +455,7 @@ async fn load_upgrade_tx() { stop_receiver, Box::new(io), Box::new(batch_executor_base), - Box::new(sealer), + Arc::new(sealer), ); // Since the version hasn't changed, and we are not using shared bridge, we should not load any From f61c596831c2fb7ecd2596e9fa39a916acae30b0 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 20 Feb 2024 12:40:05 +0200 Subject: [PATCH 37/37] Resolve remaining nits --- core/lib/zksync_core/src/genesis.rs | 5 +++-- core/lib/zksync_core/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/lib/zksync_core/src/genesis.rs b/core/lib/zksync_core/src/genesis.rs index 861371ec7a35..8b02cc13ba1a 100644 --- a/core/lib/zksync_core/src/genesis.rs +++ b/core/lib/zksync_core/src/genesis.rs @@ -447,8 +447,9 @@ pub(crate) async fn save_set_chain_id_tx( let mut logs = eth_client.logs(filter, "fetch_chain_id_tx").await?; anyhow::ensure!( logs.len() == 1, - "Expected a single set_chain_id event, got {:?}", - logs.len() + "Expected a single set_chain_id event, got these {}: {:?}", + logs.len(), + logs ); let (version_id, upgrade_tx) = decode_set_chain_id_event(logs.remove(0))?; storage diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 4510a7b15d61..4bbbc7551b56 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -184,7 +184,7 @@ pub async fn genesis_init( contracts_config.diamond_proxy_addr, contracts_config .state_transition_proxy_addr - .expect("state_transition_proxy_addr is not set, but needed for genesis"), + .context("state_transition_proxy_addr is not set, but needed for genesis")?, &mut storage, ) .await