Skip to content

rpc: impl eth fill transaction#21870

Merged
lupin012 merged 21 commits into
mainfrom
lupin012/impl_eth_fillTransaction
Jun 27, 2026
Merged

rpc: impl eth fill transaction#21870
lupin012 merged 21 commits into
mainfrom
lupin012/impl_eth_fillTransaction

Conversation

@lupin012

@lupin012 lupin012 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

closes #21864

Implements eth_fillTransaction compatible with Geth.

The method accepts the parameters of a partial transaction, fills in the missing fields (nonce, gas limit, gas price / EIP-1559 fee caps, chain ID, blob fee), and returns the RLP-serialized transaction (raw) together with its JSON representation (tx), without signing or submitting it.

Main changes

  • rpc/jsonrpc/eth_fill_transaction.go — implementation of FillTransaction on APIImpl, with a fillFeeDefaults helper that handles both the pre-London path (gas price from oracle) and the post-London path (EIP-1559, blob fee).
  • rpc/ethapi/api.go — adds SignTransactionResult (reusable by eth_signTransaction as well) with a custom MarshalJSON that strips block-placement/sender fields and normalises fee and signature fields to match Geth's output.
  • rpc/jsonrpc/eth_api.go — adds FillTransaction to the EthAPI interface.
  • rpc/jsonrpc/eth_fill_transaction_test.go and rpc/ethapi/api_test.go — tests covering the happy path, conflicting fee arguments, wrong chainID, contract creation without data, blob transactions before Cancun, and JSON serialisation for both EIP-1559 and legacy transactions.
  • cmd/rpcdaemon/README.md — marks eth_fillTransaction as implemented.

Notes

  • The rpc-tests version will be tagged and rpc_version.env updated to a stable tag once the PR is approved
  • Added 15 RPC tests to latest, comparing them against the Geth response.

lupin012 added 5 commits June 17, 2026 21:48
SignTransactionResult.MarshalJSON now explicitly emits gasPrice:null for
EIP-1559 transactions, maxFeePerGas:null/maxPriorityFeePerGas:null for
legacy transactions, and normalises null v/r/s to "0x0" for unsigned
transactions.  Adds blob/authorizationList validation checks to
FillTransaction and two unit tests that pin the serialisation contract.
fillFeeDefaults constructed NewOracle unconditionally, wasting allocs on
the three fast-exit paths (pre-London with gasPrice set, post-London with
all EIP-1559 fields supplied, post-London legacy gasPrice path).  Move
oracle construction to the two branches that actually call SuggestTipCap.
Also remove the redundant isPostLondon variable.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Implements the eth_fillTransaction JSON-RPC method in rpcdaemon, returning an unsigned, default-populated transaction along with its raw-encoded form (Geth-compatible response shape).

Changes:

  • Add eth_fillTransaction implementation that fills nonce/fees/gas/chainId defaults and returns an RLP/binary-encoded transaction plus its JSON form.
  • Introduce ethapi.SignTransactionResult with custom JSON marshaling to match Geth’s field behavior for unsigned txs.
  • Update docs and CI rpc-tests version pinning to reflect the new method support.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
rpc/jsonrpc/eth_fill_transaction.go Adds the FillTransaction RPC implementation and fee-default helper logic.
rpc/jsonrpc/eth_fill_transaction_test.go Adds basic unit tests for default filling and a few validation errors.
rpc/jsonrpc/eth_api.go Extends the EthAPI interface to include FillTransaction.
rpc/ethapi/api.go Adds SignTransactionResult + custom MarshalJSON to normalize response fields for fill/sign flows.
rpc/ethapi/api_test.go Adds tests covering SignTransactionResult JSON normalization for legacy and EIP-1559 txs.
cmd/rpcdaemon/README.md Marks eth_fillTransaction as implemented in the RPC support table.
.github/workflows/scripts/rpc_version.env Changes the pinned rpc-tests version/branch used by CI workflows.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rpc/jsonrpc/eth_fill_transaction.go Outdated
Comment thread rpc/jsonrpc/eth_fill_transaction.go Outdated
Comment thread .github/workflows/scripts/rpc_version.env Outdated
lupin012 added 3 commits June 18, 2026 08:55
- Propagate GetTransactionCount error in nonce fallback instead of
  silently leaving nonce at 0, which would produce an incorrect contract
  address for deployments.
- Return a clear error for blob transactions on pre-Cancun chains
  (ExcessBlobGas == nil) instead of panicking when ToTransaction
  dereferences a nil MaxFeePerBlobGas.
@lupin012 lupin012 marked this pull request as ready for review June 20, 2026 15:16
- validate maxFeePerBlobGas != 0 if specified (matches Geth)
- extract newGasOracle helper to avoid duplicating oracle construction in fillFeeDefaults
- add tests for From=nil (nonce defaults to 0), explicit nonce preservation, explicit gas preservation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread rpc/jsonrpc/eth_fill_transaction.go Outdated
Comment thread rpc/jsonrpc/eth_fill_transaction.go
Comment thread rpc/jsonrpc/eth_fill_transaction.go
Comment thread rpc/jsonrpc/eth_fill_transaction.go Outdated
Comment thread rpc/ethapi/api.go
Comment thread rpc/jsonrpc/eth_fill_transaction_test.go
lupin012 added 2 commits June 21, 2026 09:52
- preserve user-provided gas (pass 0 instead of api.GasCap to ToTransaction)
- warn on txpool nonce fallback instead of silently using on-chain nonce
- improve error message when only maxFeePerGas is provided and oracle tip exceeds it
- add README note about blob sidecar not supported
- add tests for pool error fallback, gas cap bypass, pool nonce, fee filling, gas price post-London
- avoid calling gas oracle when MaxPriorityFeePerGas is already set
- merge blob-hash guards into single block; drop redundant proto nil guard; inline baseFee
Comment thread rpc/jsonrpc/eth_fill_transaction.go
@yperbasis yperbasis added this to the 3.6.0 milestone Jun 22, 2026
@yperbasis yperbasis added the RPC label Jun 22, 2026

@yperbasis yperbasis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Requesting changes — mostly mechanical, plus two items that need a decision. Implementation itself looks correct (builds clean, new tests pass, JSON shape matches Geth's types.Transaction output).

Blocking

  • .github/workflows/scripts/rpc_version.env is pinned to a feature branch (lupin012/add_test_eth_fillTransaction) and adds a stray trailing newline. Branch pins make CI non-reproducible and break if the branch moves — please cut a tag in rpc-tests and pin to it before merge (as the PR description already plans).
  • The branch currently conflicts with main (needs a rebase/merge).

Please address or reply

  • gasPrice + accessList post-London: the shared ToTransaction returns an AccessListTx (type 1) where Geth forces LegacyTx (type 0). Sahil-4555's thread on this is still open — please make an explicit call and document the divergence. (Note Geth's path drops the access list, so blindly matching it isn't clearly better.)
  • The nonce-filling block in eth_fill_transaction.go re-implements what GetTransactionCount already does for pending (rpc/jsonrpc/eth_accounts.go:99-111: txpool nonce+1 → state fallback). Suggest reusing it — simpler, and it propagates the pool error like Geth instead of silently falling back to the on-chain nonce.

Minor / non-blocking

  • SignTransactionResult.MarshalJSON: the marshal → map → strip → re-marshal denylist will silently leak any future block-placement field added to RPCTransaction into the output. A dedicated typed output struct would be more robust.
  • raw field: ethereum/execution-apis#803 drops it from FillTransactionResult. Keeping it to match current Geth is fine, but it's a known future breaking change for a new method — worth linking a tracking issue.

lupin012 added 3 commits June 22, 2026 19:14
… type-1 divergence

Two fixes for yperbasis's review of PR #21870:

1. gasPrice + accessList type: document the deliberate divergence from Geth
   in ToTransaction — Erigon preserves type-1 when an explicit accessList is
   given alongside gasPrice; Geth silently drops it to LegacyTx (type 0).
   Add TestFillTransactionGasPriceWithAccessListIsTypeOne to pin the behavior.

2. Nonce filling: replace the inline txpool→warn→fallback block with a
   single GetTransactionCount(pending) call. Propagates pool errors to the
   caller instead of silently falling back to the on-chain nonce, matching
   Geth's behavior. Also fix _GetBlockNumber to guard LastPendingBlock behind
   a nil check on filters (consistent with the existing nil guard for WithOverlay).
…yped allowlist

Replace the marshal→map→strip→re-marshal approach with a dedicated
signedTxJSON struct. New fields added to RPCTransaction will not leak
into the output since only explicitly listed fields are marshalled.
@lupin012

Copy link
Copy Markdown
Contributor Author

@yperbasis
Blocking: rebase done, The rpc-tests version will be tagged and rpc_version.env updated to a stable tag once the PR is approved to avoid to block the main rpctests waiting approval of the PR
Please address or reply: done
Minor / non-blocking:
add signedTxJSON, open issue 21948

@lupin012 lupin012 requested a review from yperbasis June 22, 2026 19:10
@lupin012 lupin012 requested a review from Sahil-4555 June 22, 2026 19:10

@yperbasis yperbasis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for this. A few correctness and test-quality issues to sort out before it can go in — details inline.

Comment thread rpc/jsonrpc/eth_fill_transaction.go Outdated
Comment thread rpc/jsonrpc/eth_fill_transaction_test.go
Comment thread rpc/jsonrpc/eth_fill_transaction_test.go
Comment thread rpc/ethapi/api.go Outdated
Comment thread .github/workflows/scripts/rpc_version.env Outdated
lupin012 added 2 commits June 23, 2026 20:47
…Transaction

- Hoist head.ExcessBlobGas == nil check outside MaxFeePerBlobGas == nil guard
  so pre-Cancun blob requests error even when maxFeePerBlobGas is explicit.
- Fix TestFillTransactionExplicitNoncePreserved: use nonce 7 (not 42, which
  collides with the DB state of the test sender and made the test vacuous).
- Fix TestFillTransactionUserGasAboveCapPreserved comment: FillTransaction
  passes globalGasCap=0 so no capping can occur on that path.
- Add nil guard on r.Tx in SignTransactionResult.MarshalJSON to prevent panic
  when the type is used with a nil transaction.
- Add TestFillTransactionBlobPreCancunExplicitBlobFee and
  TestSignTransactionResultMarshalJSON_NilTx.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment thread rpc/jsonrpc/eth_fill_transaction.go Outdated
Comment thread rpc/jsonrpc/eth_fill_transaction_test.go

@yperbasis yperbasis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A few changes before merge:

  • signedTxJSON (rpc/ethapi/api.go) duplicates RPCTransaction and diverges from Geth's output shape. It's a hand-maintained parallel copy of the fields — if RPCTransaction ever gains a field, eth_fillTransaction silently drops it (no compile error, no test failure). It also drops omitempty from gasPrice/maxFeePerGas/maxPriorityFeePerGas, so a 1559 tx emits "gasPrice": null and a legacy tx emits "maxFeePerGas": null / "maxPriorityFeePerGas": null. Geth instead omits the inapplicable 1559 fields on a legacy tx and sets gasPrice to the fee cap on an unmined 1559 tx (here computeGasPrice returns nil because FillTransaction calls NewRPCTransaction with baseFee == nil). Please confirm the reference rpc-tests expect this exact shape, or marshal RPCTransaction and strip the unwanted keys so new fields flow through automatically.

  • FillTransaction estimates gas against latest but takes the nonce from pending. EstimateGas(ctx, &args, nil, …) defaults to the latest block, while the nonce comes from GetTransactionCount(…, PendingBlockNumber). For a sender with in-flight pending txs the estimate can be wrong or fail even though the tx would succeed once those land — the two should use the same block.

  • newGasOracle duplicates oracle construction already written verbatim three times in eth_system.go (GasPrice, MaxPriorityFeePerGas, FeeHistory). Route those call sites through the new helper so the wiring lives in one place and can't drift.

  • Comment policy (.claude/rules/comments.md): the "Deliberate divergence from Geth …" comment on ToTransaction is PR-description narration and is repeated verbatim in the test — trim it to one sentence and drop the test copy.

  • Nit: the new files carry // Copyright 2024 The Erigon Authors — should be 2026.

lupin012 added 2 commits June 24, 2026 16:54
…Transaction

- Remove signedTxJSON; marshal RPCTransaction via map and strip placement/sender
  fields so new fields flow through automatically; inapplicable fee fields are
  absent (not null), matching Geth
- Estimate gas against explicit latest block reference (matching Geth)
- Consolidate newGasOracle helper; route GasPrice/MaxPriorityFeePerGas/FeeHistory
  through it with feeHistoryCache wired in
- Fix MaxFeePerBlobGas default: use CalcExcessBlobGas for next-block excess
  instead of head.ExcessBlobGas directly
- Add TestFillTransactionBlobFeeUsesNextBlockExcess (RED before fix, GREEN after)
…nResult

EIP-1559 txs lack gasPrice; legacy txs lack maxFeePerGas/maxPriorityFeePerGas.
RPCTransaction omits nil fields, but Geth emits null for them. Inject null
in SignTransactionResult.MarshalJSON to match Geth's eth_fillTransaction output.
@lupin012 lupin012 requested a review from yperbasis June 24, 2026 15:41

@yperbasis yperbasis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving — implementation is solid and well-tested.

One thing worth confirming before tagging the rpc-tests version: the blob fee default in eth_fill_transaction.go diverges from Geth in two ways. Erigon computes maxFeePerBlobGas as 2 × GetBlobGasPrice(CalcExcessBlobGas(next block)) — basing it on the next block's excess blob gas and doubling the result. Geth's setFeeDefaults uses eip4844.CalcBlobFee(config, head) on the head block with no doubling (it only doubles the regular maxFeePerGas). Since the new rpc-tests compare against Geth's response, a blob-fill case would return a larger value and mismatch. TestFillTransactionBlobFeeUsesNextBlockExcess only pins Erigon's own chosen value, so it won't catch this. If the divergence is intentional, a note in the README entry would help.

@lupin012

Copy link
Copy Markdown
Contributor Author

@yperbasis: aligned blob fee default to Geth:

  • use head ExcessBlobGas directly;
  • keep 2× fee on maxFeePerBlobGas as Geth does

@lupin012 lupin012 added this pull request to the merge queue Jun 27, 2026
Merged via the queue into main with commit aa8dceb Jun 27, 2026
93 checks passed
@lupin012 lupin012 deleted the lupin012/impl_eth_fillTransaction branch June 27, 2026 22:40
taratorio pushed a commit that referenced this pull request Jun 30, 2026
closes #21864 

Implements eth_fillTransaction compatible with Geth.

The method accepts the parameters of a partial transaction, fills in the
missing fields (nonce, gas limit, gas price / EIP-1559 fee caps, chain
ID, blob fee), and returns the RLP-serialized transaction (raw) together
with its JSON representation (tx), without signing or submitting it.

  Main changes

- rpc/jsonrpc/eth_fill_transaction.go — implementation of
FillTransaction on APIImpl, with a fillFeeDefaults helper that handles
both the pre-London path (gas price from oracle) and the post-London
path (EIP-1559, blob fee).
- rpc/ethapi/api.go — adds SignTransactionResult (reusable by
eth_signTransaction as well) with a custom MarshalJSON that strips
block-placement/sender fields and normalises fee and signature fields to
match Geth's output.
- rpc/jsonrpc/eth_api.go — adds FillTransaction to the EthAPI interface.
- rpc/jsonrpc/eth_fill_transaction_test.go and rpc/ethapi/api_test.go —
tests covering the happy path, conflicting fee arguments, wrong chainID,
contract creation without data, blob transactions before Cancun, and
JSON serialisation for both EIP-1559 and legacy transactions.
  - cmd/rpcdaemon/README.md — marks eth_fillTransaction as implemented.

  Notes
* The rpc-tests version will be tagged and rpc_version.env updated to a
stable tag once the PR is approved
* Added 15 RPC tests to latest, comparing them against the Geth
response.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

implement eth_fillTransaction

4 participants