Skip to content

Commit 2c778fd

Browse files
authored
feat(eth-watch): Change protocol upgrade schema (#3435)
## What ❔ Copies protocol upgrade schema changes from sync-layer-stable in a non-breaking way. ## Why ❔ Support post-gateway upgrade schema. ## Checklist <!-- Check your PR fulfills the following items. --> <!-- For draft PRs check the boxes as you complete them. --> - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`.
1 parent 0731f60 commit 2c778fd

File tree

13 files changed

+663
-136
lines changed

13 files changed

+663
-136
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/lib/types/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ zksync_mini_merkle_tree.workspace = true
1919
zksync_protobuf.workspace = true
2020
zksync_crypto_primitives.workspace = true
2121

22+
async-trait.workspace = true
2223
anyhow.workspace = true
2324
chrono = { workspace = true, features = ["serde"] }
2425
derive_more = { workspace = true, features = ["debug"] }

core/lib/types/src/abi.rs

Lines changed: 247 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use anyhow::Context as _;
2+
use zksync_basic_types::protocol_version::ProtocolSemanticVersion;
23

34
use crate::{
45
bytecode::BytecodeHash,
@@ -185,17 +186,19 @@ impl NewPriorityRequest {
185186
}
186187

187188
/// `VerifierParams` from `l1-contracts/contracts/state-transition/chain-interfaces/IVerifier.sol`.
188-
#[derive(Default, PartialEq)]
189+
#[derive(Debug, Default, PartialEq)]
189190
pub struct VerifierParams {
190191
pub recursion_node_level_vk_hash: [u8; 32],
191192
pub recursion_leaf_level_vk_hash: [u8; 32],
192193
pub recursion_circuits_set_vks_hash: [u8; 32],
193194
}
194195

195196
/// `ProposedUpgrade` from, `l1-contracts/contracts/upgrades/BazeZkSyncUpgrade.sol`.
197+
#[derive(Debug)]
196198
pub struct ProposedUpgrade {
197199
pub l2_protocol_upgrade_tx: Box<L2CanonicalTransaction>,
198-
pub factory_deps: Vec<Vec<u8>>,
200+
// Factory deps are set only pre-gateway upgrades.
201+
pub factory_deps: Option<Vec<Vec<u8>>>,
199202
pub bootloader_hash: [u8; 32],
200203
pub default_account_hash: [u8; 32],
201204
pub verifier: Address,
@@ -250,8 +253,8 @@ impl VerifierParams {
250253
}
251254

252255
impl ProposedUpgrade {
253-
/// RLP schema of the `ProposedUpgrade`.
254-
pub fn schema() -> ParamType {
256+
/// Pre-gateway RLP schema of the `ProposedUpgrade`.
257+
pub fn schema_pre_gateway() -> ParamType {
255258
ParamType::Tuple(vec![
256259
L2CanonicalTransaction::schema(), // transaction data
257260
ParamType::Array(ParamType::Bytes.into()), // factory deps
@@ -266,16 +269,39 @@ impl ProposedUpgrade {
266269
])
267270
}
268271

272+
/// Post-gateway RLP schema of the `ProposedUpgrade`.
273+
pub fn schema_post_gateway() -> ParamType {
274+
ParamType::Tuple(vec![
275+
L2CanonicalTransaction::schema(), // transaction data
276+
ParamType::FixedBytes(32), // bootloader code hash
277+
ParamType::FixedBytes(32), // default account code hash
278+
ParamType::Address, // verifier address
279+
VerifierParams::schema(), // verifier params
280+
ParamType::Bytes, // l1 custom data
281+
ParamType::Bytes, // l1 post-upgrade custom data
282+
ParamType::Uint(256), // timestamp
283+
ParamType::Uint(256), // version id
284+
])
285+
}
286+
269287
/// Encodes `ProposedUpgrade` to a RLP token.
270288
pub fn encode(&self) -> Token {
271-
Token::Tuple(vec![
272-
self.l2_protocol_upgrade_tx.encode(),
273-
Token::Array(
289+
let mut tokens = vec![self.l2_protocol_upgrade_tx.encode()];
290+
291+
let protocol_version = ProtocolSemanticVersion::try_from_packed(self.new_protocol_version)
292+
.expect("Version is not supported")
293+
.minor;
294+
if protocol_version.is_pre_gateway() {
295+
tokens.push(Token::Array(
274296
self.factory_deps
275-
.iter()
276-
.map(|b| Token::Bytes(b.clone()))
297+
.clone()
298+
.expect("Factory deps should be present in pre-gateway upgrade data")
299+
.into_iter()
300+
.map(Token::Bytes)
277301
.collect(),
278-
),
302+
));
303+
}
304+
tokens.extend([
279305
Token::FixedBytes(self.bootloader_hash.into()),
280306
Token::FixedBytes(self.default_account_hash.into()),
281307
Token::Address(self.verifier),
@@ -284,32 +310,52 @@ impl ProposedUpgrade {
284310
Token::Bytes(self.post_upgrade_calldata.clone()),
285311
Token::Uint(self.upgrade_timestamp),
286312
Token::Uint(self.new_protocol_version),
287-
])
313+
]);
314+
315+
Token::Tuple(tokens)
288316
}
289317

290318
/// Decodes `ProposedUpgrade` from a RLP token.
291319
/// Returns an error if token doesn't match the `schema()`.
292320
pub fn decode(token: Token) -> anyhow::Result<Self> {
293321
let tokens = token.into_tuple().context("not a tuple")?;
294-
anyhow::ensure!(tokens.len() == 10);
322+
let tokens_len = tokens.len();
323+
anyhow::ensure!(tokens_len >= 9);
295324
let mut t = tokens.into_iter();
296325
let mut next = || t.next().unwrap();
297-
Ok(Self {
298-
l2_protocol_upgrade_tx: L2CanonicalTransaction::decode(next())
299-
.context("l2_protocol_upgrade_tx")?
300-
.into(),
301-
factory_deps: next()
302-
.into_array()
303-
.context("factory_deps")?
304-
.into_iter()
305-
.enumerate()
306-
.map(|(i, b)| b.into_bytes().context(i))
307-
.collect::<Result<_, _>>()
308-
.context("factory_deps")?,
309-
bootloader_hash: next()
310-
.into_fixed_bytes()
311-
.and_then(|b| b.try_into().ok())
312-
.context("bootloader_hash")?,
326+
327+
let l2_protocol_upgrade_tx = L2CanonicalTransaction::decode(next())
328+
.context("l2_protocol_upgrade_tx")?
329+
.into();
330+
let next_token = next();
331+
let (factory_deps, bootloader_hash) = match next_token {
332+
Token::Array(tokens) => {
333+
anyhow::ensure!(tokens_len == 10);
334+
(
335+
Some(
336+
tokens
337+
.into_iter()
338+
.enumerate()
339+
.map(|(i, b)| b.into_bytes().context(i))
340+
.collect::<Result<_, _>>()
341+
.context("factory_deps")?,
342+
),
343+
next().into_fixed_bytes(),
344+
)
345+
}
346+
Token::FixedBytes(bytes) => {
347+
anyhow::ensure!(tokens_len == 9);
348+
(None, Some(bytes))
349+
}
350+
_ => anyhow::bail!("Unexpected type of the second token"),
351+
};
352+
let bootloader_hash = bootloader_hash
353+
.and_then(|b| b.try_into().ok())
354+
.context("bootloader_hash")?;
355+
let upgrade = Self {
356+
l2_protocol_upgrade_tx,
357+
factory_deps,
358+
bootloader_hash,
313359
default_account_hash: next()
314360
.into_fixed_bytes()
315361
.and_then(|b| b.try_into().ok())
@@ -322,7 +368,16 @@ impl ProposedUpgrade {
322368
post_upgrade_calldata: next().into_bytes().context("post_upgrade_calldata")?,
323369
upgrade_timestamp: next().into_uint().context("upgrade_timestamp")?,
324370
new_protocol_version: next().into_uint().context("new_protocol_version")?,
325-
})
371+
};
372+
373+
let protocol_version =
374+
ProtocolSemanticVersion::try_from_packed(upgrade.new_protocol_version)
375+
.map_err(|err| anyhow::anyhow!(err))
376+
.context("Version is not supported")?
377+
.minor;
378+
anyhow::ensure!(protocol_version.is_pre_gateway() == upgrade.factory_deps.is_some());
379+
380+
Ok(upgrade)
326381
}
327382
}
328383

@@ -365,3 +420,166 @@ impl Transaction {
365420
})
366421
}
367422
}
423+
424+
pub struct ForceDeployment {
425+
pub bytecode_hash: H256,
426+
pub new_address: Address,
427+
pub call_constructor: bool,
428+
pub value: U256,
429+
pub input: Vec<u8>,
430+
}
431+
432+
impl ForceDeployment {
433+
/// ABI schema of the `ForceDeployment`.
434+
pub fn schema() -> ParamType {
435+
ParamType::Tuple(vec![
436+
ParamType::FixedBytes(32),
437+
ParamType::Address,
438+
ParamType::Bool,
439+
ParamType::Uint(256),
440+
ParamType::Bytes,
441+
])
442+
}
443+
444+
/// Encodes `ForceDeployment` to a RLP token.
445+
pub fn encode(&self) -> Token {
446+
Token::Tuple(vec![
447+
Token::FixedBytes(self.bytecode_hash.0.to_vec()),
448+
Token::Address(self.new_address),
449+
Token::Bool(self.call_constructor),
450+
Token::Uint(self.value),
451+
Token::Bytes(self.input.clone()),
452+
])
453+
}
454+
455+
/// Decodes `ForceDeployment` from a RLP token.
456+
/// Returns an error if token doesn't match the `schema()`.
457+
pub fn decode(token: Token) -> anyhow::Result<Self> {
458+
let tokens = token.into_tuple().context("not a tuple")?;
459+
anyhow::ensure!(tokens.len() == 5);
460+
let mut t = tokens.into_iter();
461+
let mut next = || t.next().unwrap();
462+
Ok(Self {
463+
bytecode_hash: next()
464+
.into_fixed_bytes()
465+
.and_then(|b| Some(H256(b.try_into().ok()?)))
466+
.context("bytecode_hash")?,
467+
new_address: next().into_address().context("new_address")?,
468+
call_constructor: next().into_bool().context("call_constructor")?,
469+
value: next().into_uint().context("value")?,
470+
input: next().into_bytes().context("input")?,
471+
})
472+
}
473+
}
474+
475+
pub struct GatewayUpgradeEncodedInput {
476+
pub force_deployments: Vec<ForceDeployment>,
477+
pub l2_gateway_upgrade_position: usize,
478+
pub fixed_force_deployments_data: Vec<u8>,
479+
pub ctm_deployer: Address,
480+
pub old_validator_timelock: Address,
481+
pub new_validator_timelock: Address,
482+
pub wrapped_base_token_store: Address,
483+
}
484+
485+
impl GatewayUpgradeEncodedInput {
486+
/// ABI schema of the `GatewayUpgradeEncodedInput`.
487+
pub fn schema() -> ParamType {
488+
ParamType::Tuple(vec![
489+
ParamType::Array(Box::new(ForceDeployment::schema())),
490+
ParamType::Uint(256),
491+
ParamType::Bytes,
492+
ParamType::Address,
493+
ParamType::Address,
494+
ParamType::Address,
495+
ParamType::Address,
496+
])
497+
}
498+
499+
/// Decodes `GatewayUpgradeEncodedInput` from a RLP token.
500+
/// Returns an error if token doesn't match the `schema()`.
501+
pub fn decode(token: Token) -> anyhow::Result<Self> {
502+
let tokens = token.into_tuple().context("not a tuple")?;
503+
anyhow::ensure!(tokens.len() == 7);
504+
let mut t = tokens.into_iter();
505+
let mut next = || t.next().unwrap();
506+
507+
let force_deployments_array = next().into_array().context("force_deployments_array")?;
508+
let mut force_deployments = vec![];
509+
for token in force_deployments_array {
510+
force_deployments.push(ForceDeployment::decode(token)?);
511+
}
512+
513+
Ok(Self {
514+
force_deployments,
515+
l2_gateway_upgrade_position: next()
516+
.into_uint()
517+
.context("l2_gateway_upgrade_position")?
518+
.as_usize(),
519+
fixed_force_deployments_data: next()
520+
.into_bytes()
521+
.context("fixed_force_deployments_data")?,
522+
ctm_deployer: next().into_address().context("ctm_deployer")?,
523+
old_validator_timelock: next().into_address().context("old_validator_timelock")?,
524+
new_validator_timelock: next().into_address().context("new_validator_timelock")?,
525+
wrapped_base_token_store: next().into_address().context("wrapped_base_token_store")?,
526+
})
527+
}
528+
}
529+
530+
#[derive(Debug, Clone)]
531+
pub struct ZkChainSpecificUpgradeData {
532+
pub base_token_asset_id: H256,
533+
pub l2_legacy_shared_bridge: Address,
534+
pub predeployed_l2_weth_address: Address,
535+
pub base_token_l1_address: Address,
536+
pub base_token_name: String,
537+
pub base_token_symbol: String,
538+
}
539+
540+
impl ZkChainSpecificUpgradeData {
541+
pub fn from_partial_components(
542+
base_token_asset_id: Option<H256>,
543+
l2_legacy_shared_bridge: Option<Address>,
544+
predeployed_l2_weth_address: Option<Address>,
545+
base_token_l1_address: Option<Address>,
546+
base_token_name: Option<String>,
547+
base_token_symbol: Option<String>,
548+
) -> Option<Self> {
549+
Some(Self {
550+
base_token_asset_id: base_token_asset_id?,
551+
l2_legacy_shared_bridge: l2_legacy_shared_bridge?,
552+
// Note, that some chains may not contain previous deployment of L2 wrapped base
553+
// token. For those, zero address is used.
554+
predeployed_l2_weth_address: predeployed_l2_weth_address.unwrap_or_default(),
555+
base_token_l1_address: base_token_l1_address?,
556+
base_token_name: base_token_name?,
557+
base_token_symbol: base_token_symbol?,
558+
})
559+
}
560+
561+
/// ABI schema of the `ZkChainSpecificUpgradeData`.
562+
pub fn schema() -> ParamType {
563+
ParamType::Tuple(vec![
564+
ParamType::FixedBytes(32),
565+
ParamType::Address,
566+
ParamType::Address,
567+
])
568+
}
569+
570+
/// Encodes `ZkChainSpecificUpgradeData` to a RLP token.
571+
pub fn encode(&self) -> Token {
572+
Token::Tuple(vec![
573+
Token::FixedBytes(self.base_token_asset_id.0.to_vec()),
574+
Token::Address(self.l2_legacy_shared_bridge),
575+
Token::Address(self.predeployed_l2_weth_address),
576+
Token::Address(self.base_token_l1_address),
577+
Token::String(self.base_token_name.clone()),
578+
Token::String(self.base_token_symbol.clone()),
579+
])
580+
}
581+
582+
pub fn encode_bytes(&self) -> Vec<u8> {
583+
ethabi::encode(&[self.encode()])
584+
}
585+
}

0 commit comments

Comments
 (0)