From 5db2d451cc503ce9044ebd9869a7ea7421040028 Mon Sep 17 00:00:00 2001 From: Thomas Nguy <81727899+thomas-nguy@users.noreply.github.com> Date: Mon, 22 Jul 2024 10:55:28 +0900 Subject: [PATCH] Problem: eth_sender transaction's base fee is not capped (#61) --- core/lib/config/src/configs/eth_sender.rs | 4 +++ core/lib/config/src/testonly.rs | 1 + core/lib/env_config/src/eth_sender.rs | 2 ++ core/lib/protobuf_config/src/eth.rs | 7 ++++-- .../src/proto/config/eth_sender.proto | 1 + core/node/eth_sender/src/error.rs | 2 ++ core/node/eth_sender/src/eth_fees_oracle.rs | 25 ++++++++++++++++++- core/node/eth_sender/src/eth_tx_manager.rs | 1 + etc/env/base/eth_sender.toml | 3 +++ etc/env/file_based/general.yaml | 1 + 10 files changed, 44 insertions(+), 3 deletions(-) diff --git a/core/lib/config/src/configs/eth_sender.rs b/core/lib/config/src/configs/eth_sender.rs index 714a77294..c7fc25a51 100644 --- a/core/lib/config/src/configs/eth_sender.rs +++ b/core/lib/config/src/configs/eth_sender.rs @@ -43,6 +43,7 @@ impl EthConfig { tx_aggregation_paused: false, tx_aggregation_only_prove_and_execute: false, signing_mode: SigningMode::PrivateKey, + max_acceptable_base_fee_in_wei: 100000000000, }), gas_adjuster: Some(GasAdjusterConfig { default_priority_fee_per_gas: 1000000000, @@ -138,6 +139,9 @@ pub struct SenderConfig { /// Type of signing client for Ethereum transactions. pub signing_mode: SigningMode, + + /// Max acceptable base fee the sender is allowed to use to send L1 txs. + pub max_acceptable_base_fee_in_wei: u64, } impl SenderConfig { diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index 3d007419a..80482e5ea 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -415,6 +415,7 @@ impl Distribution for EncodeDist { tx_aggregation_paused: false, tx_aggregation_only_prove_and_execute: false, signing_mode: SigningMode::PrivateKey, + max_acceptable_base_fee_in_wei: self.sample(rng), } } } diff --git a/core/lib/env_config/src/eth_sender.rs b/core/lib/env_config/src/eth_sender.rs index 07d44648e..a1d4b6d3b 100644 --- a/core/lib/env_config/src/eth_sender.rs +++ b/core/lib/env_config/src/eth_sender.rs @@ -72,6 +72,7 @@ mod tests { tx_aggregation_only_prove_and_execute: false, tx_aggregation_paused: false, signing_mode: SigningMode::PrivateKey, + max_acceptable_base_fee_in_wei: 100_000_000_000, }), gas_adjuster: Some(GasAdjusterConfig { default_priority_fee_per_gas: 20000000000, @@ -138,6 +139,7 @@ mod tests { ETH_WATCH_ETH_NODE_POLL_INTERVAL="300" ETH_SENDER_SENDER_SIGNING_MODE="PrivateKey" ETH_CLIENT_WEB3_URL="http://127.0.0.1:8545" + ETH_SENDER_SENDER_MAX_ACCEPTABLE_BASE_FEE_IN_WEI="100000000000" "#; lock.set_env(config); diff --git a/core/lib/protobuf_config/src/eth.rs b/core/lib/protobuf_config/src/eth.rs index 7eede7f7f..ff8ebd939 100644 --- a/core/lib/protobuf_config/src/eth.rs +++ b/core/lib/protobuf_config/src/eth.rs @@ -137,6 +137,10 @@ impl ProtoRepr for proto::Sender { .and_then(|x| Ok(proto::SigningMode::try_from(*x)?)) .context("signing_mode")? .parse(), + gkms_op_key_name: self.gkms_op_key_name.clone(), + gkms_op_blob_key_name: self.gkms_op_blob_key_name.clone(), + max_acceptable_base_fee_in_wei: *required(&self.max_acceptable_base_fee_in_wei) + .context("max_acceptable_base_fee_in_wei")?, }) } @@ -167,9 +171,8 @@ impl ProtoRepr for proto::Sender { pubdata_sending_mode: Some( proto::PubdataSendingMode::new(&this.pubdata_sending_mode).into(), ), - tx_aggregation_only_prove_and_execute: Some(this.tx_aggregation_only_prove_and_execute), - tx_aggregation_paused: Some(this.tx_aggregation_paused), signing_mode: Some(proto::SigningMode::new(&this.signing_mode).into()), + max_acceptable_base_fee_in_wei: Some(this.max_acceptable_base_fee_in_wei), } } } diff --git a/core/lib/protobuf_config/src/proto/config/eth_sender.proto b/core/lib/protobuf_config/src/proto/config/eth_sender.proto index aa3d1da8a..303a5fcf3 100644 --- a/core/lib/protobuf_config/src/proto/config/eth_sender.proto +++ b/core/lib/protobuf_config/src/proto/config/eth_sender.proto @@ -54,6 +54,7 @@ message Sender { optional bool tx_aggregation_paused = 20; // required optional bool tx_aggregation_only_prove_and_execute = 21; // required optional SigningMode signing_mode = 99; // required + optional uint64 max_acceptable_base_fee_in_wei = 100; // required; wei } message GasAdjuster { diff --git a/core/node/eth_sender/src/error.rs b/core/node/eth_sender/src/error.rs index ecb89c1f3..c81a85d85 100644 --- a/core/node/eth_sender/src/error.rs +++ b/core/node/eth_sender/src/error.rs @@ -9,6 +9,8 @@ pub enum EthSenderError { ContractCall(#[from] ContractCallError), #[error("Token parsing error: {0}")] Parse(#[from] contract::Error), + #[error("Max base fee exceeded")] + ExceedMaxBaseFee, } impl EthSenderError { diff --git a/core/node/eth_sender/src/eth_fees_oracle.rs b/core/node/eth_sender/src/eth_fees_oracle.rs index 271a33d49..7be7c2606 100644 --- a/core/node/eth_sender/src/eth_fees_oracle.rs +++ b/core/node/eth_sender/src/eth_fees_oracle.rs @@ -8,7 +8,9 @@ use zksync_eth_client::{ClientError, EnrichedClientError}; use zksync_node_fee_model::l1_gas_price::TxParamsProvider; use zksync_types::eth_sender::TxHistory; -use crate::{abstract_l1_interface::OperatorType, EthSenderError}; +use crate::{ + abstract_l1_interface::OperatorType, EthSenderError, EthSenderError::ExceedMaxBaseFee, +}; #[derive(Debug)] pub(crate) struct EthFees { @@ -32,6 +34,7 @@ pub(crate) trait EthFeesOracle: 'static + Sync + Send + fmt::Debug { pub(crate) struct GasAdjusterFeesOracle { pub gas_adjuster: Arc, pub max_acceptable_priority_fee_in_gwei: u64, + pub max_acceptable_base_fee_in_wei: u64, } impl GasAdjusterFeesOracle { @@ -43,6 +46,16 @@ impl GasAdjusterFeesOracle { let priority_fee_per_gas = self.gas_adjuster.get_blob_tx_priority_fee(); let blob_base_fee_per_gas = Some(self.gas_adjuster.get_blob_tx_blob_base_fee()); + if base_fee_per_gas > self.max_acceptable_base_fee_in_wei { + tracing::info!( + "base fee per gas: {} exceed max acceptable fee in configuration: {}, skip transaction", + base_fee_per_gas, + self.max_acceptable_base_fee_in_wei + ); + + return Err(ExceedMaxBaseFee); + } + if let Some(previous_sent_tx) = previous_sent_tx { // for blob transactions on re-sending need to double all gas prices return Ok(EthFees { @@ -80,6 +93,16 @@ impl GasAdjusterFeesOracle { )?; } + if base_fee_per_gas > self.max_acceptable_base_fee_in_wei { + tracing::info!( + "base fee per gas: {} exceed max acceptable fee in configuration: {}, skip transaction", + base_fee_per_gas, + self.max_acceptable_base_fee_in_wei + ); + + return Err(ExceedMaxBaseFee); + } + let mut priority_fee_per_gas = self.gas_adjuster.get_priority_fee(); if let Some(previous_sent_tx) = previous_sent_tx { diff --git a/core/node/eth_sender/src/eth_tx_manager.rs b/core/node/eth_sender/src/eth_tx_manager.rs index 0d78ab71c..fb8470548 100644 --- a/core/node/eth_sender/src/eth_tx_manager.rs +++ b/core/node/eth_sender/src/eth_tx_manager.rs @@ -48,6 +48,7 @@ impl EthTxManager { let fees_oracle = GasAdjusterFeesOracle { gas_adjuster, max_acceptable_priority_fee_in_gwei: config.max_acceptable_priority_fee_in_gwei, + max_acceptable_base_fee_in_wei: config.max_acceptable_base_fee_in_wei, }; let l1_interface = Box::new(RealL1Interface { ethereum_gateway, diff --git a/etc/env/base/eth_sender.toml b/etc/env/base/eth_sender.toml index 0cead97cf..8394baca3 100644 --- a/etc/env/base/eth_sender.toml +++ b/etc/env/base/eth_sender.toml @@ -50,6 +50,9 @@ pubdata_sending_mode = "Blobs" signing_mode = "PrivateKey" +# Max acceptable base fee for sending tx to L1 +max_acceptable_base_fee_in_wei = 1000000000000 + [eth_sender.gas_adjuster] # Priority fee to be used by GasAdjuster (in wei). default_priority_fee_per_gas = 1_000_000_000 diff --git a/etc/env/file_based/general.yaml b/etc/env/file_based/general.yaml index 19921cf53..2c2701866 100644 --- a/etc/env/file_based/general.yaml +++ b/etc/env/file_based/general.yaml @@ -108,6 +108,7 @@ eth: max_aggregated_tx_gas: 15000000 max_acceptable_priority_fee_in_gwei: 100000000000 pubdata_sending_mode: BLOBS + max_acceptable_base_fee_in_wei: 100000000000 gas_adjuster: default_priority_fee_per_gas: 1000000000 max_base_fee_samples: 100