Skip to content

Commit

Permalink
use linear regression for l1 gas used
Browse files Browse the repository at this point in the history
  • Loading branch information
danyalprout committed Apr 30, 2024
1 parent a95d5f3 commit 6413a3e
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 57 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ require (
rsc.io/tmplfunc v0.0.3 // indirect
)

replace github.com/ethereum/go-ethereum v1.13.11 => github.com/base-org/op-geth v0.0.0-20240430004555-57f391c1492c
replace github.com/ethereum/go-ethereum v1.13.11 => github.com/base-org/op-geth v0.0.0-20240430172712-f66b9be65c17

//replace github.com/ethereum/go-ethereum v1.13.9 => ../op-geth

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/base-org/op-geth v0.0.0-20240430004555-57f391c1492c h1:U0aDbLq0uyOjZ7+QEiXDYO5qy4FzxkxvTeIbp8v8Zww=
github.com/base-org/op-geth v0.0.0-20240430004555-57f391c1492c/go.mod h1:K23yb9efVf9DdUOv/vl/Ux57Tng00rLaFqWYlFF45CA=
github.com/base-org/op-geth v0.0.0-20240430172712-f66b9be65c17 h1:l1OZ6XdUvvQcWF2IRniE5aqhsahJLLlRCMPheb+tM+Y=
github.com/base-org/op-geth v0.0.0-20240430172712-f66b9be65c17/go.mod h1:K23yb9efVf9DdUOv/vl/Ux57Tng00rLaFqWYlFF45CA=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
Expand Down
1 change: 0 additions & 1 deletion op-e2e/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,4 @@ clean:
.PHONY: clean

fuzz:
go test -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzFastLZ ./
go test -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzFjordCostFunction ./
15 changes: 6 additions & 9 deletions op-e2e/actions/fjord_fork_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@ import (
)

var (
fjordGasPriceOracleCodeHash = common.HexToHash("0x17563a1e2f4faeee2c47abda44d74d8c91438c26f2f1ba774ef4e3c41cc45f3b")
fjordGasPriceOracleCodeHash = common.HexToHash("0x58e192326ee67ed52b7add91e4640024cbd1b21528a0ff1e1d21b7ca54e3ee62")
// https://basescan.org/tx/0x8debb2fe54200183fb8baa3c6dbd8e6ec2e4f7a4add87416cd60336b8326d16a
txHex = "02f875822105819b8405709fb884057d460082e97f94273ca93a52b817294830ed7572aa591ccfa647fd80881249c58b0021fb3fc080a05bb08ccfd68f83392e446dac64d88a2d28e7072c06502dfabc4a77e77b5c7913a05878d53dd4ebba4f6367e572d524dffcabeec3abb1d8725ee3ac5dc32e1852e3"

costFastlzCoef int64 = 836_500
costIntercept int64 = -42_585_600
)

