eth/catalyst: pass TargetGasLimit via engine api (#35372)
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run

Pass targetGasLimit via engine api

---------

Co-authored-by: Gary Rong <garyrong0905@gmail.com>
This commit is contained in:
Marius van der Wijden 2026-07-20 09:08:23 +02:00 committed by GitHub
parent 4911ab04fc
commit 4363b81e6f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 92 additions and 59 deletions

View file

@ -34,8 +34,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
SlotNumber *hexutil.Uint64 `json:"slotNumber,omitempty"`
BlockAccessList hexutil.Bytes `json:"blockAccessList,omitempty"`
SlotNumber *hexutil.Uint64 `json:"slotNumber,omitempty"`
}
var enc ExecutableData
enc.ParentHash = e.ParentHash
@ -60,8 +60,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
enc.Withdrawals = e.Withdrawals
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
enc.SlotNumber = (*hexutil.Uint64)(e.SlotNumber)
enc.BlockAccessList = e.BlockAccessList
enc.SlotNumber = (*hexutil.Uint64)(e.SlotNumber)
return json.Marshal(&enc)
}
@ -85,8 +85,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
SlotNumber *hexutil.Uint64 `json:"slotNumber,omitempty"`
BlockAccessList *hexutil.Bytes `json:"blockAccessList,omitempty"`
SlotNumber *hexutil.Uint64 `json:"slotNumber,omitempty"`
}
var dec ExecutableData
if err := json.Unmarshal(input, &dec); err != nil {
@ -160,11 +160,11 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
if dec.ExcessBlobGas != nil {
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
}
if dec.SlotNumber != nil {
e.SlotNumber = (*uint64)(dec.SlotNumber)
}
if dec.BlockAccessList != nil {
e.BlockAccessList = *dec.BlockAccessList
}
if dec.SlotNumber != nil {
e.SlotNumber = (*uint64)(dec.SlotNumber)
}
return nil
}

View file

