Skip to content

consensus, ethapi: embed gas target and base fee params in block header extra field (post Giugliano HF)#2135

Merged
pratikspatil024 merged 12 commits intodevelopfrom
psp-pos-3494
Mar 11, 2026
Merged

consensus, ethapi: embed gas target and base fee params in block header extra field (post Giugliano HF)#2135
pratikspatil024 merged 12 commits intodevelopfrom
psp-pos-3494

Conversation

@pratikspatil024
Copy link
Copy Markdown
Member

@pratikspatil024 pratikspatil024 commented Mar 10, 2026

Description

  • Extends BlockExtraData with two optional RLP fields (GasTarget, BaseFeeChangeDenominator) so full node operators and RPC users can determine the EIP-1559 parameters a block producer used
  • Populates these fields during Prepare() for post-Giugliano blocks and verifies their presence during block import in verifyCascadingFields()
  • Exports eip1559.CalcGasTarget() for use by consensus code
  • Adds bor_getBlockGasParams RPC method returning both values for any block (post Giugliano block)
  • Adds optional borExtra parameter to eth_getBlockByNumber and eth_getBlockByHash, when set to true, the response includes a blockExtraData object with parsed gasTarget, baseFeeChangeDenominator, and txDependency from the header extra field, eliminating the need for a second RPC call
  • Adds Header.DecodeBlockExtraData() for single-pass RLP decoding of the full BlockExtraData struct
  • Adds RLP backward compatibility and GetBaseFeeParams extraction tests

Changes

  • Bugfix (non-breaking change that solves an issue)
  • Hotfix (change that solves an urgent issue, and requires immediate attention)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (change that is not backwards-compatible and/or changes current functionality)
  • Changes only for a subset of nodes

Breaking changes

Please complete this section if any breaking changes have been made, otherwise delete it

Nodes audience

In case this PR includes changes that must be applied only to a subset of nodes, please specify how you handled it (e.g. by adding a flag with a default value...)

Checklist

  • I have added at least 2 reviewer or the whole pos-v1 team
  • I have added sufficient documentation in code
  • I will be resolving comments - if any - by pushing each fix in a separate commit and linking the commit hash in the comment reply
  • Created a task in Jira and informed the team for implementation in Erigon client (if applicable)
  • Includes RPC methods changes, and the Notion documentation has been updated

Cross repository changes

  • This PR requires changes to heimdall
    • In case link the PR here:
  • This PR requires changes to matic-cli
    • In case link the PR here:

Testing

  • I have added unit tests
  • I have added tests to CI
  • I have tested this code manually on local environment
  • I have tested this code manually on remote devnet using express-cli
  • I have tested this code manually on amoy
  • I have created new e2e tests into express-cli

Manual tests

Please complete this section with the steps you performed if you ran manual tests for this functionality, otherwise delete it

Additional comments

Please post additional comments in this section if you have them, otherwise delete it

@pratikspatil024 pratikspatil024 requested review from a team, cffls and lucca30 March 10, 2026 04:14
@claude
Copy link
Copy Markdown

claude bot commented Mar 10, 2026

Code Review

Bug found in consensus/bor/bor.go line 993: setGiuglianoExtraFields passes the current block header to CalcGasTarget and BaseFeeChangeDenominator, but both functions expect the parent header. CalcGasTarget wraps calcParentGasTarget which reads parent.GasLimit, parent.BaseFee, parent.Number. At Prepare() time, the current header has different values (GasLimit adjusted by CalcGasLimit, BaseFee is the new value, Number is parent+1). The fix is to pass the parent header, available via chain.GetHeaderByHash(header.ParentHash).

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 10, 2026

Codecov Report

❌ Patch coverage is 82.20339% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 51.49%. Comparing base (0f809a9) to head (268474d).
⚠️ Report is 3 commits behind head on develop.

Files with missing lines Patch % Lines
internal/ethapi/bor_api.go 88.67% 4 Missing and 2 partials ⚠️
params/config.go 0.00% 5 Missing ⚠️
core/types/block.go 87.50% 2 Missing and 1 partial ⚠️
consensus/bor/bor.go 91.30% 2 Missing ⚠️
consensus/misc/eip1559/eip1559.go 0.00% 2 Missing ⚠️
internal/ethapi/api.go 77.77% 2 Missing ⚠️
eth/bor_checkpoint_verifier.go 50.00% 1 Missing ⚠️

