diff --git a/checks-config/era.dic b/checks-config/era.dic
index b5ef3712f51a..22d6189ca671 100644
--- a/checks-config/era.dic
+++ b/checks-config/era.dic
@@ -411,6 +411,10 @@ prode
StorageBatchInfo
CommitBatchInfo
IExecutor
+SetChainId
+setChainId
+SetChainIdUpgrade
+state_transition_manager_contract
// Names
Vyper
diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs
index e37a71d79c6f..a4a6bc39b48b 100644
--- a/core/bin/external_node/src/config/mod.rs
+++ b/core/bin/external_node/src/config/mod.rs
@@ -28,6 +28,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: Option
,
pub diamond_proxy_addr: Address,
pub l1_erc20_bridge_proxy_addr: Address,
pub l2_erc20_bridge_addr: Address,
@@ -48,6 +49,8 @@ impl RemoteENConfig {
.get_testnet_paymaster()
.rpc_context("get_testnet_paymaster")
.await?;
+ // 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()
.rpc_context("get_main_contract")
@@ -59,6 +62,7 @@ impl RemoteENConfig {
let l1_chain_id = L1ChainId(l1_chain_id.as_u64());
Ok(Self {
+ bridgehub_proxy_addr,
diamond_proxy_addr,
l2_testnet_paymaster_addr,
l1_erc20_bridge_proxy_addr: bridges.l1_erc20_default_bridge,
@@ -557,6 +561,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/bin/zksync_server/src/main.rs b/core/bin/zksync_server/src/main.rs
index b17913d30947..2deb64d45722 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,
@@ -142,6 +146,7 @@ async fn main() -> anyhow::Result<()> {
&network,
&contracts,
ð_client.web3_url,
+ opt.set_chain_id,
)
.await
.context("genesis_init")?;
diff --git a/core/lib/config/src/configs/contracts.rs b/core/lib/config/src/configs/contracts.rs
index a05027e0bf0d..70d4e685586f 100644
--- a/core/lib/config/src/configs/contracts.rs
+++ b/core/lib/config/src/configs/contracts.rs
@@ -40,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 {
@@ -52,6 +59,7 @@ impl ContractsConfig {
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),
@@ -77,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/config/src/testonly.rs b/core/lib/config/src/testonly.rs
index 3d9fa817bd2b..065e1b3e6054 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(),
}
}
}
diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs
index f6bfd9c1e4a3..065008d5dbce 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};
@@ -489,358 +489,94 @@ 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": [
{
- "components": [
- {
- "internalType": "uint64",
- "name": "blockNumber",
- "type": "uint64"
- },
- {
- "internalType": "bytes32",
- "name": "blockHash",
- "type": "bytes32"
- },
- {
- "internalType": "uint64",
- "name": "indexRepeatedStorageChanges",
- "type": "uint64"
- },
- {
- "internalType": "uint256",
- "name": "numberOfLayer1Txs",
- "type": "uint256"
- },
- {
- "internalType": "bytes32",
- "name": "priorityOperationsHash",
- "type": "bytes32"
- },
- {
- "internalType": "bytes32",
- "name": "l2LogsTreeRoot",
- "type": "bytes32"
- },
- {
- "internalType": "uint256",
- "name": "timestamp",
- "type": "uint256"
- },
- {
- "internalType": "bytes32",
- "name": "commitment",
- "type": "bytes32"
- }
- ],
- "internalType": "struct IExecutor.StoredBlockInfo",
- "name": "_prevBlock",
- "type": "tuple"
+ "indexed": true,
+ "name": "_stateTransitionChain",
+ "type": "address"
},
{
"components": [
{
- "internalType": "uint64",
- "name": "blockNumber",
- "type": "uint64"
- },
- {
- "internalType": "bytes32",
- "name": "blockHash",
- "type": "bytes32"
- },
- {
- "internalType": "uint64",
- "name": "indexRepeatedStorageChanges",
- "type": "uint64"
+ "name": "txType",
+ "type": "uint256"
},
{
- "internalType": "uint256",
- "name": "numberOfLayer1Txs",
+ "name": "from",
"type": "uint256"
},
{
- "internalType": "bytes32",
- "name": "priorityOperationsHash",
- "type": "bytes32"
+ "name": "to",
+ "type": "uint256"
},
{
- "internalType": "bytes32",
- "name": "l2LogsTreeRoot",
- "type": "bytes32"
+ "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[]"
+ "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"
+ "name": "maxPriorityFeePerGas",
+ "type": "uint256"
},
{
- "internalType": "bytes32",
- "name": "blockHash",
- "type": "bytes32"
+ "name": "paymaster",
+ "type": "uint256"
},
{
- "internalType": "uint64",
- "name": "indexRepeatedStorageChanges",
- "type": "uint64"
+ "name": "nonce",
+ "type": "uint256"
},
{
- "internalType": "uint256",
- "name": "numberOfLayer1Txs",
+ "name": "value",
"type": "uint256"
},
{
- "internalType": "bytes32",
- "name": "priorityOperationsHash",
- "type": "bytes32"
+ "name": "reserved",
+ "type": "uint256[4]"
},
{
- "internalType": "bytes32",
- "name": "l2LogsTreeRoot",
- "type": "bytes32"
+ "name": "data",
+ "type": "bytes"
},
{
- "internalType": "uint256",
- "name": "timestamp",
- "type": "uint256"
+ "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"
+ "name": "factoryDeps",
+ "type": "uint256[]"
},
{
- "internalType": "uint256",
- "name": "num_inputs",
- "type": "uint256"
+ "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]"
+ "name": "reservedDynamic",
+ "type": "bytes"
}
],
- "internalType": "struct VerificationKey",
- "name": "vk",
+ "indexed": false,
+ "name": "_l2Transaction",
"type": "tuple"
+ },
+ {
+ "indexed": true,
+ "name": "_protocolVersion",
+ "type": "uint256"
}
],
- "stateMutability": "pure",
- "type": "function"
+ "name": "SetChainIdUpgrade",
+ "type": "event"
}"#;
serde_json::from_str(abi).unwrap()
});
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 63f09dde5286..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
@@ -98,6 +98,47 @@ impl ProtocolVersionsDal<'_, '_> {
db_transaction.commit().await.unwrap();
}
+ async fn save_genesis_upgrade_tx_hash(&mut self, id: ProtocolVersionId, tx_hash: Option) {
+ sqlx::query!(
+ r#"
+ UPDATE protocol_versions
+ SET
+ upgrade_tx_hash = $1
+ WHERE
+ id = $2
+ "#,
+ tx_hash.as_ref().map(H256::as_bytes),
+ id as i32,
+ )
+ .execute(self.storage.conn())
+ .await
+ .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,
+ 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_tx_hash(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/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 537b68414c63..bf2dc31d7bb3 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: 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"),
@@ -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: Some(addr("dd6fa5c14e7550b4caf2aa2818d24c69cbc347e5")),
validator_timelock_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"),
genesis_tx_hash: hash(
"b99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e",
@@ -100,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="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/protobuf_config/src/contracts.rs b/core/lib/protobuf_config/src/contracts.rs
index 6521bd0bf810..0a55f9b1145f 100644
--- a/core/lib/protobuf_config/src/contracts.rs
+++ b/core/lib/protobuf_config/src/contracts.rs
@@ -122,6 +122,36 @@ 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")?,
+ bridgehub_impl_addr: self
+ .bridgehub_impl_addr
+ .as_ref()
+ .map(|x| parse_h160(x))
+ .transpose()
+ .context("bridgehub_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")?,
})
}
@@ -174,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()),
}
}
}
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/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 034987d01c81..639ff7f6192b 100644
--- a/core/lib/types/src/protocol_version.rs
+++ b/core/lib/types/src/protocol_version.rs
@@ -17,9 +17,8 @@ use crate::{
};
#[repr(u16)]
-#[derive(
- Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TryFromPrimitive, Serialize, Deserialize,
-)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(TryFromPrimitive, Serialize, Deserialize)]
pub enum ProtocolVersionId {
Version0 = 0,
Version1,
@@ -93,6 +92,15 @@ impl ProtocolVersionId {
self <= &Self::Version17
}
+ pub fn is_pre_shared_bridge(&self) -> bool {
+ // TODO: review this when we actually deploy shared bridge
+ true
+ }
+
+ pub fn is_1_4_0(&self) -> bool {
+ self >= &ProtocolVersionId::Version18 && self < &ProtocolVersionId::Version20
+ }
+
pub fn is_post_1_4_1(&self) -> bool {
self >= &ProtocolVersionId::Version20
}
@@ -119,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,
@@ -227,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;
@@ -252,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),
@@ -299,119 +310,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());
@@ -458,6 +371,147 @@ impl TryFrom for ProtocolUpgrade {
}
}
+pub fn decode_set_chain_id_event(
+ event: Log,
+) -> Result<(ProtocolVersionId, ProtocolUpgradeTx), crate::ethabi::Error> {
+ let transaction_param_type: ParamType = get_transaction_param_type();
+
+ 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 {
+ 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 == U256::zero() {
+ // There is no upgrade tx.
+ return None;
+ }
+
+ assert_eq!(
+ tx_type,
+ PROTOCOL_UPGRADE_TX_TYPE.into(),
+ "Unexpected tx type {} when decoding upgrade",
+ tx_type
+ );
+
+ // 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(),
+ })
+ }
+}
+
impl TryFrom for ProtocolUpgrade {
type Error = crate::ethabi::Error;
@@ -606,7 +660,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.
@@ -641,7 +695,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/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/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/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/web3_decl/src/namespaces/zks.rs b/core/lib/web3_decl/src/namespaces/zks.rs
index 66ca97cb03aa..d62827056232 100644
--- a/core/lib/web3_decl/src/namespaces/zks.rs
+++ b/core/lib/web3_decl/src/namespaces/zks.rs
@@ -33,6 +33,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