diff --git a/beacon/engine/gen_blockmetadata.go b/beacon/engine/gen_blockmetadata.go index 94df6bb786e8..a981fe403356 100644 --- a/beacon/engine/gen_blockmetadata.go +++ b/beacon/engine/gen_blockmetadata.go @@ -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 } diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 2931e066c476..aff6230d8b9b 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -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. diff --git a/consensus/misc/eip1559/eip1559.go b/consensus/misc/eip1559/eip1559.go index 84b82c4c492e..79ad57403662 100644 --- a/consensus/misc/eip1559/eip1559.go +++ b/consensus/misc/eip1559/eip1559.go @@ -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) + } +} diff --git a/core/state/statedb.go b/core/state/statedb.go index 0e2743944116..ebd2143882ac 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -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. diff --git a/core/state_processor.go b/core/state_processor.go index 40a9f53819cc..5fcbdd4b8d0d 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -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) diff --git a/core/state_transition.go b/core/state_transition.go index bce9bfbfa637..44f8061b456e 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -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) +} diff --git a/core/taiko_genesis.go b/core/taiko_genesis.go index 80a06c72db7a..26aee3c0fbac 100644 --- a/core/taiko_genesis.go +++ b/core/taiko_genesis.go @@ -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 } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 0f44a8489ca8..c37cee4e02eb 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -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( diff --git a/miner/taiko_worker.go b/miner/taiko_worker.go index b050d7b77eb8..12bfea0efe1e 100644 --- a/miner/taiko_worker.go +++ b/miner/taiko_worker.go @@ -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 diff --git a/miner/worker.go b/miner/worker.go index 5952c8ee2e98..e1616d30244f 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -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) { diff --git a/params/config.go b/params/config.go index 491878d4f798..d2dbff45a931 100644 --- a/params/config.go +++ b/params/config.go @@ -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 {