From 1f8c9c63e96f7d7b37d613403056e71b13ca152f Mon Sep 17 00:00:00 2001 From: Rachit Sonthalia <54906134+rachit77@users.noreply.github.com> Date: Wed, 4 Oct 2023 20:18:17 +0530 Subject: [PATCH] Base Fee Configs (#1890) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added genesis base fee flag * cr fix * typo * cr fix * edited flag comment * made baseFeeEM as optional parameter * fix linting error * cr fix * fix typo * cr fix * refactored baseFeeChangeDenom code * linting fix * cr fix * cr fix * Add BaseFeeChangeDenom to JSON marshalling logic --------- Co-authored-by: Stefan Negovanović --- blockchain/blockchain.go | 2 +- blockchain/blockchain_test.go | 4 +- chain/chain.go | 63 ++++++++++++++++++------------- chain/params.go | 3 -- command/default.go | 14 +++++-- command/genesis/genesis.go | 18 +++++---- command/genesis/params.go | 57 +++++++++++++++++++++------- command/genesis/polybft_params.go | 6 +-- command/genesis/utils.go | 50 ++++++++++++++++++++++++ 9 files changed, 158 insertions(+), 59 deletions(-) diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 13acc0de75..cc79b3e3ce 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -1393,7 +1393,7 @@ func (b *Blockchain) CalculateBaseFee(parent *types.Header) uint64 { func (b *Blockchain) calcBaseFeeDelta(gasUsedDelta, parentGasTarget, baseFee uint64) uint64 { y := baseFee * gasUsedDelta / parentGasTarget - return y / b.config.Params.BaseFeeChangeDenom + return y / b.config.Genesis.BaseFeeChangeDenom } func (b *Blockchain) writeBatchAndUpdate( diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go index 33b624d9cb..2bc36943ef 100644 --- a/blockchain/blockchain_test.go +++ b/blockchain/blockchain_test.go @@ -1396,10 +1396,10 @@ func TestBlockchain_CalculateBaseFee(t *testing.T) { Forks: &chain.Forks{ chain.London: chain.NewFork(5), }, - BaseFeeChangeDenom: chain.BaseFeeChangeDenom, }, Genesis: &chain.Genesis{ - BaseFeeEM: test.elasticityMultiplier, + BaseFeeEM: test.elasticityMultiplier, + BaseFeeChangeDenom: chain.BaseFeeChangeDenom, }, }, } diff --git a/chain/chain.go b/chain/chain.go index 7d00d2c34f..ea461a5a45 100644 --- a/chain/chain.go +++ b/chain/chain.go @@ -55,6 +55,9 @@ type Genesis struct { BaseFee uint64 `json:"baseFee"` BaseFeeEM uint64 `json:"baseFeeEM"` + // BaseFeeChangeDenom is the value to bound the amount the base fee can change between blocks + BaseFeeChangeDenom uint64 `json:"baseFeeChangeDenom,omitempty"` + // Override StateRoot types.Hash @@ -113,19 +116,20 @@ func (g *Genesis) Hash() types.Hash { // MarshalJSON implements the json interface func (g *Genesis) MarshalJSON() ([]byte, error) { type Genesis struct { - Nonce string `json:"nonce"` - Timestamp *string `json:"timestamp,omitempty"` - ExtraData *string `json:"extraData,omitempty"` - GasLimit *string `json:"gasLimit,omitempty"` - Difficulty *string `json:"difficulty,omitempty"` - Mixhash types.Hash `json:"mixHash"` - Coinbase types.Address `json:"coinbase"` - Alloc *map[string]*GenesisAccount `json:"alloc,omitempty"` - Number *string `json:"number,omitempty"` - GasUsed *string `json:"gasUsed,omitempty"` - ParentHash types.Hash `json:"parentHash"` - BaseFee *string `json:"baseFee"` - BaseFeeEM *string `json:"baseFeeEM"` + Nonce string `json:"nonce"` + Timestamp *string `json:"timestamp,omitempty"` + ExtraData *string `json:"extraData,omitempty"` + GasLimit *string `json:"gasLimit,omitempty"` + Difficulty *string `json:"difficulty,omitempty"` + Mixhash types.Hash `json:"mixHash"` + Coinbase types.Address `json:"coinbase"` + Alloc *map[string]*GenesisAccount `json:"alloc,omitempty"` + Number *string `json:"number,omitempty"` + GasUsed *string `json:"gasUsed,omitempty"` + ParentHash types.Hash `json:"parentHash"` + BaseFee *string `json:"baseFee"` + BaseFeeEM *string `json:"baseFeeEM"` + BaseFeeChangeDenom *string `json:"baseFeeChangeDenom"` } var enc Genesis @@ -138,6 +142,7 @@ func (g *Genesis) MarshalJSON() ([]byte, error) { enc.Difficulty = common.EncodeUint64(g.Difficulty) enc.BaseFee = common.EncodeUint64(g.BaseFee) enc.BaseFeeEM = common.EncodeUint64(g.BaseFeeEM) + enc.BaseFeeChangeDenom = common.EncodeUint64(g.BaseFeeChangeDenom) enc.Mixhash = g.Mixhash enc.Coinbase = g.Coinbase @@ -161,19 +166,20 @@ func (g *Genesis) MarshalJSON() ([]byte, error) { // UnmarshalJSON implements the json interface func (g *Genesis) UnmarshalJSON(data []byte) error { type Genesis struct { - Nonce *string `json:"nonce"` - Timestamp *string `json:"timestamp"` - ExtraData *string `json:"extraData"` - GasLimit *string `json:"gasLimit"` - Difficulty *string `json:"difficulty"` - Mixhash *types.Hash `json:"mixHash"` - Coinbase *types.Address `json:"coinbase"` - Alloc map[string]*GenesisAccount `json:"alloc"` - Number *string `json:"number"` - GasUsed *string `json:"gasUsed"` - ParentHash *types.Hash `json:"parentHash"` - BaseFee *string `json:"baseFee"` - BaseFeeEM *string `json:"baseFeeEM"` + Nonce *string `json:"nonce"` + Timestamp *string `json:"timestamp"` + ExtraData *string `json:"extraData"` + GasLimit *string `json:"gasLimit"` + Difficulty *string `json:"difficulty"` + Mixhash *types.Hash `json:"mixHash"` + Coinbase *types.Address `json:"coinbase"` + Alloc map[string]*GenesisAccount `json:"alloc"` + Number *string `json:"number"` + GasUsed *string `json:"gasUsed"` + ParentHash *types.Hash `json:"parentHash"` + BaseFee *string `json:"baseFee"` + BaseFeeEM *string `json:"baseFeeEM"` + BaseFeeChangeDenom *string `json:"baseFeeChangeDenom"` } var dec Genesis @@ -230,6 +236,11 @@ func (g *Genesis) UnmarshalJSON(data []byte) error { parseError("baseFeeEM", subErr) } + g.BaseFeeChangeDenom, subErr = common.ParseUint64orHex(dec.BaseFeeChangeDenom) + if subErr != nil { + parseError("baseFeeChangeDenom", subErr) + } + if dec.Mixhash != nil { g.Mixhash = *dec.Mixhash } diff --git a/chain/params.go b/chain/params.go index 199dc5d9d5..eb6ec07c47 100644 --- a/chain/params.go +++ b/chain/params.go @@ -32,9 +32,6 @@ type Params struct { BurnContract map[uint64]types.Address `json:"burnContract"` // Destination address to initialize default burn contract with BurnContractDestinationAddress types.Address `json:"burnContractDestinationAddress,omitempty"` - - // BaseFeeChangeDenom is the value to bound the amount the base fee can change between blocks - BaseFeeChangeDenom uint64 `json:"baseFeeChangeDenom,omitempty"` } type AddressListConfig struct { diff --git a/command/default.go b/command/default.go index 01ce1feac6..2b69cc721f 100644 --- a/command/default.go +++ b/command/default.go @@ -1,6 +1,8 @@ package command import ( + "fmt" + "github.com/umbracle/ethgo" "github.com/0xPolygon/polygon-edge/chain" @@ -19,9 +21,15 @@ const ( ) var ( - DefaultStake = ethgo.Ether(1e6) - DefaultPremineBalance = ethgo.Ether(1e6) - DefaultGenesisBaseFee = chain.GenesisBaseFee + DefaultStake = ethgo.Ether(1e6) + DefaultPremineBalance = ethgo.Ether(1e6) + DefaultGenesisBaseFee = chain.GenesisBaseFee + DefaultGenesisBaseFeeConfig = fmt.Sprintf( + "%d:%d:%d", + DefaultGenesisBaseFee, + DefaultGenesisBaseFeeEM, + DefaultGenesisBaseFeeChangeDenom, + ) ) const ( diff --git a/command/genesis/genesis.go b/command/genesis/genesis.go index c71f1fb93f..fad6c7c9d6 100644 --- a/command/genesis/genesis.go +++ b/command/genesis/genesis.go @@ -77,6 +77,17 @@ func setFlags(cmd *cobra.Command) { "the burn contract block and address (format: :
[:])", ) + cmd.Flags().StringVar( + ¶ms.baseFeeConfig, + genesisBaseFeeConfigFlag, + command.DefaultGenesisBaseFeeConfig, + `initial base fee(in wei), base fee elasticity multiplier, and base fee change denominator + (provided in the following format: [][:][:]). + BaseFeeChangeDenom represents the value to bound the amount the base fee can change between blocks. + Default BaseFee is 1 Gwei, BaseFeeEM is 2 and BaseFeeChangeDenom is 8. + Note: BaseFee, BaseFeeEM, and BaseFeeChangeDenom should be greater than 0.`, + ) + cmd.Flags().StringArrayVar( ¶ms.bootnodes, command.BootnodeFlag, @@ -249,13 +260,6 @@ func setFlags(cmd *cobra.Command) { defaultBlockTrackerPollInterval, "interval (number of seconds) at which block tracker polls for latest block at rootchain", ) - - cmd.Flags().Uint64Var( - ¶ms.baseFeeChangeDenom, - baseFeeChangeDenomFlag, - command.DefaultGenesisBaseFeeChangeDenom, - "represents the value to bound the amount the base fee can change between blocks.", - ) } // Access Control Lists diff --git a/command/genesis/params.go b/command/genesis/params.go index 1d3731224d..1e202827fa 100644 --- a/command/genesis/params.go +++ b/command/genesis/params.go @@ -34,6 +34,7 @@ const ( epochRewardFlag = "epoch-reward" blockGasLimitFlag = "block-gas-limit" burnContractFlag = "burn-contract" + genesisBaseFeeConfigFlag = "base-fee-config" posFlag = "pos" minValidatorCount = "min-validator-count" maxValidatorCount = "max-validator-count" @@ -42,7 +43,6 @@ const ( rewardWalletFlag = "reward-wallet" blockTrackerPollIntervalFlag = "block-tracker-poll-interval" proxyContractsAdminFlag = "proxy-contracts-admin" - baseFeeChangeDenomFlag = "base-fee-change-denom" defaultNativeTokenName = "Polygon" defaultNativeTokenSymbol = "MATIC" @@ -69,6 +69,8 @@ var ( errReserveAccMustBePremined = errors.New("it is mandatory to premine reserve account (0x0 address)") errBlockTrackerPollInterval = errors.New("block tracker poll interval must be greater than 0") errBaseFeeChangeDenomZero = errors.New("base fee change denominator must be greater than 0") + errBaseFeeEMZero = errors.New("base fee elasticity multiplier must be greater than 0") + errBaseFeeZero = errors.New("base fee must be greater than 0") ) type genesisParams struct { @@ -88,7 +90,9 @@ type genesisParams struct { blockGasLimit uint64 isPos bool - burnContract string + burnContract string + baseFeeConfig string + parsedBaseFeeConfig *baseFeeInfo minNumValidators uint64 maxNumValidators uint64 @@ -140,8 +144,6 @@ type genesisParams struct { blockTrackerPollInterval time.Duration proxyContractsAdmin string - - baseFeeChangeDenom uint64 } func (p *genesisParams) validateFlags() error { @@ -150,6 +152,10 @@ func (p *genesisParams) validateFlags() error { return errUnsupportedConsensus } + if err := p.validateGenesisBaseFeeConfig(); err != nil { + return err + } + // Check if validator information is set at all if p.isIBFTConsensus() && !p.areValidatorsSetManually() && @@ -161,10 +167,6 @@ func (p *genesisParams) validateFlags() error { return err } - if p.baseFeeChangeDenom == 0 { - return errBaseFeeChangeDenomZero - } - if p.isPolyBFTConsensus() { if err := p.extractNativeTokenMetadata(); err != nil { return err @@ -417,18 +419,18 @@ func (p *genesisParams) initGenesisConfig() error { GasUsed: command.DefaultGenesisGasUsed, }, Params: &chain.Params{ - ChainID: int64(p.chainID), - Forks: enabledForks, - Engine: p.consensusEngineConfig, - BaseFeeChangeDenom: p.baseFeeChangeDenom, + ChainID: int64(p.chainID), + Forks: enabledForks, + Engine: p.consensusEngineConfig, }, Bootnodes: p.bootnodes, } // burn contract can be set only for non mintable native token if p.isBurnContractEnabled() { - chainConfig.Genesis.BaseFee = command.DefaultGenesisBaseFee - chainConfig.Genesis.BaseFeeEM = command.DefaultGenesisBaseFeeEM + chainConfig.Genesis.BaseFee = p.parsedBaseFeeConfig.baseFee + chainConfig.Genesis.BaseFeeEM = p.parsedBaseFeeConfig.baseFeeEM + chainConfig.Genesis.BaseFeeChangeDenom = p.parsedBaseFeeConfig.baseFeeChangeDenom chainConfig.Params.BurnContract = make(map[uint64]types.Address, 1) burnContractInfo, err := parseBurnContractInfo(p.burnContract) @@ -566,6 +568,33 @@ func (p *genesisParams) validateBurnContract() error { return nil } +func (p *genesisParams) validateGenesisBaseFeeConfig() error { + if p.baseFeeConfig == "" { + return errors.New("invalid input(empty string) for genesis base fee config flag") + } + + baseFeeInfo, err := parseBaseFeeConfig(p.baseFeeConfig) + if err != nil { + return fmt.Errorf("failed to parse base fee config: %w, provided value %s", err, p.baseFeeConfig) + } + + p.parsedBaseFeeConfig = baseFeeInfo + + if baseFeeInfo.baseFee == 0 { + return errBaseFeeZero + } + + if baseFeeInfo.baseFeeEM == 0 { + return errBaseFeeEMZero + } + + if baseFeeInfo.baseFeeChangeDenom == 0 { + return errBaseFeeChangeDenomZero + } + + return nil +} + func (p *genesisParams) validateProxyContractsAdmin() error { if strings.TrimSpace(p.proxyContractsAdmin) == "" { return errors.New("proxy contracts admin address must be set") diff --git a/command/genesis/polybft_params.go b/command/genesis/polybft_params.go index 2976ffbbe1..bacd4ed63c 100644 --- a/command/genesis/polybft_params.go +++ b/command/genesis/polybft_params.go @@ -175,7 +175,6 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er Engine: map[string]interface{}{ string(server.PolyBFTConsensus): polyBftConfig, }, - BaseFeeChangeDenom: p.baseFeeChangeDenom, }, Bootnodes: p.bootnodes, } @@ -308,8 +307,9 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er if p.isBurnContractEnabled() { // only populate base fee and base fee multiplier values if burn contract(s) // is provided - chainConfig.Genesis.BaseFee = command.DefaultGenesisBaseFee - chainConfig.Genesis.BaseFeeEM = command.DefaultGenesisBaseFeeEM + chainConfig.Genesis.BaseFee = p.parsedBaseFeeConfig.baseFee + chainConfig.Genesis.BaseFeeEM = p.parsedBaseFeeConfig.baseFeeEM + chainConfig.Genesis.BaseFeeChangeDenom = p.parsedBaseFeeConfig.baseFeeChangeDenom } return helper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath) diff --git a/command/genesis/utils.go b/command/genesis/utils.go index e41cf7da90..561178615d 100644 --- a/command/genesis/utils.go +++ b/command/genesis/utils.go @@ -2,6 +2,7 @@ package genesis import ( "encoding/hex" + "errors" "fmt" "io/ioutil" "math/big" @@ -163,6 +164,55 @@ func parseBurnContractInfo(burnContractInfoRaw string) (*polybft.BurnContractInf }, nil } +type baseFeeInfo struct { + baseFee uint64 + baseFeeEM uint64 + baseFeeChangeDenom uint64 +} + +// parseBaseFeeConfig parses provided base fee configuration and returns baseFeeInfo +func parseBaseFeeConfig(baseFeeConfigRaw string) (*baseFeeInfo, error) { + baseFeeInfo := &baseFeeInfo{ + command.DefaultGenesisBaseFee, + command.DefaultGenesisBaseFeeEM, + command.DefaultGenesisBaseFeeChangeDenom, + } + + baseFeeConfig := strings.Split(baseFeeConfigRaw, ":") + if len(baseFeeConfig) > 3 { + return baseFeeInfo, errors.New("invalid number of arguments for base fee configuration") + } + + if len(baseFeeConfig) >= 1 && baseFeeConfig[0] != "" { + baseFee, err := common.ParseUint64orHex(&baseFeeConfig[0]) + if err != nil { + return baseFeeInfo, err + } + + baseFeeInfo.baseFee = baseFee + } + + if len(baseFeeConfig) >= 2 && baseFeeConfig[1] != "" { + baseFeeEM, err := common.ParseUint64orHex(&baseFeeConfig[1]) + if err != nil { + return baseFeeInfo, err + } + + baseFeeInfo.baseFeeEM = baseFeeEM + } + + if len(baseFeeConfig) == 3 && baseFeeConfig[2] != "" { + baseFeeChangeDenom, err := common.ParseUint64orHex(&baseFeeConfig[2]) + if err != nil { + return baseFeeInfo, err + } + + baseFeeInfo.baseFeeChangeDenom = baseFeeChangeDenom + } + + return baseFeeInfo, nil +} + // GetValidatorKeyFiles returns file names which has validator secrets func GetValidatorKeyFiles(rootDir, filePrefix string) ([]string, error) { if rootDir == "" {