rpc: fix testing build block v1 according Hive Test#20592
rpc: fix testing build block v1 according Hive Test#20592
Conversation
Move staticTxnProvider from txnprovider (public API) into the testing_ namespace where it belongs. Replace Parameters.OverrideTxns with Parameters.CustomProvider (txnprovider.TxnProvider interface) so the builder is opaque to the provider implementation. - builder.Parameters: OverrideTxns *[]types.Transaction → CustomProvider TxnProvider - builder.Build: drop NewStaticTxnProvider call, just assign param.CustomProvider - engineapi/testing_api: add local staticTxnProvider, create it after tx decode - txnprovider/provider.go: remove NewStaticTxnProvider (reverted to main) - txnprovider/shutter/pool_test.go: restore EmptyTxnProvider (reverted to main) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove GetAccountNonce from ExecModule (execmodule/getters.go) — it was added solely for the testing_ namespace - Remove accountNonceGetter interface and nonceGetter field from testingImpl; replace with a private getAccountNonce method that uses t.db and t.logger directly - Add logger and db params to NewTestingImpl / NewTestingRPCEntry; pass s.logger and s.chainDB from backend.go - Move case "testing" into jsonrpc.APIList switch (same pattern as other namespaces); add testingEntry *rpc.API param to APIList - Restructure "nonce too low" test: simulate via two txs with the same nonce from the same sender (no db required) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove redundant `if len(*transactions) > 0` guard in decodeTxnProvider (range over empty slice is already a no-op) - staticTxnProvider.ProvideTxns: nil out txns slice after consume to allow GC of decoded transactions once the builder has taken them - TestStaticTxnProvider: replace ECDSA key generation with a simple stub transaction — atomic consumed semantics don't require a real tx - Extract nilGetAssembledBlock as a package-level var shared by TestBuildBlockV1AssembleParamsVersion and TestBuildBlockV1MultipleSendersNonce - Add TestBuildBlockV1AssembleParamsVersion: verifies fork-specific fields (ParentBeaconBlockRoot, Withdrawals) are correctly propagated to assembleParams - Add TestBuildBlockV1MultipleSendersNonce: covers per-sender nonce tracking with interleaved transactions from two different senders - Add TestStaticTxnProvider: direct unit test of ProvideTxns atomic behaviour Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes Hive failures for testing_buildBlockV1 by adding explicit transaction list support, wiring the testing_ namespace through the standard JSON-RPC API registry, and aligning payload JSON output with expectations.
Changes:
- Implement explicit transaction-list flow in
testing_buildBlockV1(decode txs, recover senders, strict per-sender sequential nonce validation) and plumb it into the builder via aCustomTxnProvider. - Wire
testing_intojsonrpc.APIListand pass the entry fromnode/eth/backend.go(with a prominent production warning when enabled). - Adjust Engine API JSON encoding for
blockAccessListto omit empty values; expand/adjust tests around the new behaviors.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| rpc/jsonrpc/daemon.go | Adds optional testing API entry wiring to the centralized API list and logs a warning when enabled. |
| node/eth/backend.go | Constructs/passes testing_ RPC entry into APIList instead of manually appending. |
| execution/engineapi/testing_api.go | Implements explicit tx list decoding + nonce checks, DB-backed nonce reads, staticTxnProvider, and blockValue/extraData handling tweaks. |
| execution/engineapi/testing_api_test.go | Adds coverage for invalid tx bytes, nonce too high/low, multi-sender tracking, params propagation, and staticTxnProvider. |
| execution/engineapi/engine_types/jsonrpc.go | Makes blockAccessList omit empty values in JSON. |
| execution/builder/parameters.go | Adds CustomTxnProvider to allow overriding the transaction source. |
| execution/builder/builder.go | Uses CustomTxnProvider when provided, otherwise defaults to the builder’s injected provider. |
| cmd/rpcdaemon/main.go | Updates APIList call signature (passes nil testing entry). |
| cmd/mcp/main.go | Updates APIList call signature (passes nil testing entry). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if _, seen := expectedNonce[sender]; !seen { | ||
| stateNonce, err := t.getAccountNonce(ctx, sender.Value()) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| expectedNonce[sender] = stateNonce | ||
| } |
There was a problem hiding this comment.
decodeTxnProvider calls getAccountNonce the first time it sees each sender, and getAccountNonce opens a new temporal DB transaction + SharedDomains every time. For large explicit tx lists with many senders this adds significant overhead. Consider opening the temporal tx/SharedDomains/state.Reader once per BuildBlockV1 call (or once per decodeTxnProvider call) and reading all needed nonces from that single reader, caching them in expectedNonce.
| return nil, &rpc.CustomError{ | ||
| Code: rpc.ErrCodeDefault, | ||
| Message: fmt.Sprintf("nonce too high: address %v, tx: %d state: %d", sender.Value(), got, want), | ||
| } | ||
| } | ||
| if got < want { | ||
| return nil, &rpc.CustomError{ | ||
| Code: rpc.ErrCodeDefault, | ||
| Message: fmt.Sprintf("nonce too low: address %v, tx: %d state: %d", sender.Value(), got, want), | ||
| } |
There was a problem hiding this comment.
Nonce mismatches are treated as rpc.CustomError with ErrCodeDefault (-32000). Since this is a request/parameter validation failure (like the decode/sender recovery paths just above), returning rpc.InvalidParamsError (or at least using -32602) would be more consistent and easier for clients/tests to classify as an input error.
| return nil, &rpc.CustomError{ | |
| Code: rpc.ErrCodeDefault, | |
| Message: fmt.Sprintf("nonce too high: address %v, tx: %d state: %d", sender.Value(), got, want), | |
| } | |
| } | |
| if got < want { | |
| return nil, &rpc.CustomError{ | |
| Code: rpc.ErrCodeDefault, | |
| Message: fmt.Sprintf("nonce too low: address %v, tx: %d state: %d", sender.Value(), got, want), | |
| } | |
| return nil, &rpc.InvalidParamsError{Message: fmt.Sprintf("nonce too high: address %v, tx: %d state: %d", sender.Value(), got, want)} | |
| } | |
| if got < want { | |
| return nil, &rpc.InvalidParamsError{Message: fmt.Sprintf("nonce too low: address %v, tx: %d state: %d", sender.Value(), got, want)} |
This PR fixes the following Hive test failures:
Note:
The test testing_buildBlockV1/build-block-from-mempool currently still fails; this is expected as it will be updated to a speconly type, following the changes in:
execution-apis PR #783.
Changes vs main
Explicit transaction list support in testing_buildBlockV1
In main the endpoint returns an error if a non-empty transaction list is passed. This branch implements the full flow: raw transactions are decoded, the sender is recovered via the chain signer, and nonces are validated sequentially per sender against the current state.
Three modes: null → mempool, [] → empty block, [...] → exact transaction list with strict nonce check.
execution/builder/parameters.go — added CustomTxnProvider txnprovider.TxnProvider: allows injecting an alternative transaction source without exposing the concrete type to the builder.
execution/engineapi/testing_api.go
Tests — full coverage: input validation, busy execution paths, happy path (mempool and explicit list), nonce too high/low, multi-sender nonce tracking, fork-specific parameter propagation (Withdrawals, ParentBeaconBlockRoot) to assembleParams.