Skip to content

feat: add support for testing_ rpc namespace and testing_buildBlockV1#20094

Merged
mattsse merged 30 commits intoparadigmxyz:mainfrom
0xKarl98:testing_buildBlockV1
Dec 11, 2025
Merged

feat: add support for testing_ rpc namespace and testing_buildBlockV1#20094
mattsse merged 30 commits intoparadigmxyz:mainfrom
0xKarl98:testing_buildBlockV1

Conversation

@0xKarl98
Copy link
Contributor

@0xKarl98 0xKarl98 commented Dec 3, 2025

This closes issue #20069 , summerized as below :

  • Implemented the testing_buildBlockV1 RPC namespace (testing-only, default disabled) per spec:
    • Added TestingApi and TestingBuildBlockRequest (camelCase, payloadAttributes+transactions+extraData) in rpc-ap

    • Implemented server-side handler and builder: TestingBlockBuilder trait and EthTestingBlockBuilder execute only the provided raw signed transactions (order preserved), reject blob tx without sidecars, apply payloadAttributes/extraData, and return ExecutionPayloadEnvelopeV4 without touching the canonical chain.

    • Wired conditional registration: hidden CLI flags --http.testing / --ws.testing add testing to module selection, and in Ethereum node we construct EthTestingBlockBuilder and merge TestingApi only when the testing module is explicitly requested. Security note added to API docs

    • Expose a hidden --testing.max-concurrent flag (default 1), and wire testing RPC instantiation to use a semaphore + spawn_blocking so heavy block builds don’t block the async runtime and have bounded concurrency

References :
testing_buildBlockV1.md ethereum/execution-apis#710

cc @mattsse

@github-project-automation github-project-automation bot moved this to Backlog in Reth Tracker Dec 3, 2025
@0xKarl98 0xKarl98 marked this pull request as draft December 4, 2025 02:57
@0xKarl98 0xKarl98 marked this pull request as ready for review December 4, 2025 04:47
@0xKarl98
Copy link
Contributor Author

0xKarl98 commented Dec 4, 2025

@mattsse Should we support testing blob/sidecar transactions here ?

Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

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

this looks pretty good already

left some suggestions

Copy link
Collaborator

Choose a reason for hiding this comment

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

these args we can exclude, we can make it so that --http.api also accepts testing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah we can exclude that and make it more simple

/// Request payload for `testing_buildBlockV1`.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TestingBuildBlockRequest {
Copy link
Collaborator

Choose a reason for hiding this comment

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

let's name this V1

