Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Server 10k gwei limit on gas price and 1M limit on pubdata price #2460

Merged
merged 15 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion core/lib/types/src/fee_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ pub struct FeeModelConfigV2 {
/// The maximum amount of pubdata that can be used by the batch. Note that if the calldata is used as pubdata, this variable should not exceed 128kb.
pub max_pubdata_per_batch: u64,
}

impl Default for FeeModelConfig {
/// Config with all zeroes is not a valid config (since for instance having 0 max gas per batch may incur division by zero),
/// so we implement a sensible default config here.
Expand Down
110 changes: 99 additions & 11 deletions core/node/fee_model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ pub trait BatchFeeModelInputProvider: fmt::Debug + 'static + Send + Sync {
params,
l1_gas_price_scale_factor,
)),
FeeParams::V2(params) => {
BatchFeeInput::PubdataIndependent(compute_batch_fee_model_input_v2(
FeeParams::V2(params) => BatchFeeInput::PubdataIndependent(
clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(
params,
l1_gas_price_scale_factor,
l1_pubdata_price_scale_factor,
))
}
)),
),
})
}

Expand Down Expand Up @@ -191,7 +191,7 @@ fn compute_batch_fee_model_input_v2(
let l1_batch_overhead_wei = U256::from(l1_gas_price) * U256::from(batch_overhead_l1_gas);

let fair_l2_gas_price = {
// Firstly, we calculate which part of the overall overhead overhead each unit of L2 gas should cover.
// Firstly, we calculate which part of the overall overhead each unit of L2 gas should cover.
let l1_batch_overhead_per_gas =
ceil_div_u256(l1_batch_overhead_wei, U256::from(max_gas_per_batch));

Expand All @@ -206,7 +206,7 @@ fn compute_batch_fee_model_input_v2(
};

let fair_pubdata_price = {
// Firstly, we calculate which part of the overall overhead overhead each pubdata byte should cover.
// Firstly, we calculate which part of the overall overhead each pubdata byte should cover.
cytadela8 marked this conversation as resolved.
Show resolved Hide resolved
let l1_batch_overhead_per_pubdata =
ceil_div_u256(l1_batch_overhead_wei, U256::from(max_pubdata_per_batch));

Expand All @@ -227,6 +227,33 @@ fn compute_batch_fee_model_input_v2(
}
}

/// Bootloader places limitations on fair_l2_gas_price and fair_pubdata_price.
/// (MAX_ALLOWED_FAIR_L2_GAS_PRICE and MAX_ALLOWED_FAIR_PUBDATA_PRICE in bootloader code respectively)
/// Server needs to clip this prices in order to allow chain continues operation at a loss. The alternative
/// would be to stop accepting the transactions until the conditions improve.
/// TODO PE-153, to be removed when bootloader limitation is removed
cytadela8 marked this conversation as resolved.
Show resolved Hide resolved
fn clip_batch_fee_model_input_v2(
fee_model: PubdataIndependentBatchFeeModelInput,
) -> PubdataIndependentBatchFeeModelInput {
/// MAX_ALLOWED_FAIR_L2_GAS_PRICE
const MAXIMUM_L2_GAS_PRICE: u64 = 10_000_000_000_000;
/// MAX_ALLOWED_FAIR_PUBDATA_PRICE
const MAXIMUM_PUBDATA_PRICE: u64 = 1_000_000_000_000_000;
PubdataIndependentBatchFeeModelInput {
l1_gas_price: fee_model.l1_gas_price,
fair_l2_gas_price: if fee_model.fair_l2_gas_price < MAXIMUM_L2_GAS_PRICE {
fee_model.fair_l2_gas_price
} else {
MAXIMUM_L2_GAS_PRICE
},
fair_pubdata_price: if fee_model.fair_pubdata_price < MAXIMUM_PUBDATA_PRICE {
fee_model.fair_pubdata_price
} else {
MAXIMUM_PUBDATA_PRICE
},
cytadela8 marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Mock [`BatchFeeModelInputProvider`] implementation that returns a constant value.
/// Intended to be used in tests only.
#[derive(Debug)]
Expand Down Expand Up @@ -259,9 +286,10 @@ mod tests {
// To test that overflow never happens, we'll use giant L1 gas price, i.e.
// almost realistic very large value of 100k gwei. Since it is so large, we'll also
// use it for the L1 pubdata price.
const GIANT_L1_GAS_PRICE: u64 = 100_000_000_000_000;
const GWEI: u64 = 1_000_000_000;
const GIANT_L1_GAS_PRICE: u64 = 100_000 * GWEI;

// As a small small L2 gas price we'll use the value of 1 wei.
// As a small L2 gas price we'll use the value of 1 wei.
const SMALL_L1_GAS_PRICE: u64 = 1;

#[test]
Expand Down Expand Up @@ -314,7 +342,8 @@ mod tests {
BaseTokenConversionRatio::default(),
);

let input = compute_batch_fee_model_input_v2(params, 1.0, 1.0);
let input =
clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0));

assert_eq!(input.l1_gas_price, SMALL_L1_GAS_PRICE);
assert_eq!(input.fair_l2_gas_price, SMALL_L1_GAS_PRICE);
Expand All @@ -340,7 +369,8 @@ mod tests {
BaseTokenConversionRatio::default(),
);

let input = compute_batch_fee_model_input_v2(params, 1.0, 1.0);
let input =
clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0));
assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE);
// The fair L2 gas price is identical to the minimal one.
assert_eq!(input.fair_l2_gas_price, 100_000_000_000);
Expand Down Expand Up @@ -491,6 +521,64 @@ mod tests {
);
}

#[test]
fn test_compute_batch_fee_model_input_v2_gas_price_over_limit_due_to_l1_gas() {
// In this test we check the gas price limit works as expected
let config = FeeModelConfigV2 {
minimal_l2_gas_price: 100 * GWEI,
compute_overhead_part: 0.5,
pubdata_overhead_part: 0.5,
batch_overhead_l1_gas: 700_000,
max_gas_per_batch: 500_000_000,
max_pubdata_per_batch: 100_000,
};

let l1_gas_price = 1_000_000_000 * GWEI;
let params = FeeParamsV2::new(
config,
l1_gas_price,
GIANT_L1_GAS_PRICE,
BaseTokenConversionRatio::default(),
);

let input =
clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0));
assert_eq!(input.l1_gas_price, l1_gas_price);
// The fair L2 gas price is identical to the maximum
assert_eq!(input.fair_l2_gas_price, 10_000 * GWEI);
assert_eq!(input.fair_pubdata_price, 1_000_000 * GWEI);
}

#[test]
fn test_compute_batch_fee_model_input_v2_gas_price_over_limit_due_to_conversion_rate() {
// In this test we check the gas price limit works as expected
let config = FeeModelConfigV2 {
minimal_l2_gas_price: GWEI,
compute_overhead_part: 0.5,
pubdata_overhead_part: 0.5,
batch_overhead_l1_gas: 700_000,
max_gas_per_batch: 500_000_000,
max_pubdata_per_batch: 100_000,
};

let params = FeeParamsV2::new(
config,
GWEI,
2 * GWEI,
BaseTokenConversionRatio {
numerator: NonZeroU64::new(3_000_000).unwrap(),
denominator: NonZeroU64::new(1).unwrap(),
},
);

let input =
clip_batch_fee_model_input_v2(compute_batch_fee_model_input_v2(params, 1.0, 1.0));
assert_eq!(input.l1_gas_price, 3_000_000 * GWEI);
// The fair L2 gas price is identical to the maximum
assert_eq!(input.fair_l2_gas_price, 10_000 * GWEI);
assert_eq!(input.fair_pubdata_price, 1_000_000 * GWEI);
}

#[tokio::test]
async fn test_get_fee_model_params() {
struct TestCase {
Expand Down Expand Up @@ -544,7 +632,7 @@ mod tests {
expected_l1_pubdata_price: 3000,
},
TestCase {
name: "Large conversion - 1 ETH = 1_000 BaseToken",
name: "Large conversion - 1 ETH = 1_000_000 BaseToken",
conversion_ratio: BaseTokenConversionRatio {
numerator: NonZeroU64::new(1_000_000).unwrap(),
denominator: NonZeroU64::new(1).unwrap(),
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/advanced/07_fee_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ proportional to the part of the batch you are using.
| gas_limit | `<= max_allowed_l2_tx_gas_limit` | The limit (4G gas) is set in the `StateKeeper` config; it's the limit for the entire L1 batch. |
| gas_limit | `<= MAX_GAS_PER_TRANSACTION` | This limit (80M) is set in bootloader. |
| gas_limit | `> l2_tx_intrinsic_gas` | This limit (around 14k gas) is hardcoded to ensure that the transaction has enough gas to start. |
| max_fee_per_gas | `<= fair_l2_gas_price` | Fair L2 gas price (0.25 Gwei) is set in the `StateKeeper` config |
| max_fee_per_gas | `>= fair_l2_gas_price` | Fair L2 gas price (0.1 Gwei on Era) is set in the `StateKeeper` config |
perekopskiy marked this conversation as resolved.
Show resolved Hide resolved
| | `<=validation_computational_gas_limit` | There is an additional, stricter limit (300k gas) on the amount of gas that a transaction can use during validation. |

### Why do we have two limits: 80M and 4G
Expand Down
Loading