From 1cb9d6b6ffdd39c3b8704ac200466cd39fc11850 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Mon, 4 Nov 2024 06:57:32 -0600 Subject: [PATCH] chore(refactor): update so forked networks chainID is used and rename `fork-at` to fork-block-number` (#372) * feat: make use of forked network chainID unless explicitly set by --chain-id arg * fix: update test to reflect changes * chore(refactor): update fork-at to reflect anvils fork-block-number and respects chainID during forking * fix: add alias for cli change --- docs/rustbook/src/usage/fork.md | 4 ++-- src/config/cli.rs | 10 ++++++-- src/fork.rs | 42 ++++++++++++++++++++++----------- src/main.rs | 4 +++- src/node/in_memory.rs | 1 + src/node/zks.rs | 24 +++++++++++++++---- src/testing.rs | 27 +++++++++++++++------ 7 files changed, 81 insertions(+), 31 deletions(-) diff --git a/docs/rustbook/src/usage/fork.md b/docs/rustbook/src/usage/fork.md index 2d01fdfb..344d2bc2 100644 --- a/docs/rustbook/src/usage/fork.md +++ b/docs/rustbook/src/usage/fork.md @@ -42,8 +42,8 @@ This command starts the node, forking it from the latest block on the zkSync Sep You also have the option to specify a custom http endpoint and a custom forking height, like so: ```sh -# Usage: era_test_node fork --fork-at -era_test_node fork --fork-at 7000000 mainnet http://172.17.0.3:3060 +# Usage: era_test_node fork --fork-block-number +era_test_node fork --fork-block-number 7000000 mainnet http://172.17.0.3:3060 ``` ## Sending network calls diff --git a/src/config/cli.rs b/src/config/cli.rs index 2217243a..899f4e19 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -128,10 +128,16 @@ pub struct ForkArgs { /// - testnet /// - http://XXX:YY pub network: String, - #[arg(long)] // Fork at a given L2 miniblock height. // If not set - will use the current finalized block from the network. - pub fork_at: Option, + #[arg( + long, + value_name = "BLOCK", + long_help = "Fetch state from a specific block number over a remote endpoint.", + requires = "fork", + alias = "fork-at" + )] + pub fork_block_number: Option, } #[derive(Debug, Parser)] diff --git a/src/fork.rs b/src/fork.rs index 6c2036a4..76d2ac5c 100644 --- a/src/fork.rs +++ b/src/fork.rs @@ -127,12 +127,13 @@ impl ForkStorage { use_evm_emulator: bool, override_chain_id: Option, ) -> Self { - let chain_id = fork - .as_ref() - .and_then(|d| d.overwrite_chain_id) - .unwrap_or(L2ChainId::from( - override_chain_id.unwrap_or(TEST_NODE_NETWORK_ID), - )); + let chain_id = if let Some(override_id) = override_chain_id { + L2ChainId::from(override_id) + } else { + fork.as_ref() + .and_then(|d| d.overwrite_chain_id) + .unwrap_or(L2ChainId::from(TEST_NODE_NETWORK_ID)) + }; tracing::info!("Starting network with chain id: {:?}", chain_id); ForkStorage { @@ -398,6 +399,8 @@ pub trait ForkSource { pub struct ForkDetails { // Source of the fork data (for example HttpForkSource) pub fork_source: Box, + // Chain ID of fork + pub chain_id: L2ChainId, // Block number at which we forked (the next block to create is l1_block + 1) pub l1_block: L1BatchNumber, // The actual L2 block @@ -453,6 +456,7 @@ pub fn supported_versions_to_string() -> String { impl fmt::Debug for ForkDetails { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ForkDetails") + .field("chain_id", &self.chain_id) .field("l1_block", &self.l1_block) .field("l2_block", &self.l2_block) .field("l2_miniblock", &self.l2_miniblock) @@ -524,6 +528,7 @@ impl ForkDetails { Ok(ForkDetails { fork_source: Box::new(HttpForkSource::new(url.to_owned(), cache_config.clone())), + chain_id: chain_id.unwrap_or_else(|| L2ChainId::from(TEST_NODE_NETWORK_ID)), l1_block: l1_batch_number, l2_block: block, block_timestamp: block_details.base.timestamp, @@ -545,12 +550,15 @@ impl ForkDetails { /// Create a fork from a given network at a given height. pub async fn from_network( fork: &str, - fork_at: Option, + fork_block_number: Option, cache_config: CacheConfig, ) -> eyre::Result { let (network, client) = Self::fork_network_and_client(fork)?; - let l2_miniblock = if let Some(fork_at) = fork_at { - fork_at + let chain_id_u64 = client.chain_id().await?; + let chain_id = L2ChainId::from(chain_id_u64.as_u32()); + + let l2_miniblock = if let Some(fork_block_number) = fork_block_number { + fork_block_number } else { match client.get_block_number().await { Ok(bn) => bn.as_u64(), @@ -559,11 +567,12 @@ impl ForkDetails { } } }; + Self::from_network_and_miniblock_and_chain( network, client, l2_miniblock, - None, + chain_id.into(), cache_config, ) .await @@ -604,7 +613,7 @@ impl ForkDetails { /// Return URL and HTTP client for `hardhat_reset`. pub fn from_url( url: String, - fork_at: Option, + fork_block_number: Option, cache_config: CacheConfig, ) -> eyre::Result { let parsed_url = SensitiveUrl::from_str(&url)?; @@ -612,8 +621,10 @@ impl ForkDetails { let client = builder.build(); block_on(async move { - let l2_miniblock = if let Some(fork_at) = fork_at { - fork_at + let chain_id_u64 = client.chain_id().await?; + let chain_id = L2ChainId::from(chain_id_u64.as_u32()); + let l2_miniblock = if let Some(fork_block_number) = fork_block_number { + fork_block_number } else { client.get_block_number().await?.as_u64() }; @@ -622,7 +633,7 @@ impl ForkDetails { ForkNetwork::Other(url), client, l2_miniblock, - None, + chain_id.into(), cache_config, ) .await @@ -736,6 +747,7 @@ mod tests { DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, DEFAULT_FAIR_PUBDATA_PRICE, DEFAULT_L2_GAS_PRICE, }; + use crate::node::TEST_NODE_NETWORK_ID; use crate::{deps::InMemoryStorage, system_contracts, testing}; use super::{ForkDetails, ForkStorage}; @@ -758,6 +770,7 @@ mod tests { let fork_details = ForkDetails { fork_source: Box::new(external_storage), + chain_id: TEST_NODE_NETWORK_ID.into(), l1_block: L1BatchNumber(1), l2_block: zksync_types::api::Block::::default(), l2_miniblock: 1, @@ -793,6 +806,7 @@ mod tests { fork_source: Box::new(testing::ExternalStorage { raw_storage: InMemoryStorage::default(), }), + chain_id: TEST_NODE_NETWORK_ID.into(), l1_block: L1BatchNumber(0), l2_block: zksync_types::api::Block::::default(), l2_miniblock: 0, diff --git a/src/main.rs b/src/main.rs index 3d07089e..9a7c9d25 100644 --- a/src/main.rs +++ b/src/main.rs @@ -120,7 +120,9 @@ async fn main() -> anyhow::Result<()> { let fork_details = match command { Command::Run => None, Command::Fork(fork) => { - match ForkDetails::from_network(&fork.network, fork.fork_at, config.cache).await { + match ForkDetails::from_network(&fork.network, fork.fork_block_number, config.cache) + .await + { Ok(fd) => Some(fd), Err(error) => { tracing::error!("cannot fork: {:?}", error); diff --git a/src/node/in_memory.rs b/src/node/in_memory.rs index 704ce568..5df71f02 100644 --- a/src/node/in_memory.rs +++ b/src/node/in_memory.rs @@ -1932,6 +1932,7 @@ mod tests { let node: InMemoryNode = InMemoryNode::new( Some(ForkDetails { fork_source: Box::new(mock_db), + chain_id: TEST_NODE_NETWORK_ID.into(), l1_block: L1BatchNumber(1), l2_block: Block::default(), l2_miniblock: 2, diff --git a/src/node/zks.rs b/src/node/zks.rs index b6ba5585..1bfe8405 100644 --- a/src/node/zks.rs +++ b/src/node/zks.rs @@ -1165,6 +1165,19 @@ mod tests { serde_json::json!({ "jsonrpc": "2.0", "id": 0, + "method": "eth_chainId", + }), + serde_json::json!({ + "jsonrpc": "2.0", + "id": 0, + "result": "0x104", + }), + ); + + mock_server.expect( + serde_json::json!({ + "jsonrpc": "2.0", + "id": 1, "method": "zks_getBlockDetails", "params": [1] }), @@ -1193,13 +1206,13 @@ mod tests { "status": "verified", "timestamp": 1000 }, - "id": 0 + "id": 1 }), ); mock_server.expect( serde_json::json!({ "jsonrpc": "2.0", - "id": 1, + "id": 2, "method": "eth_getBlockByHash", "params": ["0xdaa77426c30c02a43d9fba4e841a6556c524d47030762eb14dc4af897e605d9b", true] }), @@ -1231,7 +1244,7 @@ mod tests { "transactionsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "uncles": [] }, - "id": 1 + "id": 2 }), ); mock_server.expect( @@ -1258,7 +1271,7 @@ mod tests { mock_server.expect( serde_json::json!({ "jsonrpc": "2.0", - "id": 2, + "id": 3, "method": "zks_getFeeParams", }), serde_json::json!({ @@ -1277,7 +1290,7 @@ mod tests { "l1_pubdata_price": 100780475095u64 } }, - "id": 2 + "id": 3 }), ); @@ -1291,6 +1304,7 @@ mod tests { Default::default(), Default::default(), ); + { let inner = node.get_inner(); let writer = inner.write().unwrap(); diff --git a/src/testing.rs b/src/testing.rs index 7c46ec8c..61ece0ac 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -61,24 +61,37 @@ impl MockServer { Expectation::matching(request::body(json_decoded(eq(serde_json::json!({ "jsonrpc": "2.0", "id": 0, - "method": "eth_blockNumber", + "method": "eth_chainId", }))))) .respond_with(json_encoded(serde_json::json!({ "jsonrpc": "2.0", "id": 0, - "result": format!("{:#x}", block_config.number), + "result": "0x104", }))), ); + server.expect( Expectation::matching(request::body(json_decoded(eq(serde_json::json!({ "jsonrpc": "2.0", "id": 1, + "method": "eth_blockNumber", + }))))) + .respond_with(json_encoded(serde_json::json!({ + "jsonrpc": "2.0", + "id": 1, + "result": format!("{:#x}", block_config.number), + }))), + ); + server.expect( + Expectation::matching(request::body(json_decoded(eq(serde_json::json!({ + "jsonrpc": "2.0", + "id": 2, "method": "zks_getBlockDetails", "params": [ block_config.number ], }))))) .respond_with(json_encoded(serde_json::json!({ "jsonrpc": "2.0", - "id": 1, + "id": 2, "result": { "number": block_config.number, "l1BatchNumber": 1, @@ -107,13 +120,13 @@ impl MockServer { server.expect( Expectation::matching(request::body(json_decoded(eq(serde_json::json!({ "jsonrpc": "2.0", - "id": 2, + "id": 3, "method": "eth_getBlockByHash", "params": [format!("{:#x}", block_config.hash), true], }))))).times(0..) .respond_with(json_encoded(serde_json::json!({ "jsonrpc": "2.0", - "id": 2, + "id": 3, "result": { "hash": format!("{:#x}", block_config.hash), "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -151,7 +164,7 @@ impl MockServer { server.expect( Expectation::matching(request::body(json_decoded(eq(serde_json::json!({ "jsonrpc": "2.0", - "id": 3, + "id": 4, "method": "zks_getFeeParams", }))))) .respond_with(json_encoded(serde_json::json!( @@ -171,7 +184,7 @@ impl MockServer { "l1_pubdata_price": 100780475095u64 } }, - "id": 3 + "id": 4 }))), );