-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
99 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# L2 Execution Engine | ||
|
||
## Fees | ||
|
||
### L1-Cost fees (L1 Fee Vault) | ||
|
||
#### Fjord L1-Cost fee changes (FastLZ estimator) | ||
|
||
Fjord updates the L1 cost calculation function to use a FastLZ-based compression estimator. | ||
The L1 cost is computed as: | ||
|
||
``` | ||
l1FeeScaled = l1BaseFeeScalar*l1BaseFee*16 + l1BlobFeeScalar*l1BlobBaseFee | ||
l1CostSigned = (intercept + fastlzCoef*fastlzSize + uncompressedTxCoef*uncompressedTxSize) * l1FeeScaled / 1e12 | ||
l1Cost = uint256(max(0, l1CostSigned)) | ||
``` | ||
|
||
Where: | ||
|
||
- the final `l1Cost` computation is an unlimited precision unsigned integer computation, with the result in Wei and | ||
having `uint256` range. | ||
|
||
- the `l1CostSigned` calculation is an unlimited precision signed integer computation, with the result in Wei and | ||
having `int256` range. | ||
|
||
- `l1BaseFee` is the L1 base fee of the latest L1 origin registered in the L2 chain. | ||
|
||
- `l1BlobBaseFee` is the blob gas price, computed as described in [EIP-4844][4844-gas] from the | ||
header of the latest registered L1 origin block. | ||
|
||
- `l1BaseFeeScalar` is the L1 base fee scalar, scaled by `1e6` (see below for suggested values). | ||
|
||
- `l1BlobFeeScalar` is the L1 blob fee scalar, scaled by `1e6` (see below for suggested values). | ||
|
||
- `fastlzSize` is the length of the FastLZ-compressed RLP-encoded signed tx. | ||
|
||
- `uncompressedTxSize` is the length of uncompressed RLP-encoded signed tx. | ||
|
||
- `intercept`, `fastlzCoef`, and `uncompressedTxCoef` are constants calculated by linear regression (see next section), | ||
scaled by `1e6`. These values can be negative. | ||
|
||
##### L1-Cost linear regression details | ||
|
||
The `intercept`, `fastlzCoef`, and `uncompressedTxCoef` constants are calculated by linear regression using a dataset | ||
of previous L2 transactions. The dataset is generated by iterating over all transactions in a given time range, and | ||
performing the following actions. For each transaction: | ||
1. Calculate the RLP-encoded transaction payload. Record the length of this payload as `uncompressedTxSize`. | ||
2. Compress the payload using FastLZ. Record the length of the compressed payload as `fastlzSize`. | ||
3. Compress the payload using a "best estimate" compression, defined as: | ||
- Create two zlib streams, both using the maximum compression level. | ||
- Bootstrap one of the streams with at least 64kb of transaction data (after compression). | ||
- Write each transaction to both streams (flushing after each write), and record the size increase | ||
of the larger buffer as `bestEstimateSize`. | ||
- Each time the larger buffer grows larger than 128kb, empty the stream and swap the buffers. | ||
|
||
Once this dataset is generated, a linear regression can be calculated using the `bestEstimateSize` as | ||
the dependent variable and `fastlzSize` and `uncompressedTxSize` as the independent variables. | ||
|
||
The following Python code can be used to calculate the linear regression: | ||
|
||
```python | ||
import numpy as np | ||
from sklearn.linear_model import LinearRegression | ||
|
||
# Dataset format is: | ||
# data = [record...] (one or more records, concatenated) | ||
# record = bestEstimateSize ++ fastlzSize ++ uncompressedTxSize | ||
# bestEstimateSize = little-endian uint32 | ||
# fastlzSize = little-endian uint32 | ||
# uncompressedTxSize = little-endian uint32 | ||
|
||
dt = np.dtype([('best', '<u4'), ('fastlz', '<u4'), ('length', '<u4')]) | ||
data = np.fromfile('./data.bin', dtype=dt) | ||
input_array = np.array(data.tolist()) | ||
|
||
x = np.delete(input_array, [0], 1) | ||
y = input_array[:, 0] | ||
model = LinearRegression().fit(x, y) | ||
print(f'model: {model.intercept_} {model.coef_}') | ||
``` | ||
|
||
As an example, we generated a dataset from all transactions on Optimism Mainnet in October 2023, | ||
and the resulting linear regression was: | ||
|
||
`-27.321890037208703 + 1.03146206*fastlzSize - 0.08866427*uncompressedTxSize` | ||
|
||
Scaling these values by `1e6` gives the constants used in the L1-Cost fee estimator: | ||
- `l1BaseFeeScalar = 11_111` (`~= 7600/0.684`) | ||
- `l1BlobFeeScalar = 1_250_000` (`~= 862000/0.684`) | ||
- `intercept = -27_321_890` | ||
- `fastlzCoef = 1_031_462` | ||
- `uncompressedTxCoef = -88_664` | ||
|
||
Note that the linear regression takes into account the current compression ratio, so the | ||
scalars `l1BaseFeeScalar` and `l1BlobFeeScalar` should be adjusted to account for any previous | ||
compression ratio they encoded. For example, if the previous compression ratio was `0.684`, then | ||
they should be divided by `0.684` to get the new scalars. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters