From 87ab9435f542d48e70f65652242118e84795b83e Mon Sep 17 00:00:00 2001 From: Chase Wright Date: Tue, 11 Aug 2026 07:28:01 -0500 Subject: [PATCH] eth/catalyst: pass targetGasLimit through in testing_buildBlockV1 (#35501) `testing_buildBlockV1` decodes `targetGasLimit` from the payload attributes but does not pass it to `miner.BuildPayloadArgs`. The miner then falls back to its configured gas ceiling, so the field is silently ignored. The engine API path (`forkchoiceUpdated`) already passes it through. This matters for fixture generation in ethereum/execution-apis, where `testing_buildBlockV1` builds Amsterdam test blocks and the gas limit must honor the CL-provided target (see ethereum/execution-apis#857 and ethereum/execution-apis#862). The new test builds an Amsterdam block with a target inside the per-block adjustment bound and checks the payload hits it exactly. --- eth/catalyst/api_testing.go | 15 ++++++------ eth/catalyst/api_testing_test.go | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/eth/catalyst/api_testing.go b/eth/catalyst/api_testing.go index b017641a5b..9fbe058d0e 100644 --- a/eth/catalyst/api_testing.go +++ b/eth/catalyst/api_testing.go @@ -94,13 +94,14 @@ func (api *testingAPI) buildTestingBlock(payloadAttributes engine.PayloadAttribu extra = *extraData } args := &miner.BuildPayloadArgs{ - Parent: parentHash, - Timestamp: payloadAttributes.Timestamp, - FeeRecipient: payloadAttributes.SuggestedFeeRecipient, - Random: payloadAttributes.Random, - Withdrawals: payloadAttributes.Withdrawals, - BeaconRoot: payloadAttributes.BeaconRoot, - SlotNum: payloadAttributes.SlotNumber, + Parent: parentHash, + Timestamp: payloadAttributes.Timestamp, + FeeRecipient: payloadAttributes.SuggestedFeeRecipient, + Random: payloadAttributes.Random, + Withdrawals: payloadAttributes.Withdrawals, + BeaconRoot: payloadAttributes.BeaconRoot, + SlotNum: payloadAttributes.SlotNumber, + TargetGasLimit: payloadAttributes.TargetGasLimit, } return api.eth.Miner().BuildTestingPayload(args, txs, buildEmpty, extra) } diff --git a/eth/catalyst/api_testing_test.go b/eth/catalyst/api_testing_test.go index 8b20df13e4..b9c2a12ffb 100644 --- a/eth/catalyst/api_testing_test.go +++ b/eth/catalyst/api_testing_test.go @@ -120,6 +120,48 @@ func TestBuildBlockV1(t *testing.T) { }) } +func TestBuildBlockV1TargetGasLimit(t *testing.T) { + genesis, blocks := generateMergeChain(5, true) + + time := blocks[len(blocks)-1].Time() + 5 + genesis.Config.ShanghaiTime = &time + genesis.Config.CancunTime = &time + genesis.Config.PragueTime = &time + genesis.Config.OsakaTime = &time + genesis.Config.AmsterdamTime = &time + genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule + + n, ethservice := startEthService(t, genesis, blocks) + defer n.Close() + + var ( + api = &testingAPI{eth: ethservice} + parent = ethservice.BlockChain().CurrentBlock() + beaconRoot = common.Hash{42} + slot = uint64(1) + // Within the per-block adjustment bound, so the built block + // must hit the target exactly. + target = parent.GasLimit - 1000 + ) + attrs := engine.PayloadAttributes{ + Timestamp: parent.Time + 5, + Random: crypto.Keccak256Hash([]byte("test")), + SuggestedFeeRecipient: parent.Coinbase, + Withdrawals: make([]*types.Withdrawal, 0), + BeaconRoot: &beaconRoot, + SlotNumber: &slot, + TargetGasLimit: &target, + } + emptyTxs := []hexutil.Bytes{} + envelope, err := api.BuildBlockV1(parent.Hash(), attrs, &emptyTxs, nil) + if err != nil { + t.Fatalf("BuildBlockV1 failed: %v", err) + } + if got := envelope.ExecutionPayload.GasLimit; got != target { + t.Errorf("gas limit mismatch: got %d want %d", got, target) + } +} + func TestCommitBlockV1(t *testing.T) { genesis, blocks := generateMergeChain(5, true) n, ethservice := startEthService(t, genesis, blocks)