Skip to content

Commit 80b990c

Browse files
committed
apollo_gateway: reject tx with low l2 gas price
1 parent a1cf12f commit 80b990c

File tree

5 files changed

+54
-4
lines changed

5 files changed

+54
-4
lines changed

Cargo.lock

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

crates/apollo_gateway/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ cairo-lang-starknet-classes.workspace = true
3131
futures.workspace = true
3232
lazy_static.workspace = true
3333
mempool_test_utils.workspace = true
34+
num-rational.workspace = true
3435
reqwest.workspace = true
3536
serde.workspace = true
3637
serde_json.workspace = true

crates/apollo_gateway/src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ impl SerializeConfig for GatewayConfig {
4444

4545
#[derive(Clone, Debug, Serialize, Deserialize, Validate, PartialEq)]
4646
pub struct StatelessTransactionValidatorConfig {
47+
// TODO(Arni): Align the name of this field with the mempool config, and all other places where
48+
// validation is skipped during the systems bootstrap phase.
4749
// If true, validates that the resource bounds are not zero.
4850
pub validate_non_zero_resource_bounds: bool,
4951
// TODO(AlonH): Remove this field and use the one from the versioned constants.

crates/apollo_gateway/src/gateway.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@ use apollo_proc_macros::sequencer_latency_histogram;
2626
use apollo_state_sync_types::communication::SharedStateSyncClient;
2727
use axum::async_trait;
2828
use blockifier::context::ChainInfo;
29+
use num_rational::Ratio;
30+
use starknet_api::block::NonzeroGasPrice;
2931
use starknet_api::executable_transaction::ValidateCompiledClassHashError;
3032
use starknet_api::rpc_transaction::{
3133
InternalRpcTransaction,
3234
InternalRpcTransactionWithoutTxHash,
3335
RpcTransaction,
3436
};
37+
use starknet_api::transaction::fields::ValidResourceBounds;
3538
use tracing::{debug, error, info, instrument, warn, Span};
3639

3740
use crate::config::GatewayConfig;
@@ -46,6 +49,10 @@ use crate::sync_state_reader::SyncStateReaderFactory;
4649
#[path = "gateway_test.rs"]
4750
pub mod gateway_test;
4851

52+
// TODO(Arni): Move to a config.
53+
// Minimum gas price as percentage of threshold to accept transactions.
54+
const MIN_GAS_PRICE_PRECENTAGE: u8 = 80; // E.g., 80 to require 80% of threshold.
55+
4956
#[derive(Clone)]
5057
pub struct Gateway {
5158
pub config: Arc<GatewayConfig>,
@@ -203,10 +210,17 @@ impl ProcessTxBlockingTask {
203210
let mut validator = self
204211
.stateful_tx_validator
205212
.instantiate_validator(self.state_reader_factory.as_ref(), &self.chain_info)?;
206-
// TODO(Arni): Use the _l2_gas_price reject transactions that do not pass the gas price
207-
// threshold.
208-
let _l2_gas_price =
209-
validator.block_context().block_info().gas_prices.strk_gas_prices.l2_gas_price;
213+
214+
// Skip this validation during the systems bootstrap phase.
215+
if self.stateless_tx_validator.config.validate_non_zero_resource_bounds {
216+
let l2_gas_price =
217+
validator.block_context().block_info().gas_prices.strk_gas_prices.l2_gas_price;
218+
validate_tx_l2_gas_price_within_threshold(
219+
executable_tx.resource_bounds(),
220+
l2_gas_price,
221+
)?;
222+
}
223+
210224
let address = executable_tx.contract_address();
211225
let nonce = validator.get_nonce(address).map_err(|e| {
212226
error!("Failed to get nonce for sender address {}: {}", address, e);
@@ -226,6 +240,36 @@ impl ProcessTxBlockingTask {
226240
}
227241
}
228242

243+
// TODO(Arni): Consider running this validation for all gas prices.
244+
fn validate_tx_l2_gas_price_within_threshold(
245+
tx_resource_bounds: ValidResourceBounds,
246+
previous_block_l2_gas_price: NonzeroGasPrice,
247+
) -> GatewayResult<()> {
248+
match tx_resource_bounds {
249+
ValidResourceBounds::AllResources(tx_resource_bounds) => {
250+
let tx_l2_gas_price = tx_resource_bounds.l2_gas.max_price_per_unit;
251+
let gas_price_threshold_multiplier =
252+
Ratio::new(MIN_GAS_PRICE_PRECENTAGE.into(), 100_u128);
253+
let threshold =
254+
(gas_price_threshold_multiplier * previous_block_l2_gas_price.get().0).to_integer();
255+
if tx_l2_gas_price.0 < threshold {
256+
return Err(StarknetError {
257+
code: StarknetErrorCode::KnownErrorCode(KnownStarknetErrorCode::GasPriceTooLow),
258+
message: format!(
259+
"Transaction gas price {} is below the required threshold {}.",
260+
tx_l2_gas_price, threshold
261+
),
262+
});
263+
}
264+
}
265+
ValidResourceBounds::L1Gas(_) => {
266+
// No validation required for legacy transactions.
267+
}
268+
}
269+
270+
Ok(())
271+
}
272+
229273
fn convert_compiled_class_hash_error(error: ValidateCompiledClassHashError) -> StarknetError {
230274
let ValidateCompiledClassHashError::CompiledClassHashMismatch {
231275
computed_class_hash,

crates/apollo_gateway_types/src/deprecated_gateway_error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ pub enum KnownStarknetErrorCode {
4141
EntryPointNotFoundInContract,
4242
#[serde(rename = "StarknetErrorCode.INSUFFICIENT_ACCOUNT_BALANCE")]
4343
InsufficientAccountBalance,
44+
#[serde(rename = "StarknetErrorCode.GAS_PRICE_TOO_LOW")]
45+
GasPriceTooLow,
4446
#[serde(rename = "StarknetErrorCode.INSUFFICIENT_MAX_FEE")]
4547
InsufficientMaxFee,
4648
#[serde(rename = "StarknetErrorCode.INVALID_COMPILED_CLASS_HASH")]

0 commit comments

Comments
 (0)