Suggested change
pub struct TestingBuildBlockRequest {
pub struct TestingBuildBlockRequestV1 {

Copy link
Collaborator

Choose a reason for hiding this comment

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

these changes we can all undo because we can instantiate this on demand specifically for eth

similar to flashbots api:

container.modules.merge_if_module_configured(
RethRpcModule::Flashbots,
validation_api.into_rpc(),
)?;

Comment on lines +156 to +159
async fn build_block(
&self,
request: TestingBuildBlockRequest,
) -> RpcResult<ExecutionPayloadEnvelopeV4> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this entire fn logic we need to spawn as blocking, ideally also add a semaphor for this so we can limit how many requests we allow at the same time

Copy link
Contributor Author

@0xKarl98 0xKarl98 Dec 4, 2025

Choose a reason for hiding this comment

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

In terms of the semaphor , which number do you think is appropriate by default ?

I just set the concurrent number to at least 1 and can be overriten if value provided

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think let's go with just 1 by default for now

@github-project-automation github-project-automation bot moved this from Backlog to In Progress in Reth Tracker Dec 4, 2025
@0xKarl98 0xKarl98 requested a review from mattsse December 5, 2025 03:43
Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

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

cool, a few more nits

would be great to get a simple e2e test for this that calls this, see ethereum/node/tests/it for reference

paging @klkvr for suggestions re generics

Comment on lines +337 to +341
let testing_requested = {
let cfg = container.modules.module_config();
cfg.contains_http(&RethRpcModule::Other("testing".to_string())) ||
cfg.contains_ws(&RethRpcModule::Other("testing".to_string())) ||
cfg.contains_ipc(&RethRpcModule::Other("testing".to_string()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe this is just merge_if_configured

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah should use merge_if_module_configured instead

Comment on lines +343 to +351
if testing_requested {
let evm_config: EthEvmConfig<ChainSpec> =
EthEvmConfig::new(testing_chain.clone());
let builder = EthTestingBlockBuilder::new(
testing_provider,
evm_config,
EthereumBuilderConfig::new(),
);
let testing_api = TestingApi::new(builder, testing_max_concurrent).into_rpc();
Copy link
Collaborator

Choose a reason for hiding this comment

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

imo we can always instantiate this and just call merge_if_configured

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah true

Comment on lines +74 to +76
/// Max concurrent `testing_buildBlockV1` requests (hidden, defaults to 1).
#[arg(long = "testing.max-concurrent", default_value_t = 1usize, hide = true)]
pub testing_max_concurrent: usize,
Copy link
Collaborator

Choose a reason for hiding this comment

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

we can make some default assumptions here and dont really need this as a setting imo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahh alright let's go by default

Comment on lines +32 to +38
pub trait TestingBlockBuilder: Send + Sync + std::fmt::Debug + 'static {
/// Build a block according to the testing API request.
async fn build_block(
&self,
request: TestingBuildBlockRequestV1,
) -> RpcResult<ExecutionPayloadEnvelopeV4>;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this api could potentially be useful for other networks as well, so we can make an effort here to make this generic over the types, like N: NodePrimitives perhaps, or at least the actual TestingApi

Comment on lines +278 to +293
ChainSpec = ChainSpec,
Primitives = EthPrimitives,
Payload: EngineTypes<ExecutionData = ExecutionData>,
>,
Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
>,
N::Provider: BlockReaderIdExt<
Block = EthBlock,
Header = <EthBlock as BlockTrait>::Header,
Transaction = TransactionSigned,
Receipt = Receipt,
> + StateProviderFactory
+ ChainSpecProvider<ChainSpec = ChainSpec>
+ Send
+ Sync
+ 'static,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd like to avoid these changes if possible, I think the entire block building logic is already sufficiently generic enough and we can make a few changes to the TestingApi to route the types accordingly

Comment on lines +344 to +345
let evm_config: EthEvmConfig<ChainSpec> =
EthEvmConfig::new(testing_chain.clone());
Copy link
Collaborator

Choose a reason for hiding this comment

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

all of these should be obtainable from the ctx type I believe

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah have reduced the unnessary part

Comment on lines +84 to +86
let handle = Handle::current();
let join_handle =
tokio::task::spawn_blocking(move || handle.block_on(builder.build_block(request)));
Copy link
Collaborator

Choose a reason for hiding this comment

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

we can give this type a Box<dyn TaskExecutor> which can also obtain from the ctx where this type is created

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines +156 to +159
async fn build_block(
&self,
request: TestingBuildBlockRequest,
) -> RpcResult<ExecutionPayloadEnvelopeV4> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think let's go with just 1 by default for now

@0xKarl98
Copy link
Contributor Author

0xKarl98 commented Dec 6, 2025

cool, a few more nits

would be great to get a simple e2e test for this that calls this, see ethereum/node/tests/it for reference

paging @klkvr for suggestions re generics

Yeah before i was thinking to add it after getting feedbacks from you , now will add it

@0xKarl98 0xKarl98 requested a review from mattsse December 6, 2025 12:00
@klkvr klkvr force-pushed the testing_buildBlockV1 branch from 6f1b5d2 to 7262e4a Compare December 11, 2025 00:40
@klkvr klkvr requested a review from rakita as a code owner December 11, 2025 00:40
@mattsse mattsse added C-enhancement New feature or request M-changelog This change should be included in the changelog A-rpc Related to the RPC implementation labels Dec 11, 2025
@mattsse mattsse enabled auto-merge December 11, 2025 08:54
@mattsse mattsse added this pull request to the merge queue Dec 11, 2025
Merged via the queue into paradigmxyz:main with commit e90cfed Dec 11, 2025
45 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Reth Tracker Dec 11, 2025
Vui-Chee added a commit to okx/reth that referenced this pull request Dec 12, 2025
…number

* upstream: (203 commits)
  feat(node-core): make rpc server args customizable (paradigmxyz#20312)
  feat: add `account_history_in_rocksdb` field to `StorageSettings` (paradigmxyz#20282)
  feat(engine): Add BAL stub methods to ExecutionPayload and BlockOrPayload (paradigmxyz#20311)
  docs: fix misleading links (paradigmxyz#20300)
  ci: add more sccache (paradigmxyz#20316)
  feat: bump alloy-evm (paradigmxyz#20314)
  feat: allow larger ws frames on client side (paradigmxyz#20307)
  docs: add architecture diagrams to ExEx documentation (paradigmxyz#20193)
  feat: add semaphore for blocking IO requests (paradigmxyz#20289)
  ci: scale down depot runners (paradigmxyz#20295)
  perf: fetch header directly (paradigmxyz#20294)
  docs(exex): fix DebugApi comment (paradigmxyz#20296)
  feat: add support for testing_ rpc namespace and testing_buildBlockV1 (paradigmxyz#20094)
  chore: update engine_getBlobs metric (paradigmxyz#20290)
  chore(optimism): move predeploy constant to op-alloy (paradigmxyz#20181)
  docs: fix stages order and add missing EraStage (paradigmxyz#20283)
  docs: improve map_add_ons method documentation (paradigmxyz#20248)
  feat: add `transaction_hash_numbers_in_rocksdb` field to `StorageSettings` (paradigmxyz#20209)
  docs: clarify network mode, tx gossip and NAT (paradigmxyz#20247)
  feat: add support for debug_getBadBlock (paradigmxyz#20177)
  ...
@0xKarl98 0xKarl98 deleted the testing_buildBlockV1 branch December 30, 2025 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-rpc Related to the RPC implementation C-enhancement New feature or request M-changelog This change should be included in the changelog

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants