From 7f40bbd7d8ed1364b5d461977b0e89de2907a9b9 Mon Sep 17 00:00:00 2001 From: Moon Shiesty Date: Tue, 31 Oct 2023 01:23:29 -0500 Subject: [PATCH] gasLimit (#12) --- beacon/engine/gen_blockparams.go | 6 ++++++ beacon/engine/types.go | 3 +++ consensus/misc/eip1559/eip1559.go | 10 ++++++++-- eth/catalyst/api.go | 4 ++++ miner/payload_building.go | 18 ++++++++++++++---- miner/worker.go | 15 ++++++++++++++- params/config.go | 8 ++++++++ 7 files changed, 57 insertions(+), 7 deletions(-) diff --git a/beacon/engine/gen_blockparams.go b/beacon/engine/gen_blockparams.go index 1d5d0735c4..f165fffb22 100644 --- a/beacon/engine/gen_blockparams.go +++ b/beacon/engine/gen_blockparams.go @@ -24,6 +24,7 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) { // Transactions []hexutil.Bytes `json:"transactions,omitempty" gencodec:"optional"` NoTxPool bool `json:"noTxPool,omitempty" gencodec:"optional"` + GasLimit *hexutil.Uint64 `json:"gasLimit,omitempty" gencodec:"optional"` // } var enc PayloadAttributes @@ -40,6 +41,7 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) { } } enc.NoTxPool = p.NoTxPool + enc.GasLimit = (*hexutil.Uint64)(p.GasLimit) // return json.Marshal(&enc) } @@ -55,6 +57,7 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error { // Transactions []hexutil.Bytes `json:"transactions,omitempty" gencodec:"optional"` NoTxPool *bool `json:"noTxPool,omitempty" gencodec:"optional"` + GasLimit *hexutil.Uint64 `json:"gasLimit,omitempty" gencodec:"optional"` // } var dec PayloadAttributes @@ -89,6 +92,9 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error { if dec.NoTxPool != nil { p.NoTxPool = *dec.NoTxPool } + if dec.GasLimit != nil { + p.GasLimit = (*uint64)(dec.GasLimit) + } // return nil } diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 92022785f9..26b2d7060a 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -42,6 +42,8 @@ type PayloadAttributes struct { // NoTxPool is a field for L2s: if true, the no transactions are taken out of the tx-pool, // only transactions from the above Transactions list will be included. NoTxPool bool `json:"noTxPool,omitempty" gencodec:"optional"` + // GasLimit is a field for L2s: if set, this sets the exact gas limit the block produced with. + GasLimit *uint64 `json:"gasLimit,omitempty" gencodec:"optional"` // } @@ -50,6 +52,7 @@ type payloadAttributesMarshaling struct { Timestamp hexutil.Uint64 // Transactions []hexutil.Bytes + GasLimit *hexutil.Uint64 // } diff --git a/consensus/misc/eip1559/eip1559.go b/consensus/misc/eip1559/eip1559.go index 84b82c4c49..07e2c49436 100644 --- a/consensus/misc/eip1559/eip1559.go +++ b/consensus/misc/eip1559/eip1559.go @@ -37,9 +37,15 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade if !config.IsLondon(parent.Number) { parentGasLimit = parent.GasLimit * config.ElasticityMultiplier() } - if err := misc.VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { - return err + + // + if !config.EnableL2GasLimitApi { // gasLimit can adjust instantly on L2s + if err := misc.VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { + return err + } } + // + // Verify the header is not malformed if header.BaseFee == nil { return errors.New("header is missing baseFee") diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 0254032113..e9f3a6668b 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -367,6 +367,9 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl // will replace it arbitrarily many times in between. if payloadAttributes != nil { // + if api.eth.BlockChain().Config().EnableL2GasLimitApi && payloadAttributes.GasLimit == nil { + return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("gasLimit parameter is required")) + } transactions := make(types.Transactions, 0, len(payloadAttributes.Transactions)) for i, otx := range payloadAttributes.Transactions { var tx types.Transaction @@ -387,6 +390,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl // NoTxPool: payloadAttributes.NoTxPool, Transactions: transactions, + GasLimit: payloadAttributes.GasLimit, // } id := args.Id() diff --git a/miner/payload_building.go b/miner/payload_building.go index 16cb5ebb3c..42574b9ef5 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -42,8 +42,9 @@ type BuildPayloadArgs struct { Withdrawals types.Withdrawals // The provided withdrawals BeaconRoot *common.Hash // The provided beaconRoot (Cancun) // - NoTxPool bool // Specular addition: option to disable tx pool contents from being included - Transactions []*types.Transaction // Specular addition: txs forced into the block via engine API + NoTxPool bool // L2 engine api addition: option to disable tx pool contents from being included + Transactions []*types.Transaction // L2 engine api addition: txs forced into the block via engine API + GasLimit *uint64 // L2 engine api addition: override gas limit of the block to build // } @@ -68,6 +69,9 @@ func (args *BuildPayloadArgs) Id() engine.PayloadID { hasher.Write(h[:]) } } + if args.GasLimit != nil { + binary.Write(hasher, binary.BigEndian, *args.GasLimit) + } // var out engine.PayloadID copy(out[:], hasher.Sum(nil)[:8]) @@ -193,6 +197,10 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { // Build the initial version with no transaction included. It should be fast // enough to run. The empty payload can at least make sure there is something // to deliver for not missing slot. + + // + // With L2s, the "empty" block is constructed from provided txs only, i.e. no tx-pool usage. + // emptyParams := &generateParams{ timestamp: args.Timestamp, forceTime: true, @@ -203,7 +211,8 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { beaconRoot: args.BeaconRoot, noTxs: true, // - txs: args.Transactions, + txs: args.Transactions, + gasLimit: args.GasLimit, // } empty := w.getSealingBlock(emptyParams) @@ -245,7 +254,8 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { beaconRoot: args.BeaconRoot, noTxs: false, // - txs: args.Transactions, + txs: args.Transactions, + gasLimit: args.GasLimit, // } diff --git a/miner/worker.go b/miner/worker.go index b4e2f8292e..3ebb71e9ba 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -902,7 +902,8 @@ type generateParams struct { beaconRoot *common.Hash // The beacon root (cancun field). noTxs bool // Flag whether an empty block without any transaction is expected // - txs types.Transactions // Transactions to include at the start of the block + txs types.Transactions // Transactions to include at the start of the block + gasLimit *uint64 // Optional gas limit override // } @@ -958,6 +959,15 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) } } + // + if genParams.gasLimit != nil { // override gas limit if specified + header.GasLimit = *genParams.gasLimit + } else if w.chain.Config().EnableL2GasLimitApi && w.config.GasCeil != 0 { + // configure the gas limit of pending blocks with the miner gas limit config when L2 gas limit config is enabled + header.GasLimit = w.config.GasCeil + } + // + // Apply EIP-4844, EIP-4788. if w.chainConfig.IsCancun(header.Number, header.Time) { var excessBlobGas uint64 @@ -1031,6 +1041,9 @@ func (w *worker) generateWork(params *generateParams) *newPayloadResult { } defer work.discard() // + if work.gasPool == nil { + work.gasPool = new(core.GasPool).AddGas(work.header.GasLimit) + } for _, tx := range params.txs { from, _ := types.Sender(work.signer, tx) work.state.SetTxContext(tx.Hash(), work.tcount) diff --git a/params/config.go b/params/config.go index f503862422..f3743f3e38 100644 --- a/params/config.go +++ b/params/config.go @@ -333,6 +333,10 @@ type ChainConfig struct { Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` IsDevMode bool `json:"isDev,omitempty"` + + // + EnableL2GasLimitApi bool `json:"enableL2GasLimitApi,omitempty"` + // } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -365,6 +369,10 @@ func (c *ChainConfig) Description() string { } banner += fmt.Sprintf("Chain ID: %v (%s)\n", c.ChainID, network) switch { + // + case c.EnableL2GasLimitApi: + banner += "Consensus: L2 gas limit API enabled\n" + // case c.Ethash != nil: if c.TerminalTotalDifficulty == nil { banner += "Consensus: Ethash (proof-of-work)\n"