@ -22,6 +22,7 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) {
Withdrawals []*types.Withdrawal `json:"withdrawals"`
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
SlotNumber *hexutil.Uint64 `json:"slotNumber"`
TargetGasLimit *hexutil.Uint64 `json:"targetGasLimit"`
}
var enc PayloadAttributes
enc.Timestamp = hexutil.Uint64(p.Timestamp)
@ -30,6 +31,7 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) {
enc.Withdrawals = p.Withdrawals
enc.BeaconRoot = p.BeaconRoot
enc.SlotNumber = (*hexutil.Uint64)(p.SlotNumber)
enc.TargetGasLimit = (*hexutil.Uint64)(p.TargetGasLimit)
return json.Marshal(&enc)
}
@ -42,6 +44,7 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error {
Withdrawals []*types.Withdrawal `json:"withdrawals"`
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
SlotNumber *hexutil.Uint64 `json:"slotNumber"`
TargetGasLimit *hexutil.Uint64 `json:"targetGasLimit"`
}
var dec PayloadAttributes
if err := json.Unmarshal(input, &dec); err != nil {
@ -68,5 +71,8 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error {
if dec.SlotNumber != nil {
p.SlotNumber = (*uint64)(dec.SlotNumber)
}
if dec.TargetGasLimit != nil {
p.TargetGasLimit = (*uint64)(dec.TargetGasLimit)
}
return nil
}

View file

@ -59,7 +59,7 @@ var (
//
// https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#executionpayloadv4
// ExecutionPayloadV4 has the syntax of ExecutionPayloadV3 and appends the new
// field slotNumber.
// fields slotNumber and blockAccessList.
PayloadV4 PayloadVersion = 0x4
)
@ -74,12 +74,14 @@ type PayloadAttributes struct {
Withdrawals []*types.Withdrawal `json:"withdrawals"`
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
SlotNumber *uint64 `json:"slotNumber"`
TargetGasLimit *uint64 `json:"targetGasLimit"`
}
// JSON type overrides for PayloadAttributes.
type payloadAttributesMarshaling struct {
Timestamp hexutil.Uint64
SlotNumber *hexutil.Uint64
TargetGasLimit *hexutil.Uint64
}
//go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out ed_codec.go
@ -103,8 +105,8 @@ type ExecutableData struct {
Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *uint64 `json:"blobGasUsed"`
ExcessBlobGas *uint64 `json:"excessBlobGas"`
SlotNumber *uint64 `json:"slotNumber,omitempty"`
BlockAccessList []byte `json:"blockAccessList,omitempty"`
SlotNumber *uint64 `json:"slotNumber,omitempty"`
}
// JSON type overrides for executableData.
@ -440,7 +442,7 @@ type ExecutionPayloadBody struct {
// ExecutionPayloadBodyV2 extends ExecutionPayloadBody with the block access list.
type ExecutionPayloadBodyV2 struct {
ExecutionPayloadBody
BlockAccessList *bal.BlockAccessList `json:"blockAccessList"`
BlockAccessList *hexutil.Bytes `json:"blockAccessList"`
}
// Client identifiers to support ClientVersionV1.

View file

@ -229,6 +229,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV4(ctx context.Context, update engine.
return engine.STATUS_INVALID, attributesErr("missing beacon root")
case params.SlotNumber == nil:
return engine.STATUS_INVALID, attributesErr("missing slot number")
case params.TargetGasLimit == nil:
return engine.STATUS_INVALID, attributesErr("missing target gas limit")
case !api.checkFork(params.Timestamp, forks.Amsterdam):
return engine.STATUS_INVALID, unsupportedForkErr("fcuV4 must only be called for amsterdam payloads")
}
@ -392,6 +394,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(ctx context.Context, update engine.Fo
Withdrawals: payloadAttributes.Withdrawals,
BeaconRoot: payloadAttributes.BeaconRoot,
SlotNum: payloadAttributes.SlotNumber,
TargetGasLimit: payloadAttributes.TargetGasLimit,
Version: payloadVersion,
}
id := args.Id()
@ -1320,9 +1323,17 @@ func getBodyV2(block *types.Block) *engine.ExecutionPayloadBodyV2 {
if body == nil {
return nil
}
var balData *hexutil.Bytes
if bal := block.AccessList(); bal != nil {
// Ignore the RLP encoding error just in case, interpreting
// the BAL as unavailable.
if enc, err := rlp.EncodeToBytes(bal); err == nil {
balData = (*hexutil.Bytes)(&enc)
}
}
return &engine.ExecutionPayloadBodyV2{
ExecutionPayloadBody: *body,
BlockAccessList: block.AccessList(),
BlockAccessList: balData,
}
}

View file

@ -1594,7 +1594,7 @@ func TestGetPayloadBodyV2BlockAccessList(t *testing.T) {
name: "retained empty BAL",
header: &types.Header{BlockAccessListHash: &emptyHash},
accessList: &empty,
want: "[]",
want: `"0xc0"`, // JSON-encoded hex string, quotes included
},
{
name: "pruned BAL",

View file

@ -46,7 +46,8 @@ type BuildPayloadArgs struct {
Random common.Hash // The provided randomness value
Withdrawals types.Withdrawals // The provided withdrawals
BeaconRoot *common.Hash // The provided beaconRoot (Cancun)
SlotNum *uint64 // The provided slotNumber
SlotNum *uint64 // The provided slotNumber (Amsterdam)
TargetGasLimit *uint64 // The provided target gas limit (Amsterdam)
Version engine.PayloadVersion // Versioning byte for payload id calculation.
}
@ -62,7 +63,10 @@ func (args *BuildPayloadArgs) Id() engine.PayloadID {
hasher.Write(args.BeaconRoot[:])
}
if args.SlotNum != nil {
binary.Write(hasher, binary.BigEndian, args.SlotNum)
binary.Write(hasher, binary.BigEndian, *args.SlotNum)
}
if args.TargetGasLimit != nil {
binary.Write(hasher, binary.BigEndian, *args.TargetGasLimit)
}
var out engine.PayloadID
copy(out[:], hasher.Sum(nil)[:8])
@ -254,6 +258,7 @@ func (miner *Miner) buildPayload(ctx context.Context, args *BuildPayloadArgs, wi
withdrawals: args.Withdrawals,
beaconRoot: args.BeaconRoot,
slotNum: args.SlotNum,
targetGasLimit: args.TargetGasLimit,
noTxs: true,
}
empty := miner.generateWork(ctx, emptyParams, witness)
@ -294,6 +299,7 @@ func (miner *Miner) buildPayload(ctx context.Context, args *BuildPayloadArgs, wi
withdrawals: args.Withdrawals,
beaconRoot: args.BeaconRoot,
slotNum: args.SlotNum,
targetGasLimit: args.TargetGasLimit,
noTxs: false,
}
for {
@ -351,6 +357,7 @@ func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*
withdrawals: args.Withdrawals,
beaconRoot: args.BeaconRoot,
slotNum: args.SlotNum,
targetGasLimit: args.TargetGasLimit,
noTxs: empty,
forceOverrides: true,
overrideExtraData: extraData,

View file

@ -125,6 +125,7 @@ type generateParams struct {
withdrawals types.Withdrawals // List of withdrawals to include in block (shanghai field)
beaconRoot *common.Hash // The beacon root (cancun field).
slotNum *uint64 // The slot number (amsterdam field).
targetGasLimit *uint64 // The target gas limit requested by the CL (amsterdam field).
noTxs bool // Flag whether an empty block without any transaction is expected
forceOverrides bool // Flag whether we should overwrite extraData and transactions
@ -267,11 +268,17 @@ func (miner *Miner) prepareWork(ctx context.Context, genParams *generateParams,
}
timestamp = parent.Time + 1
}
// Post-Amsterdam use TargetGasLimit provided by CL
number := new(big.Int).Add(parent.Number, common.Big1)
gasCeil := miner.config.GasCeil
if miner.chainConfig.IsAmsterdam(number, timestamp) && genParams.targetGasLimit != nil {
gasCeil = *genParams.targetGasLimit
}
// Construct the sealing block header.
header := &types.Header{
ParentHash: parent.Hash(),
Number: new(big.Int).Add(parent.Number, common.Big1),
GasLimit: core.CalcGasLimit(parent.GasLimit, miner.config.GasCeil),
Number: number,
GasLimit: core.CalcGasLimit(parent.GasLimit, gasCeil),
Time: timestamp,
Coinbase: genParams.coinbase,
}