mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
feat: update base fee via cli (#1183)
* feat: update base fee via cli * fix * improve comments
This commit is contained in:
parent
3edb331d88
commit
0b6f8f1889
9 changed files with 157 additions and 14 deletions
|
|
@ -185,6 +185,8 @@ var (
|
||||||
utils.DARecoverySignBlocksFlag,
|
utils.DARecoverySignBlocksFlag,
|
||||||
utils.DARecoveryL2EndBlockFlag,
|
utils.DARecoveryL2EndBlockFlag,
|
||||||
utils.DARecoveryProduceBlocksFlag,
|
utils.DARecoveryProduceBlocksFlag,
|
||||||
|
utils.L2BaseFeeScalarFlag,
|
||||||
|
utils.L2BaseFeeOverheadFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcFlags = []cli.Flag{
|
rpcFlags = []cli.Flag{
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{
|
||||||
utils.RPCGlobalEVMTimeoutFlag,
|
utils.RPCGlobalEVMTimeoutFlag,
|
||||||
utils.RPCGlobalTxFeeCapFlag,
|
utils.RPCGlobalTxFeeCapFlag,
|
||||||
utils.AllowUnprotectedTxs,
|
utils.AllowUnprotectedTxs,
|
||||||
|
utils.MaxBlockRangeFlag,
|
||||||
utils.JSpathFlag,
|
utils.JSpathFlag,
|
||||||
utils.ExecFlag,
|
utils.ExecFlag,
|
||||||
utils.PreloadJSFlag,
|
utils.PreloadJSFlag,
|
||||||
|
|
@ -227,6 +228,30 @@ var AppHelpFlagGroups = []flags.FlagGroup{
|
||||||
Name: "METRICS AND STATS",
|
Name: "METRICS AND STATS",
|
||||||
Flags: metricsFlags,
|
Flags: metricsFlags,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "ROLLUP",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.L1EndpointFlag,
|
||||||
|
utils.L1ConfirmationsFlag,
|
||||||
|
utils.L1DeploymentBlockFlag,
|
||||||
|
utils.L1DisableMessageQueueV2Flag,
|
||||||
|
utils.RollupVerifyEnabledFlag,
|
||||||
|
utils.L2BaseFeeScalarFlag,
|
||||||
|
utils.L2BaseFeeOverheadFlag,
|
||||||
|
utils.DASyncEnabledFlag,
|
||||||
|
utils.DABlobScanAPIEndpointFlag,
|
||||||
|
utils.DABlockNativeAPIEndpointFlag,
|
||||||
|
utils.DABeaconNodeAPIEndpointFlag,
|
||||||
|
utils.DARecoveryModeFlag,
|
||||||
|
utils.DARecoveryInitialL1BlockFlag,
|
||||||
|
utils.DARecoveryInitialBatchFlag,
|
||||||
|
utils.DARecoverySignBlocksFlag,
|
||||||
|
utils.DARecoveryL2EndBlockFlag,
|
||||||
|
utils.DARecoveryProduceBlocksFlag,
|
||||||
|
utils.CircuitCapacityCheckEnabledFlag,
|
||||||
|
utils.CircuitCapacityCheckWorkersFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "ALIASED (deprecated)",
|
Name: "ALIASED (deprecated)",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/consensus"
|
"github.com/scroll-tech/go-ethereum/consensus"
|
||||||
"github.com/scroll-tech/go-ethereum/consensus/clique"
|
"github.com/scroll-tech/go-ethereum/consensus/clique"
|
||||||
"github.com/scroll-tech/go-ethereum/consensus/ethash"
|
"github.com/scroll-tech/go-ethereum/consensus/ethash"
|
||||||
|
"github.com/scroll-tech/go-ethereum/consensus/misc"
|
||||||
"github.com/scroll-tech/go-ethereum/core"
|
"github.com/scroll-tech/go-ethereum/core"
|
||||||
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
||||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
|
|
@ -934,6 +935,18 @@ var (
|
||||||
Name: "da.recovery.produceblocks",
|
Name: "da.recovery.produceblocks",
|
||||||
Usage: "Produce unsigned blocks after L1 recovery for permissionless batch submission",
|
Usage: "Produce unsigned blocks after L1 recovery for permissionless batch submission",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// L2 base fee settings
|
||||||
|
L2BaseFeeScalarFlag = BigFlag{
|
||||||
|
Name: "basefee.scalar",
|
||||||
|
Usage: "Scalar used in the l2 base fee formula. Signer nodes will use this for computing the next block's base fee. Follower nodes will use this in RPC.",
|
||||||
|
Value: misc.DefaultBaseFeeScalar,
|
||||||
|
}
|
||||||
|
L2BaseFeeOverheadFlag = BigFlag{
|
||||||
|
Name: "basefee.overhead",
|
||||||
|
Usage: "Overhead used in the l2 base fee formula. Signer nodes will use this for computing the next block's base fee. Follower nodes will use this in RPC.",
|
||||||
|
Value: misc.DefaultBaseFeeOverhead,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeDataDir retrieves the currently requested data directory, terminating
|
// MakeDataDir retrieves the currently requested data directory, terminating
|
||||||
|
|
@ -1709,6 +1722,29 @@ func setDA(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setBaseFee(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
|
cfg.BaseFeeScalar = misc.DefaultBaseFeeScalar
|
||||||
|
if ctx.GlobalIsSet(L2BaseFeeScalarFlag.Name) {
|
||||||
|
cfg.BaseFeeScalar = GlobalBig(ctx, L2BaseFeeScalarFlag.Name)
|
||||||
|
}
|
||||||
|
cfg.BaseFeeOverhead = misc.DefaultBaseFeeOverhead
|
||||||
|
if ctx.GlobalIsSet(L2BaseFeeOverheadFlag.Name) {
|
||||||
|
cfg.BaseFeeOverhead = GlobalBig(ctx, L2BaseFeeOverheadFlag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("L2 base fee coefficients", "scalar", cfg.BaseFeeScalar, "overhead", cfg.BaseFeeOverhead)
|
||||||
|
|
||||||
|
var minBaseFee uint64
|
||||||
|
if fee := misc.MinBaseFee(cfg.BaseFeeScalar, cfg.BaseFeeOverhead); fee.IsUint64() {
|
||||||
|
minBaseFee = fee.Uint64()
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.TxPool.PriceLimit < minBaseFee {
|
||||||
|
log.Warn("Updating txpool price limit to min L2 base fee", "provided", cfg.TxPool.PriceLimit, "updated", minBaseFee)
|
||||||
|
cfg.TxPool.PriceLimit = minBaseFee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setMaxBlockRange(ctx *cli.Context, cfg *ethconfig.Config) {
|
func setMaxBlockRange(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
if ctx.GlobalIsSet(MaxBlockRangeFlag.Name) {
|
if ctx.GlobalIsSet(MaxBlockRangeFlag.Name) {
|
||||||
cfg.MaxBlockRange = ctx.GlobalInt64(MaxBlockRangeFlag.Name)
|
cfg.MaxBlockRange = ctx.GlobalInt64(MaxBlockRangeFlag.Name)
|
||||||
|
|
@ -1785,6 +1821,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
setCircuitCapacityCheck(ctx, cfg)
|
setCircuitCapacityCheck(ctx, cfg)
|
||||||
setEnableRollupVerify(ctx, cfg)
|
setEnableRollupVerify(ctx, cfg)
|
||||||
setDA(ctx, cfg)
|
setDA(ctx, cfg)
|
||||||
|
setBaseFee(ctx, cfg)
|
||||||
setMaxBlockRange(ctx, cfg)
|
setMaxBlockRange(ctx, cfg)
|
||||||
if ctx.GlobalIsSet(ShadowforkPeersFlag.Name) {
|
if ctx.GlobalIsSet(ShadowforkPeersFlag.Name) {
|
||||||
cfg.ShadowForkPeerIDs = ctx.GlobalStringSlice(ShadowforkPeersFlag.Name)
|
cfg.ShadowForkPeerIDs = ctx.GlobalStringSlice(ShadowforkPeersFlag.Name)
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,16 @@ import (
|
||||||
// We would only go above this if L1 base fee hits 2931 Gwei.
|
// We would only go above this if L1 base fee hits 2931 Gwei.
|
||||||
const MaximumL2BaseFee = 10000000000
|
const MaximumL2BaseFee = 10000000000
|
||||||
|
|
||||||
|
// L2 base fee formula constants and defaults.
|
||||||
|
// l2BaseFee = (l1BaseFee * scalar) / PRECISION + overhead.
|
||||||
|
// `scalar` accounts for finalization costs. `overhead` accounts for sequencing and proving costs.
|
||||||
|
// we use 1e18 for precision to match the contract implementation.
|
||||||
|
var (
|
||||||
|
BaseFeePrecision = new(big.Int).SetUint64(1e18)
|
||||||
|
DefaultBaseFeeScalar = new(big.Int).SetUint64(34000000000000)
|
||||||
|
DefaultBaseFeeOverhead = new(big.Int).SetUint64(15680000)
|
||||||
|
)
|
||||||
|
|
||||||
// VerifyEip1559Header verifies some header attributes which were changed in EIP-1559,
|
// VerifyEip1559Header verifies some header attributes which were changed in EIP-1559,
|
||||||
// - gas limit check
|
// - gas limit check
|
||||||
// - basefee check
|
// - basefee check
|
||||||
|
|
@ -54,18 +64,29 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header, parentL1BaseF
|
||||||
if config.Clique != nil && config.Clique.ShadowForkHeight != 0 && parent.Number.Uint64() >= config.Clique.ShadowForkHeight {
|
if config.Clique != nil && config.Clique.ShadowForkHeight != 0 && parent.Number.Uint64() >= config.Clique.ShadowForkHeight {
|
||||||
return big.NewInt(10000000) // 0.01 Gwei
|
return big.NewInt(10000000) // 0.01 Gwei
|
||||||
}
|
}
|
||||||
l2SequencerFee := big.NewInt(1000000) // 0.001 Gwei
|
|
||||||
provingFee := big.NewInt(14680000) // 0.01468 Gwei
|
|
||||||
|
|
||||||
// L1_base_fee * 0.000034
|
scalar := config.Scroll.BaseFeeScalar
|
||||||
verificationFee := parentL1BaseFee
|
if scalar == nil {
|
||||||
verificationFee = new(big.Int).Mul(verificationFee, big.NewInt(34))
|
scalar = DefaultBaseFeeScalar
|
||||||
verificationFee = new(big.Int).Div(verificationFee, big.NewInt(1000000))
|
}
|
||||||
|
overhead := config.Scroll.BaseFeeOverhead
|
||||||
|
if overhead == nil {
|
||||||
|
overhead = DefaultBaseFeeOverhead
|
||||||
|
}
|
||||||
|
|
||||||
baseFee := big.NewInt(0)
|
return calcBaseFee(scalar, overhead, parentL1BaseFee)
|
||||||
baseFee.Add(baseFee, l2SequencerFee)
|
}
|
||||||
baseFee.Add(baseFee, provingFee)
|
|
||||||
baseFee.Add(baseFee, verificationFee)
|
// MinBaseFee calculates the minimum L2 base fee based on the configured coefficients.
|
||||||
|
func MinBaseFee(scalar, overhead *big.Int) *big.Int {
|
||||||
|
return calcBaseFee(scalar, overhead, big.NewInt(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcBaseFee(scalar, overhead, parentL1BaseFee *big.Int) *big.Int {
|
||||||
|
baseFee := new(big.Int).Set(parentL1BaseFee)
|
||||||
|
baseFee.Mul(baseFee, scalar)
|
||||||
|
baseFee.Div(baseFee, BaseFeePrecision)
|
||||||
|
baseFee.Add(baseFee, overhead)
|
||||||
|
|
||||||
if baseFee.Cmp(big.NewInt(MaximumL2BaseFee)) > 0 {
|
if baseFee.Cmp(big.NewInt(MaximumL2BaseFee)) > 0 {
|
||||||
baseFee = big.NewInt(MaximumL2BaseFee)
|
baseFee = big.NewInt(MaximumL2BaseFee)
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,27 @@ func TestCalcBaseFee(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
parentL1BaseFee int64
|
parentL1BaseFee int64
|
||||||
expectedL2BaseFee int64
|
expectedL2BaseFee int64
|
||||||
|
}{
|
||||||
|
{0, 1},
|
||||||
|
{1000000000, 1},
|
||||||
|
{2000000000, 1},
|
||||||
|
{100000000000, 2},
|
||||||
|
{111111111111, 2},
|
||||||
|
{2164000000000, 22},
|
||||||
|
{644149677419355, 6442},
|
||||||
|
}
|
||||||
|
for i, test := range tests {
|
||||||
|
config := config()
|
||||||
|
config.Scroll.BaseFeeScalar = big.NewInt(10000000)
|
||||||
|
config.Scroll.BaseFeeOverhead = big.NewInt(1)
|
||||||
|
if have, want := CalcBaseFee(config, nil, big.NewInt(test.parentL1BaseFee)), big.NewInt(test.expectedL2BaseFee); have.Cmp(want) != 0 {
|
||||||
|
t.Errorf("test %d: have %d want %d, ", i, have, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testsWithDefaults := []struct {
|
||||||
|
parentL1BaseFee int64
|
||||||
|
expectedL2BaseFee int64
|
||||||
}{
|
}{
|
||||||
{0, 15680000},
|
{0, 15680000},
|
||||||
{1000000000, 15714000},
|
{1000000000, 15714000},
|
||||||
|
|
@ -120,9 +141,20 @@ func TestCalcBaseFee(t *testing.T) {
|
||||||
{2164000000000, 89256000},
|
{2164000000000, 89256000},
|
||||||
{644149677419355, 10000000000}, // cap at max L2 base fee
|
{644149677419355, 10000000000}, // cap at max L2 base fee
|
||||||
}
|
}
|
||||||
for i, test := range tests {
|
for i, test := range testsWithDefaults {
|
||||||
if have, want := CalcBaseFee(config(), nil, big.NewInt(test.parentL1BaseFee)), big.NewInt(test.expectedL2BaseFee); have.Cmp(want) != 0 {
|
if have, want := CalcBaseFee(config(), nil, big.NewInt(test.parentL1BaseFee)), big.NewInt(test.expectedL2BaseFee); have.Cmp(want) != 0 {
|
||||||
t.Errorf("test %d: have %d want %d, ", i, have, want)
|
t.Errorf("test %d: have %d want %d, ", i, have, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestMinBaseFee assumes all blocks are 1559-blocks
|
||||||
|
func TestMinBaseFee(t *testing.T) {
|
||||||
|
if have, want := MinBaseFee(DefaultBaseFeeScalar, DefaultBaseFeeOverhead), big.NewInt(15680000); have.Cmp(want) != 0 {
|
||||||
|
t.Errorf("have %d want %d, ", have, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if have, want := MinBaseFee(big.NewInt(10000000), big.NewInt(1)), big.NewInt(1); have.Cmp(want) != 0 {
|
||||||
|
t.Errorf("have %d want %d, ", have, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,13 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client l1.Client) (*Ether
|
||||||
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
|
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
|
||||||
return nil, genesisErr
|
return nil, genesisErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hacky workaround:
|
||||||
|
// It's hard to pass these fields to `CalcBaseFee`, etc.
|
||||||
|
// So pass them as part of the genesis config instead.
|
||||||
|
chainConfig.Scroll.BaseFeeScalar = config.BaseFeeScalar
|
||||||
|
chainConfig.Scroll.BaseFeeOverhead = config.BaseFeeOverhead
|
||||||
|
|
||||||
log.Info("Initialised chain configuration", "config", chainConfig)
|
log.Info("Initialised chain configuration", "config", chainConfig)
|
||||||
|
|
||||||
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil {
|
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,10 @@ type Config struct {
|
||||||
|
|
||||||
// DA syncer options
|
// DA syncer options
|
||||||
DA da_syncer.Config
|
DA da_syncer.Config
|
||||||
|
|
||||||
|
// L2 base fee coefficients for the formula: `l2BaseFee = (l1BaseFee * scalar) / PRECISION + overhead`.
|
||||||
|
BaseFeeScalar *big.Int
|
||||||
|
BaseFeeOverhead *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateConsensusEngine creates a consensus engine for the given chain configuration.
|
// CreateConsensusEngine creates a consensus engine for the given chain configuration.
|
||||||
|
|
|
||||||
|
|
@ -704,6 +704,11 @@ type ScrollConfig struct {
|
||||||
|
|
||||||
// Genesis State Root for MPT clients
|
// Genesis State Root for MPT clients
|
||||||
GenesisStateRoot *common.Hash `json:"genesisStateRoot,omitempty"`
|
GenesisStateRoot *common.Hash `json:"genesisStateRoot,omitempty"`
|
||||||
|
|
||||||
|
// L2 base fee coefficients for the formula: `l2BaseFee = (l1BaseFee * scalar) / PRECISION + overhead`.
|
||||||
|
// These fields are populated from configuration flags, and passed to `CalcBaseFee`.
|
||||||
|
BaseFeeScalar *big.Int `json:"-"`
|
||||||
|
BaseFeeOverhead *big.Int `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// L1Config contains the l1 parameters needed to sync l1 contract events (e.g., l1 messages, commit/revert/finalize batches) in the sequencer
|
// L1Config contains the l1 parameters needed to sync l1 contract events (e.g., l1 messages, commit/revert/finalize batches) in the sequencer
|
||||||
|
|
@ -753,8 +758,18 @@ func (s ScrollConfig) String() string {
|
||||||
genesisStateRoot = fmt.Sprintf("%v", *s.GenesisStateRoot)
|
genesisStateRoot = fmt.Sprintf("%v", *s.GenesisStateRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("{useZktrie: %v, maxTxPerBlock: %v, MaxTxPayloadBytesPerBlock: %v, feeVaultAddress: %v, l1Config: %v, genesisStateRoot: %v}",
|
baseFeeScalar := "<nil>"
|
||||||
s.UseZktrie, maxTxPerBlock, maxTxPayloadBytesPerBlock, s.FeeVaultAddress, s.L1Config.String(), genesisStateRoot)
|
if s.BaseFeeScalar != nil {
|
||||||
|
baseFeeScalar = s.BaseFeeScalar.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
baseFeeOverhead := "<nil>"
|
||||||
|
if s.BaseFeeOverhead != nil {
|
||||||
|
baseFeeOverhead = s.BaseFeeOverhead.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("{useZktrie: %v, maxTxPerBlock: %v, MaxTxPayloadBytesPerBlock: %v, feeVaultAddress: %v, l1Config: %v, genesisStateRoot: %v, baseFeeScalar: %v, baseFeeOverhead: %v}",
|
||||||
|
s.UseZktrie, maxTxPerBlock, maxTxPayloadBytesPerBlock, s.FeeVaultAddress, s.L1Config.String(), genesisStateRoot, baseFeeScalar, baseFeeOverhead)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValidTxCount returns whether the given block's transaction count is below the limit.
|
// IsValidTxCount returns whether the given block's transaction count is below the limit.
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
const (
|
const (
|
||||||
VersionMajor = 5 // Major version component of the current release
|
VersionMajor = 5 // Major version component of the current release
|
||||||
VersionMinor = 8 // Minor version component of the current release
|
VersionMinor = 8 // Minor version component of the current release
|
||||||
VersionPatch = 44 // Patch version component of the current release
|
VersionPatch = 45 // Patch version component of the current release
|
||||||
VersionMeta = "mainnet" // Version metadata to append to the version string
|
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue