mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
feat(core): decode basefee params from block.extraData (#290)
* feat(core): decode basefee params from `block.extraData` * feat: add `CalcBaseFeeOntake`
This commit is contained in:
parent
8ff161fb39
commit
83564ba6fc
11 changed files with 99 additions and 38 deletions
|
|
@ -15,13 +15,12 @@ var _ = (*blockMetadataMarshaling)(nil)
|
|||
// MarshalJSON marshals as JSON.
|
||||
func (b BlockMetadata) MarshalJSON() ([]byte, error) {
|
||||
type BlockMetadata struct {
|
||||
Beneficiary common.Address `json:"beneficiary" gencodec:"required"`
|
||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
||||
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||
MixHash common.Hash `json:"mixHash" gencodec:"required"`
|
||||
TxList hexutil.Bytes `json:"txList" gencodec:"required"`
|
||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||
BasefeeSharingPctg uint8 `json:"basefeeSharingPctg"`
|
||||
Beneficiary common.Address `json:"beneficiary" gencodec:"required"`
|
||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
||||
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||
MixHash common.Hash `json:"mixHash" gencodec:"required"`
|
||||
TxList hexutil.Bytes `json:"txList" gencodec:"required"`
|
||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||
}
|
||||
var enc BlockMetadata
|
||||
enc.Beneficiary = b.Beneficiary
|
||||
|
|
@ -30,20 +29,18 @@ func (b BlockMetadata) MarshalJSON() ([]byte, error) {
|
|||
enc.MixHash = b.MixHash
|
||||
enc.TxList = b.TxList
|
||||
enc.ExtraData = b.ExtraData
|
||||
enc.BasefeeSharingPctg = b.BasefeeSharingPctg
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (b *BlockMetadata) UnmarshalJSON(input []byte) error {
|
||||
type BlockMetadata struct {
|
||||
Beneficiary *common.Address `json:"beneficiary" gencodec:"required"`
|
||||
GasLimit *uint64 `json:"gasLimit" gencodec:"required"`
|
||||
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||
MixHash *common.Hash `json:"mixHash" gencodec:"required"`
|
||||
TxList *hexutil.Bytes `json:"txList" gencodec:"required"`
|
||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||
BasefeeSharingPctg *uint8 `json:"basefeeSharingPctg"`
|
||||
Beneficiary *common.Address `json:"beneficiary" gencodec:"required"`
|
||||
GasLimit *uint64 `json:"gasLimit" gencodec:"required"`
|
||||
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||
MixHash *common.Hash `json:"mixHash" gencodec:"required"`
|
||||
TxList *hexutil.Bytes `json:"txList" gencodec:"required"`
|
||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||
}
|
||||
var dec BlockMetadata
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
@ -73,8 +70,5 @@ func (b *BlockMetadata) UnmarshalJSON(input []byte) error {
|
|||
return errors.New("missing required field 'extraData' for BlockMetadata")
|
||||
}
|
||||
b.ExtraData = dec.ExtraData
|
||||
if dec.BasefeeSharingPctg != nil {
|
||||
b.BasefeeSharingPctg = *dec.BasefeeSharingPctg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,9 +70,8 @@ type BlockMetadata struct {
|
|||
MixHash common.Hash `json:"mixHash" gencodec:"required"`
|
||||
|
||||
// Extra fields required in taiko-geth.
|
||||
TxList []byte `json:"txList" gencodec:"required"`
|
||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||
BasefeeSharingPctg uint8 `json:"basefeeSharingPctg"`
|
||||
TxList []byte `json:"txList" gencodec:"required"`
|
||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||
}
|
||||
|
||||
// CHANGE(taiko): JSON type overrides for BlockMetadata.
|
||||
|
|
|
|||
|
|
@ -93,3 +93,38 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
|||
return math.BigMax(baseFee, common.Big0)
|
||||
}
|
||||
}
|
||||
|
||||
// CHANGE(taiko): CalcBaseFeeOntake calculates the basefee of the an ontake block header.
|
||||
func CalcBaseFeeOntake(config *params.ChainConfig, parent *types.Header, parentGasTarget uint64) *big.Int {
|
||||
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
|
||||
if parent.GasUsed == parentGasTarget {
|
||||
return new(big.Int).Set(parent.BaseFee)
|
||||
}
|
||||
|
||||
var (
|
||||
num = new(big.Int)
|
||||
denom = new(big.Int)
|
||||
)
|
||||
|
||||
if parent.GasUsed > parentGasTarget {
|
||||
// If the parent block used more gas than its target, the baseFee should increase.
|
||||
// max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
|
||||
num.SetUint64(parent.GasUsed - parentGasTarget)
|
||||
num.Mul(num, parent.BaseFee)
|
||||
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
||||
baseFeeDelta := math.BigMax(num, common.Big1)
|
||||
|
||||
return num.Add(parent.BaseFee, baseFeeDelta)
|
||||
} else {
|
||||
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
|
||||
// max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
|
||||
num.SetUint64(parentGasTarget - parent.GasUsed)
|
||||
num.Mul(num, parent.BaseFee)
|
||||
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
||||
baseFee := num.Sub(parent.BaseFee, num)
|
||||
|
||||
return math.BigMax(baseFee, common.Big0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,10 +138,6 @@ type StateDB struct {
|
|||
|
||||
// Testing hooks
|
||||
onCommit func(states *triestate.Set) // Hook invoked when commit is performed
|
||||
|
||||
// CHANGE(taiko): basefeeSharingPctg of the basefee will be sent to the block.coinbase,
|
||||
// the remaining will be sent to the treasury address.
|
||||
BasefeeSharingPctg uint8
|
||||
}
|
||||
|
||||
// New creates a new state from a given trie.
|
||||
|
|
|
|||
|
|
@ -169,8 +169,12 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// CHANGE(taiko): set `BasefeeSharingPctg` for the current message.
|
||||
msg.BasefeeSharingPctg = statedb.BasefeeSharingPctg
|
||||
// CHANGE(taiko): decode the basefeeSharingPctg config from the extradata, and
|
||||
// add it to the Message, if its an ontake block.
|
||||
if config.IsOntake(header.Number) {
|
||||
basefeeSharingPctg, _ := DecodeOntakeExtraData(header.Extra)
|
||||
msg.BasefeeSharingPctg = basefeeSharingPctg
|
||||
}
|
||||
// Create a new context to be used in the EVM environment
|
||||
blockContext := NewEVMBlockContext(header, bc, author)
|
||||
txContext := NewEVMTxContext(msg)
|
||||
|
|
|
|||
|
|
@ -537,3 +537,22 @@ func (st *StateTransition) getTreasuryAddress() common.Address {
|
|||
suffix,
|
||||
)
|
||||
}
|
||||
|
||||
// DecodeOntakeExtraData decodes an ontake block's extradata,
|
||||
// returns basefeeSharingPctg and blockGasTargetMillion configurations.
|
||||
func DecodeOntakeExtraData(extradata []byte) (uint8, uint8) {
|
||||
// Convert []byte to *big.Int
|
||||
extra := new(big.Int).SetBytes(extradata)
|
||||
|
||||
// Define the masks.
|
||||
blockGasTargetMillionMask := big.NewInt(0xFF) // 8 bits mask for _blockGasTargetMillion
|
||||
basefeeSharingPctgMask := big.NewInt(0xFF) // 8 bits mask for _basefeeSharingPctg
|
||||
|
||||
// Extract _blockGasTargetMillion.
|
||||
blockGasTargetMillion := new(big.Int).And(extra, blockGasTargetMillionMask).Uint64()
|
||||
|
||||
// Shift right by 8 bits to get the _basefeeSharingPctg part.
|
||||
basefeeSharingPctg := new(big.Int).Rsh(extra, 8).And(basefeeSharingPctgMask, basefeeSharingPctgMask).Uint64()
|
||||
|
||||
return uint8(basefeeSharingPctg), uint8(blockGasTargetMillion)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var (
|
||||
InternalDevnetOntakeBlock = new(big.Int).SetUint64(374_400)
|
||||
HeklaOntakeBlock = new(big.Int).SetUint64(720_000)
|
||||
MainnetOntakeBlock = new(big.Int).SetUint64(374_400)
|
||||
)
|
||||
|
||||
// TaikoGenesisBlock returns the Taiko network genesis block configs.
|
||||
func TaikoGenesisBlock(networkID uint64) *Genesis {
|
||||
chainConfig := params.TaikoChainConfig
|
||||
|
|
@ -17,9 +23,11 @@ func TaikoGenesisBlock(networkID uint64) *Genesis {
|
|||
switch networkID {
|
||||
case params.TaikoMainnetNetworkID.Uint64():
|
||||
chainConfig.ChainID = params.TaikoMainnetNetworkID
|
||||
chainConfig.OntakeBlock = MainnetOntakeBlock
|
||||
allocJSON = taikoGenesis.MainnetGenesisAllocJSON
|
||||
case params.TaikoInternalL2ANetworkID.Uint64():
|
||||
chainConfig.ChainID = params.TaikoInternalL2ANetworkID
|
||||
chainConfig.OntakeBlock = InternalDevnetOntakeBlock
|
||||
allocJSON = taikoGenesis.InternalL2AGenesisAllocJSON
|
||||
case params.TaikoInternalL2BNetworkID.Uint64():
|
||||
chainConfig.ChainID = params.TaikoInternalL2BNetworkID
|
||||
|
|
@ -44,9 +52,11 @@ func TaikoGenesisBlock(networkID uint64) *Genesis {
|
|||
allocJSON = taikoGenesis.KatlaGenesisAllocJSON
|
||||
case params.HeklaNetworkID.Uint64():
|
||||
chainConfig.ChainID = params.HeklaNetworkID
|
||||
chainConfig.OntakeBlock = HeklaOntakeBlock
|
||||
allocJSON = taikoGenesis.HeklaGenesisAllocJSON
|
||||
default:
|
||||
chainConfig.ChainID = params.TaikoInternalL2ANetworkID
|
||||
chainConfig.OntakeBlock = InternalDevnetOntakeBlock
|
||||
allocJSON = taikoGenesis.InternalL2AGenesisAllocJSON
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -382,11 +382,6 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
|||
if payloadAttributes != nil {
|
||||
// CHANGE(taiko): create a L2 block by Taiko protocol.
|
||||
if isTaiko {
|
||||
if payloadAttributes.BlockMetadata.BasefeeSharingPctg > 100 {
|
||||
return valid(nil), engine.InvalidPayloadAttributes.With(
|
||||
fmt.Errorf("invalid basefeeSharingPctg %d", payloadAttributes.BlockMetadata.BasefeeSharingPctg),
|
||||
)
|
||||
}
|
||||
// No need to check payloadAttribute here, because all its fields are
|
||||
// marked as required.
|
||||
block, err := api.eth.Miner().SealBlockWith(
|
||||
|
|
|
|||
|
|
@ -144,8 +144,7 @@ func (w *worker) sealBlockWith(
|
|||
}
|
||||
|
||||
if len(txs) == 0 {
|
||||
// A L2 block needs to have have at least one `V1TaikoL2.anchor` or
|
||||
// `V1TaikoL2.invalidateBlock` transaction.
|
||||
// A L2 block needs to have have at least one `TaikoL2.anchor` / `TaikoL2.anchorV2`.
|
||||
return nil, fmt.Errorf("too less transactions in the block")
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +169,6 @@ func (w *worker) sealBlockWith(
|
|||
defer env.discard()
|
||||
|
||||
env.header.GasLimit = blkMeta.GasLimit
|
||||
env.state.BasefeeSharingPctg = blkMeta.BasefeeSharingPctg
|
||||
|
||||
// Commit transactions.
|
||||
gasLimit := env.header.GasLimit
|
||||
|
|
|
|||
|
|
@ -987,8 +987,13 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
|||
}
|
||||
// Set baseFee and GasLimit if we are on an EIP-1559 chain
|
||||
if w.chainConfig.IsLondon(header.Number) {
|
||||
if w.chainConfig.Taiko && genParams.baseFeePerGas != nil {
|
||||
header.BaseFee = genParams.baseFeePerGas
|
||||
if w.chainConfig.Taiko {
|
||||
if !w.chainConfig.IsOntake(header.Number) {
|
||||
header.BaseFee = genParams.baseFeePerGas
|
||||
} else {
|
||||
_, blockGasTargetMillion := core.DecodeOntakeExtraData(header.Extra)
|
||||
header.BaseFee = eip1559.CalcBaseFeeOntake(w.chainConfig, parent, uint64(blockGasTargetMillion)*1_000_000)
|
||||
}
|
||||
} else {
|
||||
header.BaseFee = eip1559.CalcBaseFee(w.chainConfig, parent)
|
||||
if !w.chainConfig.IsLondon(parent.Number) {
|
||||
|
|
|
|||
|
|
@ -378,7 +378,8 @@ type ChainConfig struct {
|
|||
Clique *CliqueConfig `json:"clique,omitempty"`
|
||||
|
||||
// CHANGE(taiko): Taiko network flag.
|
||||
Taiko bool `json:"taiko"`
|
||||
Taiko bool `json:"taiko"`
|
||||
OntakeBlock *big.Int `json:"ontakeBlock,omitempty"` // Ontake switch block (nil = no fork, 0 = already activated)
|
||||
}
|
||||
|
||||
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
|
||||
|
|
@ -595,6 +596,11 @@ func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool {
|
|||
return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)
|
||||
}
|
||||
|
||||
// CHANGE(taiko): IsOntake returns whether num is either equal to the Ontake fork block or greater.
|
||||
func (c *ChainConfig) IsOntake(num *big.Int) bool {
|
||||
return isBlockForked(c.OntakeBlock, num)
|
||||
}
|
||||
|
||||
// CheckCompatible checks whether scheduled fork transitions have been imported
|
||||
// with a mismatching chain configuration.
|
||||
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError {
|
||||
|
|
|
|||
Loading…
Reference in a new issue