Skip to content
Open

cgt #23

Show file tree
Hide file tree
Changes from all 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: 11 additions & 3 deletions core/types/rollup_cost.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,14 @@ func NewL1CostFunc(config *params.ChainConfig, statedb StateGetter) L1CostFunc {
l1BaseFeeScalar, l1BlobBaseFeeScalar := ExtractEcotoneFeeParams(l1FeeScalars)

if config.IsOptimismFjord(blockTime) {
l1BaseFeeScalarMultiplier, l1BlobBaseFeeScalarMultiplier := config.Optimism.L1ScalarMultipliers(blockTime)
return NewL1CostFuncFjord(
l1BaseFee,
l1BlobBaseFee,
l1BaseFeeScalar,
l1BlobBaseFeeScalar,
l1BaseFeeScalarMultiplier,
l1BlobBaseFeeScalarMultiplier,
)
} else {
return newL1CostFuncEcotone(l1BaseFee, l1BlobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar)
Expand Down Expand Up @@ -378,6 +381,8 @@ func intToScaledFloat(scalar *big.Int) *big.Float {

// extractL1GasParams extracts the gas parameters necessary to compute gas costs from L1 block info
func extractL1GasParams(config *params.ChainConfig, time uint64, data []byte) (gasParams, error) {
l1BaseFeeScalarMultiplier, l1BlobBaseFeeScalarMultiplier := config.Optimism.L1ScalarMultipliers(time)

if config.IsIsthmus(time) && len(data) >= 4 && !bytes.Equal(data[0:4], EcotoneL1AttributesSelector) {
// edge case: for the very first Isthmus block we still need to use the Ecotone
// function. We detect this edge case by seeing if the function selector is the old one
Expand All @@ -386,11 +391,13 @@ func extractL1GasParams(config *params.ChainConfig, time uint64, data []byte) (g
if err != nil {
return gasParams{}, err
}

p.costFunc = NewL1CostFuncFjord(
p.l1BaseFee,
p.l1BlobBaseFee,
big.NewInt(int64(*p.l1BaseFeeScalar)),
big.NewInt(int64(*p.l1BlobBaseFeeScalar)),
l1BaseFeeScalarMultiplier, l1BlobBaseFeeScalarMultiplier,
)
return p, nil
} else if config.IsEcotone(time) && len(data) >= 4 && !bytes.Equal(data[0:4], BedrockL1AttributesSelector) {
Expand All @@ -409,6 +416,7 @@ func extractL1GasParams(config *params.ChainConfig, time uint64, data []byte) (g
p.l1BlobBaseFee,
big.NewInt(int64(*p.l1BaseFeeScalar)),
big.NewInt(int64(*p.l1BlobBaseFeeScalar)),
l1BaseFeeScalarMultiplier, l1BlobBaseFeeScalarMultiplier,
)
} else {
p.costFunc = newL1CostFuncEcotone(
Expand Down Expand Up @@ -524,16 +532,16 @@ func l1CostHelper(gasWithOverhead, l1BaseFee, scalar *big.Int) *big.Int {
}

// NewL1CostFuncFjord returns an l1 cost function suitable for the Fjord upgrade
func NewL1CostFuncFjord(l1BaseFee, l1BlobBaseFee, baseFeeScalar, blobFeeScalar *big.Int) l1CostFunc {
func NewL1CostFuncFjord(l1BaseFee, l1BlobBaseFee, baseFeeScalar, blobFeeScalar, l1BaseFeeScalarMultiplier, l1BlobBaseFeeScalarMultiplier *big.Int) l1CostFunc {
return func(costData RollupCostData) (fee, calldataGasUsed *big.Int) {
// Fjord L1 cost function:
// l1FeeScaled = baseFeeScalar*l1BaseFee*16 + blobFeeScalar*l1BlobBaseFee
// estimatedSize = max(minTransactionSize, intercept + fastlzCoef*fastlzSize)
// l1Cost = estimatedSize * l1FeeScaled / 1e12

scaledL1BaseFee := new(big.Int).Mul(baseFeeScalar, l1BaseFee)
scaledL1BaseFee := new(big.Int).Mul(new(big.Int).Mul(baseFeeScalar, l1BaseFeeScalarMultiplier), l1BaseFee)
calldataCostPerByte := new(big.Int).Mul(scaledL1BaseFee, sixteen)
blobCostPerByte := new(big.Int).Mul(blobFeeScalar, l1BlobBaseFee)
blobCostPerByte := new(big.Int).Mul(new(big.Int).Mul(blobFeeScalar, l1BlobBaseFeeScalarMultiplier), l1BlobBaseFee)
l1FeeScaled := new(big.Int).Add(calldataCostPerByte, blobCostPerByte)
estimatedSize := costData.estimatedDASizeScaled()
l1CostScaled := new(big.Int).Mul(estimatedSize, l1FeeScaled)
Expand Down
32 changes: 32 additions & 0 deletions core/types/rollup_cost_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"math/big"
"testing"

math2 "math"

"github.com/holiman/uint256"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -69,6 +71,8 @@ func TestFjordL1CostFuncMinimumBounds(t *testing.T) {
blobBaseFee,
baseFeeScalar,
blobBaseFeeScalar,
big.NewInt(1),
big.NewInt(1),
)

// Minimum size transactions:
Expand Down Expand Up @@ -106,6 +110,8 @@ func TestFjordL1CostSolidityParity(t *testing.T) {
big.NewInt(3*1e6),
big.NewInt(20),
big.NewInt(15),
big.NewInt(1),
big.NewInt(1),
)

c0, g0 := costFunc(RollupCostData{
Expand Down Expand Up @@ -355,6 +361,32 @@ func (sg *testStateGetter) GetState(addr common.Address, slot common.Hash) commo
return buf
}

// This test checks that the L1 scalar multipliers are used in NewL1CostFunc
// for latest HF, but still need to manually check the usage in extractL1GasParams.
// it's best-effort only.
func TestL1ScalarMultipliersAreUsedInLatestHF(t *testing.T) {

// Note: may still need to manually turn on the latest HF flag if OP hasn't do that yet
config := params.OptimismTestConfig
statedb := &testStateGetter{
baseFee: baseFee,
overhead: overhead,
scalar: scalar,
blobBaseFee: blobBaseFee,
baseFeeScalar: uint32(baseFeeScalar.Uint64()),
blobBaseFeeScalar: uint32(blobBaseFeeScalar.Uint64()),
}

params.L1ScalarMultipliersCalled = false
params.L1ScalarMultipliersTestFlag = true
costFunc := NewL1CostFunc(config, statedb)
require.NotNil(t, costFunc)

costFunc(emptyTx.RollupCostData(), math2.MaxUint64-1 /*math2.MaxUint64 is used as a special mark in NewL1CostFunc, so minus 1*/)

require.Equal(t, params.L1ScalarMultipliersCalled, true)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not pass these two parameters directly into conf.Optimism = &OptimismConfig{EIP1559Elasticity: 50, EIP1559Denominator: 10, EIP1559DenominatorCanyon: uint64ptr(250)}, and check whether the return values of costFunc for both params are greater than 0?
That way, we wouldn’t need to stub the L1ScalarMultipliersCalled flag in the code.

}

// TestNewL1CostFunc tests that the appropriate cost function is selected based on the
// configuration and statedb values.
func TestNewL1CostFunc(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion eth/ethconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ var Defaults = Config{
RPCGasCap: 50000000,
RPCEVMTimeout: 5 * time.Second,
GPO: FullNodeGPO,
RPCTxFeeCap: 1, // 1 ether
RPCTxFeeCap: 1000, // 1000 QKC
}

//go:generate go run github.com/fjl/gencodec -type Config -formats toml -out gen_config.go
Expand Down
2 changes: 1 addition & 1 deletion eth/gasprice/gasprice.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var (
DefaultMaxPrice = big.NewInt(500 * params.GWei)
DefaultIgnorePrice = big.NewInt(2 * params.Wei)

DefaultMinSuggestedPriorityFee = big.NewInt(1e6 * params.Wei) // 0.001 gwei, for Optimism fee suggestion
DefaultMinSuggestedPriorityFee = big.NewInt(1e9 * params.Wei) // 1 gwei, for Optimism fee suggestion
)

type Config struct {
Expand Down
33 changes: 33 additions & 0 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,13 +511,46 @@ type OptimismConfig struct {
EIP1559Elasticity uint64 `json:"eip1559Elasticity"`
EIP1559Denominator uint64 `json:"eip1559Denominator"`
EIP1559DenominatorCanyon *uint64 `json:"eip1559DenominatorCanyon,omitempty"`
// The multiplier of the L1BaseFeeScalar, used to keep the L1BaseFeeScalar size compatible with uint32 and calculate the effective L1BaseFeeScalar;
// Only effective when the value is non-zero

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a . at the end of each comment.

L1BaseFeeScalarMultiplier uint64 `json:"l1BaseFeeScalarMultiplier,omitempty"`
// The multiplier of the L1BlobBaseFeeScalar, used to keep the L1BlobBaseFeeScalar size compatible with uint32 and calculate the effective L1BlobBaseFeeScalar;
// Only effective when the value is non-zero
L1BlobBaseFeeScalarMultiplier uint64 `json:"l1BlobBaseFeeScalarMultiplier,omitempty"`
}

// String implements the stringer interface, returning the optimism fee config details.
func (o *OptimismConfig) String() string {
return "optimism"
}

// this flag is only true in test
var L1ScalarMultipliersTestFlag bool
var L1ScalarMultipliersCalled bool

// L1ScalarMultipliers returns the scalar multipliers to make the L1BaseFeeScalar and L1BlobBaseFeeScalar compatible with uint32.
// It needs to be applied for all future changes to the L1 cost.
func (o *OptimismConfig) L1ScalarMultipliers(blockTime uint64) (*big.Int, *big.Int) {
// blockTime is not used in the current implementation, but it is kept here for future compatibility

// this code block is only used for test
if L1ScalarMultipliersTestFlag && !L1ScalarMultipliersCalled {
L1ScalarMultipliersCalled = true
}

// default values for the scalar multipliers
l1BaseFeeScalarMultiplier := int64(1)
l1BlobBaseFeeScalarMultiplier := int64(1)

if o.L1BaseFeeScalarMultiplier != 0 {
l1BaseFeeScalarMultiplier = int64(o.L1BaseFeeScalarMultiplier)
}
if o.L1BlobBaseFeeScalarMultiplier != 0 {
l1BlobBaseFeeScalarMultiplier = int64(o.L1BlobBaseFeeScalarMultiplier)
}
return big.NewInt(l1BaseFeeScalarMultiplier), big.NewInt(l1BlobBaseFeeScalarMultiplier)
}

// Description returns a human-readable description of ChainConfig.
func (c *ChainConfig) Description() string {
var banner string
Expand Down