From 2cece107848e8fa7130744012ad71ee11f6da730 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Mon, 11 Nov 2024 07:12:08 -0600 Subject: [PATCH] fix: update `run` with dynamic fee params (#377) * chore: updated scaled factors * fix: update scale factors * feat: fetch fee params from mainnet to init era-test-node * chore: cleanup * fix: fixes gas params for run and updates scale factors * chore: remove logs from override * chore: update zks_estimateFee test --- e2e-tests/test/zks-apis.test.ts | 25 ++++++++++-------- src/config/cli.rs | 7 ++++- src/config/mod.rs | 14 +++++----- src/fork.rs | 6 ++--- src/main.rs | 45 +++++++++++++++++++++++++++++++-- src/node/eth.rs | 2 +- src/node/fee_model.rs | 24 ++++++------------ src/node/in_memory.rs | 1 + src/node/zks.rs | 6 ++--- 9 files changed, 86 insertions(+), 44 deletions(-) diff --git a/e2e-tests/test/zks-apis.test.ts b/e2e-tests/test/zks-apis.test.ts index 3d361d9b..8b7489a5 100644 --- a/e2e-tests/test/zks-apis.test.ts +++ b/e2e-tests/test/zks-apis.test.ts @@ -17,7 +17,7 @@ interface Fee { } describe("zks_estimateFee", function () { - it("Should return fee estimation data for transfer of 1 ETH", async function () { + it("Should return valid fee estimation data for transfer of 1 ETH", async function () { // Arrange const wallet = new Wallet(RichAccounts[0].PrivateKey, provider); const userWallet = Wallet.createRandom().connect(provider); @@ -29,17 +29,20 @@ describe("zks_estimateFee", function () { // Act const response: Fee = await provider.send("zks_estimateFee", [transaction]); + // Assert - expect(ethers.BigNumber.from(response.gas_limit).toNumber()).to.eql(4048728, "Unexpected gas_limit"); - expect(ethers.BigNumber.from(response.gas_per_pubdata_limit)).to.eql( - ethers.BigNumber.from("50000"), - "Unexpected gas_per_pubdata_limit" - ); - expect(ethers.BigNumber.from(response.max_fee_per_gas).toNumber()).to.eql(37500000, "Unexpected max_fee_per_gas"); - expect(ethers.BigNumber.from(response.max_priority_fee_per_gas)).to.eql( - ethers.BigNumber.from("0"), - "Unexpected max_priority_fee_per_gas" - ); + expect(response).to.have.property("gas_limit"); + expect(response).to.have.property("gas_per_pubdata_limit"); + expect(response).to.have.property("max_fee_per_gas"); + expect(response).to.have.property("max_priority_fee_per_gas"); + + const gasLimit = ethers.BigNumber.from(response.gas_limit); + const gasPerPubdataLimit = ethers.BigNumber.from(response.gas_per_pubdata_limit); + const maxFeePerGas = ethers.BigNumber.from(response.max_fee_per_gas); + + expect(gasLimit.toNumber()).to.be.greaterThan(0, "gas_limit should be greater than 0"); + expect(gasPerPubdataLimit.toNumber()).to.be.greaterThan(0, "gas_per_pubdata_limit should be greater than 0"); + expect(maxFeePerGas.toNumber()).to.be.greaterThan(0, "max_fee_per_gas should be greater than 0"); }); }); diff --git a/src/config/cli.rs b/src/config/cli.rs index d580cca9..6b7face2 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -104,6 +104,11 @@ pub struct Cli { /// Use a given chain id. If not set uses 260 (or the one from the forked network). #[arg(long)] pub chain_id: Option, + + /// Run the node in offline mode. This will disable all network requests. + /// Can only be run alongside `run` command. + #[arg(long)] + pub offline: bool, } #[derive(Debug, Subcommand)] @@ -125,7 +130,7 @@ pub struct ForkArgs { /// If not set - will start a new network from genesis. /// If set - will try to fork a remote network. Possible values: /// - mainnet - /// - testnet + /// - sepolia-testnet /// - http://XXX:YY pub network: String, // Fork at a given L2 miniblock height. diff --git a/src/config/mod.rs b/src/config/mod.rs index b50d67a6..29da1fde 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -301,15 +301,13 @@ pub mod node { pub mod gas { use serde::Deserialize; - /// L1 Gas Price. - pub const DEFAULT_L1_GAS_PRICE: u64 = 50_000_000_000; - // TODO: for now, that's fine, as computation overhead is set to zero, but we may consider using calculated fee input everywhere. + pub const DEFAULT_L1_GAS_PRICE: u64 = 14_932_364_075; /// The default L2 Gas Price to be used if not supplied via the CLI argument. - pub const DEFAULT_L2_GAS_PRICE: u64 = 25_000_000; - // Default fair pubdata price based on an average from Sepolia Testnet blocks - pub const DEFAULT_FAIR_PUBDATA_PRICE: u64 = 450_000_000_000; + pub const DEFAULT_L2_GAS_PRICE: u64 = 45_250_000; + /// Default fair pubdata price based on the provided value. + pub const DEFAULT_FAIR_PUBDATA_PRICE: u64 = 13_607_659_111; /// L1 Gas Price Scale Factor for gas estimation. - pub const DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR: f64 = 1.5; + pub const DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR: f64 = 2.0; /// The factor by which to scale the gasLimit. pub const DEFAULT_ESTIMATE_GAS_SCALE_FACTOR: f32 = 1.3; @@ -319,6 +317,8 @@ pub mod gas { pub l1_gas_price: Option, /// L2 gas price. pub l2_gas_price: Option, + /// Fair pubdata price. + pub l1_pubdata_price: Option, /// Factors used in estimating gas. pub estimation: Option, } diff --git a/src/fork.rs b/src/fork.rs index 76d2ac5c..d5390c3c 100644 --- a/src/fork.rs +++ b/src/fork.rs @@ -81,12 +81,12 @@ impl ForkNetwork { ForkNetwork::Other(url) => url, } } - + // TODO: This needs to be dynamic based on the network. /// Returns the local gas scale factors currently in use by the upstream network. pub fn local_gas_scale_factors(&self) -> (f64, f32) { match self { - ForkNetwork::Mainnet => (1.5, 1.2), - ForkNetwork::SepoliaTestnet => (2.0, 1.2), + ForkNetwork::Mainnet => (1.5, 1.4), + ForkNetwork::SepoliaTestnet => (2.0, 1.3), ForkNetwork::GoerliTestnet => (1.2, 1.2), ForkNetwork::Other(_) => ( DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, diff --git a/src/main.rs b/src/main.rs index 9a7c9d25..58bb8ebd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,10 @@ use bytecode_override::override_bytecodes; use clap::Parser; use colored::Colorize; use config::cli::{Cli, Command}; +use config::gas::{ + Estimation, GasConfig, DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, + DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, +}; use config::TestNodeConfig; use fork::{ForkDetails, ForkSource}; use http_fork_source::HttpForkSource; @@ -31,13 +35,14 @@ mod testing; mod utils; use node::InMemoryNode; - use std::fs::File; use std::{ env, net::{IpAddr, Ipv4Addr, SocketAddr}, str::FromStr, }; +use zksync_types::fee_model::FeeParams; +use zksync_web3_decl::namespaces::ZksNamespaceClient; use futures::{ channel::oneshot, @@ -118,7 +123,43 @@ async fn main() -> anyhow::Result<()> { // Use `Command::Run` as default. let command = opt.command.as_ref().unwrap_or(&Command::Run); let fork_details = match command { - Command::Run => None, + Command::Run => { + if opt.offline { + tracing::warn!( + "Running in offline mode: default fee parameters will be used. \ + To override, specify values in `config.toml` and use the `--config` flag." + ); + None + } else { + // Initialize the client to get the fee params + let (_, client) = ForkDetails::fork_network_and_client("mainnet") + .map_err(|e| anyhow!("Failed to initialize client: {:?}", e))?; + + let fee = client.get_fee_params().await.map_err(|e| { + tracing::error!("Failed to fetch fee params: {:?}", e); + anyhow!(e) + })?; + + let gas_config = match fee { + FeeParams::V2(fee_v2) => GasConfig { + l1_gas_price: Some(fee_v2.l1_gas_price()), + l2_gas_price: Some(fee_v2.config().minimal_l2_gas_price), + l1_pubdata_price: Some(fee_v2.l1_pubdata_price()), + estimation: Some(Estimation { + price_scale_factor: Some(DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR), + limit_scale_factor: Some(DEFAULT_ESTIMATE_GAS_SCALE_FACTOR), + }), + }, + FeeParams::V1(_) => { + return Err(anyhow!("Unsupported FeeParams::V1 in this context")) + } + }; + + config.gas = Some(gas_config); + + None + } + } Command::Fork(fork) => { match ForkDetails::from_network(&fork.network, fork.fork_block_number, config.cache) .await diff --git a/src/node/eth.rs b/src/node/eth.rs index 251bb04b..af76bd44 100644 --- a/src/node/eth.rs +++ b/src/node/eth.rs @@ -2400,7 +2400,7 @@ mod tests { .await .expect("failed getting filter changes") { - FilterChanges::Logs(result) => assert_eq!(3, result.len()), + FilterChanges::Logs(result) => assert_eq!(4, result.len()), changes => panic!("unexpected filter changes: {:?}", changes), } diff --git a/src/node/fee_model.rs b/src/node/fee_model.rs index 9984422a..565013f4 100644 --- a/src/node/fee_model.rs +++ b/src/node/fee_model.rs @@ -1,12 +1,9 @@ use zksync_types::fee_model::{BatchFeeInput, FeeModelConfigV2, FeeParams, FeeParamsV2}; -use zksync_types::L1_GAS_PER_PUBDATA_BYTE; use crate::config::gas::{ GasConfig, DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, - DEFAULT_L1_GAS_PRICE, DEFAULT_L2_GAS_PRICE, + DEFAULT_FAIR_PUBDATA_PRICE, DEFAULT_L1_GAS_PRICE, DEFAULT_L2_GAS_PRICE, }; -use crate::utils::to_human_size; - #[derive(Debug, Clone, PartialEq)] pub struct TestNodeFeeInputProvider { pub l1_gas_price: u64, @@ -63,19 +60,14 @@ impl TestNodeFeeInputProvider { }; if let Some(l1_gas_price) = gas_config.l1_gas_price { - tracing::info!( - "L1 gas price set to {} (overridden from {})", - to_human_size(l1_gas_price.into()), - to_human_size(self.l1_gas_price.into()) - ); self.l1_gas_price = l1_gas_price; } + + if let Some(l1_pubdata_price) = gas_config.l1_pubdata_price { + self.l1_pubdata_price = l1_pubdata_price; + } + if let Some(l2_gas_price) = gas_config.l2_gas_price { - tracing::info!( - "L2 gas price set to {} (overridden from {})", - to_human_size(l2_gas_price.into()), - to_human_size(self.l2_gas_price.into()) - ); self.l2_gas_price = l2_gas_price; } @@ -126,13 +118,13 @@ impl Default for TestNodeFeeInputProvider { fn default() -> Self { Self { l1_gas_price: DEFAULT_L1_GAS_PRICE, - l1_pubdata_price: DEFAULT_L1_GAS_PRICE * L1_GAS_PER_PUBDATA_BYTE as u64, + l1_pubdata_price: DEFAULT_FAIR_PUBDATA_PRICE, l2_gas_price: DEFAULT_L2_GAS_PRICE, compute_overhead_part: 0.0, pubdata_overhead_part: 1.0, batch_overhead_l1_gas: 800000, max_gas_per_batch: 200000000, - max_pubdata_per_batch: 100000, + max_pubdata_per_batch: 500000, estimate_gas_price_scale_factor: DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, estimate_gas_scale_factor: DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, } diff --git a/src/node/in_memory.rs b/src/node/in_memory.rs index 5df71f02..479cb9ea 100644 --- a/src/node/in_memory.rs +++ b/src/node/in_memory.rs @@ -922,6 +922,7 @@ impl InMemoryNode { Ok(GasConfig { l1_gas_price: Some(fee_input_provider.l1_gas_price), l2_gas_price: Some(fee_input_provider.l2_gas_price), + l1_pubdata_price: Some(fee_input_provider.l1_pubdata_price), estimation: Some(gas::Estimation { price_scale_factor: Some(fee_input_provider.estimate_gas_price_scale_factor), limit_scale_factor: Some(fee_input_provider.estimate_gas_scale_factor), diff --git a/src/node/zks.rs b/src/node/zks.rs index 1bfe8405..cf887cc2 100644 --- a/src/node/zks.rs +++ b/src/node/zks.rs @@ -625,10 +625,10 @@ mod tests { let result = node.estimate_fee(mock_request).await.unwrap(); - assert_eq!(result.gas_limit, U256::from(4490368)); - assert_eq!(result.max_fee_per_gas, U256::from(37500000)); + assert_eq!(result.gas_limit, U256::from(279779)); + assert_eq!(result.max_fee_per_gas, U256::from(45250000)); assert_eq!(result.max_priority_fee_per_gas, U256::from(0)); - assert_eq!(result.gas_per_pubdata_limit, U256::from(50000)); + assert_eq!(result.gas_per_pubdata_limit, U256::from(1658)); } #[tokio::test]