func TestFjordNetworkUpgradeTransactions(gt *testing.T) {
Expand Down Expand Up @@ -112,9 +109,9 @@ func TestFjordNetworkUpgradeTransactions(gt *testing.T) {

l1GasUsed, err := gasPriceOracle.GetL1GasUsed(&bind.CallOpts{}, txData)
require.NoError(t, err)
require.Equal(gt, uint64(1_888), l1GasUsed.Uint64())

fastLzSize := types.FlzCompressLen(txData)
require.Equal(gt, l1GasUsed.Uint64(), uint64(fastLzSize+68)*16)

// Check that GetL1Fee takes into account fast LZ
used, err := gasPriceOracle.GetL1Fee(&bind.CallOpts{}, txData)
Expand All @@ -137,13 +134,13 @@ func TestFjordNetworkUpgradeTransactions(gt *testing.T) {
// l1BaseFeeScaled = l1BaseFeeScalar * l1BaseFee * 16
// l1BlobFeeScaled = l1BlobFeeScalar * l1BlobBaseFee
// l1FeeScaled = l1BaseFeeScaled + l1BlobFeeScaled
// ((intercept + fastlzCoef*max(fastlzLength, 71)) * l1FeeScaled) / 1e6
// ((intercept + fastlzCoef*max(fastlzLength, 100)) * l1FeeScaled) / 1e6
func fjordL1Cost(
t require.TestingT,
gasPriceOracle *bindings.GasPriceOracleCaller,
fastLzLength int64,
) *big.Int {
fastLzLength = max(fastLzLength, 71)
fastLzLength = max(fastLzLength, types.MinTransactionSize.Int64())

baseFeeScalar, err := gasPriceOracle.BaseFeeScalar(nil)
require.NoError(t, err)
Expand All @@ -158,8 +155,8 @@ func fjordL1Cost(
feeScaled = new(big.Int).Mul(feeScaled, l1BaseFee)
feeScaled = new(big.Int).Add(feeScaled, new(big.Int).Mul(new(big.Int).SetUint64(uint64(blobBaseFeeScalar)), blobBaseFee))

cost := new(big.Int).Mul(new(big.Int).SetInt64(costFastlzCoef), new(big.Int).SetInt64(fastLzLength+68))
cost = new(big.Int).Add(cost, new(big.Int).SetInt64(costIntercept))
cost := new(big.Int).Mul(types.L1CostFastlzCoef, new(big.Int).SetInt64(fastLzLength+68))
cost = new(big.Int).Add(cost, types.L1CostIntercept)
require.True(t, cost.Sign() >= 0)

cost = new(big.Int).Mul(cost, feeScaled)
Expand Down
45 changes: 9 additions & 36 deletions op-e2e/fastlz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ import (

"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient/simulated"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -48,31 +45,6 @@ func (sg *testStateGetter) GetState(addr common.Address, slot common.Hash) commo
return buf
}

func FuzzFastLZ(f *testing.F) {
l2Allocs := config.L2Allocs(genesis.L2AllocsFjord)
backend := simulated.NewBackend(l2Allocs.Accounts)
defer backend.Close()

gpoCaller, err := bindings.NewGasPriceOracleCaller(predeploys.GasPriceOracleAddr, backend.Client())
require.NoError(f, err)

isFjord, err := gpoCaller.IsFjord(&bind.CallOpts{})
require.NoError(f, err)
require.True(f, isFjord)

f.Fuzz(func(t *testing.T, fuzzedData []byte) {
gpoValue, err := gpoCaller.GetL1GasUsed(&bind.CallOpts{}, fuzzedData)
require.NoError(t, err)

gpoWithoutPadding := gpoValue.Div(gpoValue, big.NewInt(16))
gpoWithoutPadding.Sub(gpoWithoutPadding, big.NewInt(68))

gethValue := types.FlzCompressLen(fuzzedData)

require.Equal(t, uint64(gethValue), gpoWithoutPadding.Uint64())
})
}

func FuzzFjordCostFunction(f *testing.F) {
cfg := DefaultSystemConfig(f)
s := hexutil.Uint64(0)
Expand Down Expand Up @@ -154,23 +126,24 @@ func FuzzFjordCostFunction(f *testing.F) {
return
}

gpoValue, err := gpoCaller.GetL1Fee(&bind.CallOpts{}, fuzzedData)
l1FeeSolidity, err := gpoCaller.GetL1Fee(&bind.CallOpts{}, fuzzedData)
require.NoError(t, err)

// remove the adjustment
gpoValue.Mul(gpoValue, big.NewInt(1e12))
gpoValue.Div(gpoValue, feeScaled)
l1FeeSolidity.Mul(l1FeeSolidity, big.NewInt(1e12))
l1FeeSolidity.Div(l1FeeSolidity, feeScaled)

totat := new(big.Int).Mul(big.NewInt(68), big.NewInt(836_500))
gpoValue.Sub(gpoValue, totat)
l1FeeSolidity.Sub(l1FeeSolidity, totat)

gpoValue.Mul(gpoValue, feeScaled)
gpoValue.Div(gpoValue, big.NewInt(1e12))
l1FeeSolidity.Mul(l1FeeSolidity, feeScaled)
l1FeeSolidity.Div(l1FeeSolidity, big.NewInt(1e12))

costData := types.NewRollupCostData(fuzzedData)

gethValue := costFunc(costData, zeroTime)
l1FeeGeth := costFunc(costData, zeroTime)

require.Equal(t, gethValue.Uint64(), gpoValue.Uint64(), fmt.Sprintf("fuzzedData: %x", common.Bytes2Hex(fuzzedData)))
require.Equal(t, l1FeeGeth.Uint64(), l1FeeSolidity.Uint64(), fmt.Sprintf("fuzzedData: %x", common.Bytes2Hex(fuzzedData)))
})

}
2 changes: 1 addition & 1 deletion op-node/rollup/derive/fjord_upgrade_transactions.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@
"sourceCodeHash": "0x864d244dd0b01cb01e5f50425bedce46e72005bdb8bead198ac885481547f41d"
},
"src/L2/GasPriceOracle.sol": {
"initCodeHash": "0x5234d40f5e9dcc0904650dc732ef35275682ec5272dd9e844539a70d982836df",
"sourceCodeHash": "0xf434f19901d60931dc9262aa838c1d4ced50ff34bd263be50b318aa1b834c5e2"
"initCodeHash": "0x235382db0c03d93628b6609dc9aed5cf60b7f6945d88d13d59049e30b16423d0",
"sourceCodeHash": "0x5794b836406ff3b340b2208c8555077861732c9eab048e05ffed7416d20ac992"
},
"src/L2/L1Block.sol": {
"initCodeHash": "0xda6828a2a6e02d9fde7d5d9947f51b207f31abf5dbb538dd968cd491164e2115",
Expand Down
16 changes: 13 additions & 3 deletions packages/contracts-bedrock/src/L2/GasPriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ contract GasPriceOracle is ISemver {
if (isFjord) {
// Add 68 to the size to account for unsigned tx
// Assume the compressed data is mostly non-zero, and would pay 16 gas per calldata byte
return (LibZip.flzCompress(_data).length + 68) * 16;
// Divide by 1e6 due to the scaling factor of the linear regression
return _fjordLinearRegression(LibZip.flzCompress(_data).length + 68) * 16 / 1e6;
}
uint256 l1GasUsed = _getCalldataGas(_data);
if (isEcotone) {
Expand Down Expand Up @@ -206,14 +207,23 @@ contract GasPriceOracle is ISemver {
}

/// @notice Fjord L1 cost based on the compressed and original tx size.
/// @param _fastLzSize fastlz compressed tx size.
/// @param _fastLzSize estimated compressed tx size.
/// @return Fjord L1 fee that should be paid for the tx
function _fjordL1Cost(uint256 _fastLzSize) internal view returns (uint256) {
// Apply the linear regression to estimate the Brotli 10 size
uint256 estimatedSize = _fjordLinearRegression(_fastLzSize);
uint256 feeScaled = baseFeeScalar() * 16 * l1BaseFee() + blobBaseFeeScalar() * blobBaseFee();
return estimatedSize * feeScaled / (10 ** (DECIMALS * 2));
}

/// @notice Takes the fastLz size compression and returns the estimated Brotli
/// @param _fastLzSize fastlz compressed tx size.
/// @return Number of bytes in the compressed transaction
function _fjordLinearRegression(uint256 _fastLzSize) internal pure returns (uint256) {
int256 estimatedSize = COST_INTERCEPT + int256(COST_FASTLZ_COEF * _fastLzSize);
if (estimatedSize < int256(MIN_TRANSACTION_SIZE) * 1e6) {
estimatedSize = int256(MIN_TRANSACTION_SIZE) * 1e6;
}
return uint256(estimatedSize) * feeScaled / (10 ** (DECIMALS * 2));
return uint256(estimatedSize);
}
}
4 changes: 2 additions & 2 deletions packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ contract GasPriceOracleFjordActive_Test is GasPriceOracle_Test {
function test_getL1FeeMinimumBound_succeeds() external view {
bytes memory data = hex"0000010203"; // fastlzSize: 74, inc signature
uint256 gas = gasPriceOracle.getL1GasUsed(data);
assertEq(gas, 1184); // 74 * 16
assertEq(gas, 1600); // 100 * 16
uint256 price = gasPriceOracle.getL1Fee(data);
// linearRegression = -42.5856 + 74 * 0.8365 = 19.3154
// under the minTxSize of 71, so output is ignored
Expand All @@ -307,7 +307,7 @@ contract GasPriceOracleFjordActive_Test is GasPriceOracle_Test {
hex"dba6d6d796e4f80be94f8a9151d685607826e7ba25177b40cb127ea9f1438470";

uint256 gas = gasPriceOracle.getL1GasUsed(data);
assertEq(gas, 3760); // 235 * 16
assertEq(gas, 2463); // 235 * 16
uint256 price = gasPriceOracle.getL1Fee(data);
// linearRegression = -42.5856 + 235 * 0.8365 = 153.9919
// 153_991_900 * (20 * 16 * 2 * 1e6 + 3 * 1e6 * 15) / 1e12
Expand Down

0 comments on commit 6413a3e

Please sign in to comment.