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 8 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
14 changes: 14 additions & 0 deletions core/lib/types/src/fee_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,20 @@ pub struct FeeModelConfigV2 {
pub max_pubdata_per_batch: u64,
}

impl FeeModelConfigV2 {
/// The maximum acceptable L2 gas price. Currently, this is required by the bootloader.
cytadela8 marked this conversation as resolved.
Show resolved Hide resolved
/// TODO remove when no longer required by bootloader
cytadela8 marked this conversation as resolved.
Show resolved Hide resolved
pub fn maximum_l2_gas_price(&self) -> u64 {
10_000_000_000_000 // 10k gwei
perekopskiy marked this conversation as resolved.
Show resolved Hide resolved
}

/// The maximum acceptable pubdata. Currently, this is required by the bootloader.
/// TODO remove when no longer required by bootloader
cytadela8 marked this conversation as resolved.
Show resolved Hide resolved
pub fn maximum_pubdata_price(&self) -> u64 {
1_000_000_000_000_000 // 1M gwei
}
}

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
106 changes: 92 additions & 14 deletions core/node/fee_model/src/lib.rs
Original file line number Diff line number Diff line change
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 @@ -202,11 +202,22 @@ fn compute_batch_fee_model_input_v2(
(l1_batch_overhead_per_gas.as_u64() as f64 * compute_overhead_part) as u64;

// We sum up the minimal L2 gas price (i.e. the raw prover/compute cost of a single L2 gas) and the overhead for batch being closed.
minimal_l2_gas_price + gas_overhead_wei
let calculated_price = minimal_l2_gas_price + gas_overhead_wei;
cytadela8 marked this conversation as resolved.
Show resolved Hide resolved

if calculated_price < config.maximum_l2_gas_price() {
calculated_price
} else {
tracing::warn!(
"Fair l2 gas price {} exceeds maximum. Limiting to {}",
calculated_price,
config.maximum_l2_gas_price()
);
config.maximum_l2_gas_price()
}
};

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 @@ -217,7 +228,18 @@ fn compute_batch_fee_model_input_v2(
(l1_batch_overhead_per_pubdata.as_u64() as f64 * pubdata_overhead_part) as u64;

// We sum up the raw L1 pubdata price (i.e. the expected price of publishing a single pubdata byte) and the overhead for batch being closed.
l1_pubdata_price + pubdata_overhead_wei
let calculated_price = l1_pubdata_price + pubdata_overhead_wei;

if calculated_price < config.maximum_pubdata_price() {
calculated_price
} else {
tracing::warn!(
"Fair pubdata price {} exceeds maximum. Limitting to {}",
calculated_price,
config.maximum_pubdata_price()
);
config.maximum_pubdata_price()
}
};

PubdataIndependentBatchFeeModelInput {
Expand Down Expand Up @@ -259,9 +281,11 @@ 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 = 1_000 * GWEI;
const GIANT_L1_PUB_DATA_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 All @@ -283,16 +307,16 @@ mod tests {
let params = FeeParamsV2::new(
config,
GIANT_L1_GAS_PRICE,
GIANT_L1_GAS_PRICE,
GIANT_L1_PUB_DATA_PRICE,
BaseTokenConversionRatio::default(),
);

// We'll use scale factor of 3.0
let input = compute_batch_fee_model_input_v2(params, 3.0, 3.0);

assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE * 3);
assert_eq!(input.fair_l2_gas_price, 130_000_000_000_000);
assert_eq!(input.fair_pubdata_price, 15_300_000_000_000_000);
assert_eq!(input.fair_l2_gas_price, 1_300_000_000_000);
assert_eq!(input.fair_pubdata_price, 450_000_000_000_000);
}

#[test]
Expand Down Expand Up @@ -336,7 +360,7 @@ mod tests {
let params = FeeParamsV2::new(
config,
GIANT_L1_GAS_PRICE,
GIANT_L1_GAS_PRICE,
GIANT_L1_PUB_DATA_PRICE,
BaseTokenConversionRatio::default(),
);

Expand All @@ -345,14 +369,14 @@ mod tests {
// The fair L2 gas price is identical to the minimal one.
assert_eq!(input.fair_l2_gas_price, 100_000_000_000);
// The fair pubdata price is the minimal one plus the overhead.
assert_eq!(input.fair_pubdata_price, 800_000_000_000_000);
assert_eq!(input.fair_pubdata_price, 107_000_000_000_000);
}

#[test]
fn test_compute_baxtch_fee_model_input_v2_only_compute_overhead() {
// Here we use sensible config, but when only compute is used to close the batch
let config = FeeModelConfigV2 {
minimal_l2_gas_price: 100_000_000_000,
minimal_l2_gas_price: 1_000_000_000,
compute_overhead_part: 1.0,
pubdata_overhead_part: 0.0,
batch_overhead_l1_gas: 700_000,
Expand All @@ -370,7 +394,7 @@ mod tests {
let input = 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, plus the overhead
assert_eq!(input.fair_l2_gas_price, 240_000_000_000);
assert_eq!(input.fair_l2_gas_price, 2_400_000_000);
// The fair pubdata price is equal to the original one.
assert_eq!(input.fair_pubdata_price, GIANT_L1_GAS_PRICE);
}
Expand Down Expand Up @@ -491,6 +515,60 @@ 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_PUB_DATA_PRICE,
BaseTokenConversionRatio::default(),
);

let input = 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, config.maximum_l2_gas_price());
}

#[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 = 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, config.maximum_l2_gas_price());
}

#[tokio::test]
async fn test_get_fee_model_params() {
struct TestCase {
Expand Down Expand Up @@ -544,7 +622,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/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 |
| | `<=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
5 changes: 2 additions & 3 deletions docs/guides/external-node/09_decentralization.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ On the gossipnet, the data integrity will be protected by the BFT (byzantine fau
> current implementation it may take a couple of hours and gets faster the more nodes you add to the
> `gossip_static_outbound` list (see below). We are working to remove this inconvenience.


> [!NOTE]
>
> The minimal supported server version for this is [24.11.0](https://github.com/matter-labs/zksync-era/releases/tag/core-v24.11.0)

> The minimal supported server version for this is
perekopskiy marked this conversation as resolved.
Show resolved Hide resolved
> [24.11.0](https://github.com/matter-labs/zksync-era/releases/tag/core-v24.11.0)

### Generating secrets

Expand Down
Loading