❌ Your patch status has failed because the patch coverage (82.20%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #2135      +/-   ##
===========================================
+ Coverage    51.48%   51.49%   +0.01%     
===========================================
  Files          881      882       +1     
  Lines       153870   154110     +240     
===========================================
+ Hits         79216    79359     +143     
- Misses       69482    69584     +102     
+ Partials      5172     5167       -5     
Files with missing lines Coverage Δ
eth/bor_checkpoint_verifier.go 45.81% <50.00%> (ø)
consensus/bor/bor.go 83.99% <91.30%> (+0.51%) ⬆️
consensus/misc/eip1559/eip1559.go 95.76% <0.00%> (-1.66%) ⬇️
internal/ethapi/api.go 40.96% <77.77%> (+0.13%) ⬆️
core/types/block.go 40.56% <87.50%> (+3.40%) ⬆️
params/config.go 36.81% <0.00%> (-0.30%) ⬇️
internal/ethapi/bor_api.go 65.56% <88.67%> (+1.53%) ⬆️

... and 24 files with indirect coverage changes

Files with missing lines Coverage Δ
eth/bor_checkpoint_verifier.go 45.81% <50.00%> (ø)
consensus/bor/bor.go 83.99% <91.30%> (+0.51%) ⬆️
consensus/misc/eip1559/eip1559.go 95.76% <0.00%> (-1.66%) ⬇️
internal/ethapi/api.go 40.96% <77.77%> (+0.13%) ⬆️
core/types/block.go 40.56% <87.50%> (+3.40%) ⬆️
params/config.go 36.81% <0.00%> (-0.30%) ⬇️
internal/ethapi/bor_api.go 65.56% <88.67%> (+1.53%) ⬆️

... and 24 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Collaborator

@marcello33 marcello33 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some warning/errors detected from SonarCloud
Other than that, LGTM

@pratikspatil024 pratikspatil024 changed the title consensus, ethapi: embed gas target and base fee params in block header extra field (Giugliano HF) consensus, ethapi: embed gas target and base fee params in block header extra field (post Giugliano HF) Mar 10, 2026
@pratikspatil024
Copy link
Copy Markdown
Member Author

@claude - review this PR

@claude
Copy link
Copy Markdown

claude bot commented Mar 11, 2026

Claude finished @pratikspatil024's task in 4m 30s —— View job


PR Review: Embed gas target and base fee params in block header extra field (post Giugliano HF)

  • Read all changed files and understand the changes
  • Review consensus logic (bor.go, eip1559.go)
  • Review types and RLP encoding (block.go, block_test.go)
  • Review RPC API changes (api.go, bor_api.go)
  • Review config changes and test coverage
  • Post comprehensive review

Overall Assessment

Well-structured PR with good test coverage. The original bug I flagged (passing the current header instead of the parent to setGiuglianoExtraFields) has been fixed in commit 12787bb. The code correctly passes the parent header now.

Issues Found

1. Verification only checks presence, not correctness (Medium)

consensus/bor/bor.go:478-484 — The verification in verifyHeader only checks that GasTarget and BaseFeeChangeDenominator are present (non-nil), but doesn't validate their values. A malicious block producer could embed arbitrary values (e.g., GasTarget=1, BaseFeeChangeDenominator=1000000) and pass verification.

This matters because RPC consumers will trust these values. If the intent is informational-only and the actual base fee calculation uses its own computation (which it does in CalcBaseFee), this is acceptable — but it should be documented that these are self-reported by the block producer and not validated for correctness. Consider adding a comment or, if the values should be trustworthy, validating them against the expected values:

// Option: validate correctness
expectedGasTarget := eip1559.CalcGasTarget(c.chainConfig, parent)
expectedBfcd := params.BaseFeeChangeDenominator(c.config, parent.Number)
if *gasTarget != expectedGasTarget || *bfcd != expectedBfcd {
    return fmt.Errorf("post-Giugliano block %d: gas params mismatch", number)
}

Fix this →

2. GasTarget set with only one field nil would still pass (Low)

If a block is crafted with GasTarget set but BaseFeeChangeDenominator nil (or vice versa), the current check rejects it. This is correct. However, there's no check for zero-value fields — a producer could set GasTarget = 0 or BaseFeeChangeDenominator = 0. A zero BaseFeeChangeDenominator would cause a division-by-zero if any consumer naively trusts it for computation. Consider adding a > 0 check:

if gasTarget == nil || bfcd == nil || *gasTarget == 0 || *bfcd == 0 {
    return fmt.Errorf("post-Giugliano block %d: invalid or missing gas params", number)
}

3. RLP decode duplication across methods (Low — code quality)

GetValidatorBytes, GetBaseFeeParams, DecodeBlockExtraData, and GetTxDependency all independently RLP-decode the same BlockExtraData from Header.Extra. While DecodeBlockExtraData was added as a single-pass helper, the older methods still do separate decodes. This isn't a bug, but callers needing multiple fields should prefer DecodeBlockExtraData — might be worth a comment on the older methods noting that.

Positive Notes

  • Bug fix verified: The parent-vs-current header bug (commit 12787bb) is correctly resolved. setGiuglianoExtraFields now receives parent explicitly and uses it for both CalcGasTarget and BaseFeeChangeDenominator.

  • RLP backward compatibility: The rlp:"optional" tags on GasTarget and BaseFeeChangeDenominator correctly handle pre-Giugliano blocks. The TestBlockExtraDataRLPBackwardCompatibility test verifies this.

  • Clean API design: The borExtra *bool pointer pattern for optional RPC params is well-explained and maintains backward compatibility.

  • Good test coverage: Tests cover pre/post Giugliano for both Prepare and verifyHeader, RLP backward compat, GetBaseFeeParams edge cases, RPC endpoints (by number, by hash, nil/false/true borExtra).

  • Parent fetch moved up: The parent header fetch was moved earlier in Prepare() (line 1028), avoiding a duplicate lookup.

Nits

  • bor.go:1059,1079: Pre-existing issue — log.Error("error while encoding block extra data: %v", err) uses printf-style formatting but go-ethereum's log.Error expects key-value pairs. Should be log.Error("error while encoding block extra data", "err", err). Not introduced by this PR but worth fixing while touching these lines.

  • bor.go:482: The error message fmt.Errorf("post-Giugliano block %d missing gas target...") could be a sentinel error variable for consistency with other errors in the file (e.g., errExtraValidators, errInvalidSpanValidators).


|

Copy link
Copy Markdown
Member

@manav2401 manav2401 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few small nits, else LGTM.

@sonarqubecloud
Copy link
Copy Markdown

@pratikspatil024 pratikspatil024 merged commit 5eb6b6c into develop Mar 11, 2026
19 of 20 checks passed
@pratikspatil024 pratikspatil024 deleted the psp-pos-3494 branch March 11, 2026 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants