mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-19 03:04:27 -05:00
feat(rpc): add flag to skip invalid transactions in testing_buildBlockV1 (#21094)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@@ -303,6 +303,8 @@ where
|
||||
let eth_config =
|
||||
EthConfigHandler::new(ctx.node.provider().clone(), ctx.node.evm_config().clone());
|
||||
|
||||
let testing_skip_invalid_transactions = ctx.config.rpc.testing_skip_invalid_transactions;
|
||||
|
||||
self.inner
|
||||
.launch_add_ons_with(ctx, move |container| {
|
||||
container.modules.merge_if_module_configured(
|
||||
@@ -316,14 +318,16 @@ where
|
||||
|
||||
// testing_buildBlockV1: only wire when the hidden testing module is explicitly
|
||||
// requested on any transport. Default stays disabled to honor security guidance.
|
||||
let testing_api = TestingApi::new(
|
||||
let mut testing_api = TestingApi::new(
|
||||
container.registry.eth_api().clone(),
|
||||
container.registry.evm_config().clone(),
|
||||
)
|
||||
.into_rpc();
|
||||
);
|
||||
if testing_skip_invalid_transactions {
|
||||
testing_api = testing_api.with_skip_invalid_transactions();
|
||||
}
|
||||
container
|
||||
.modules
|
||||
.merge_if_module_configured(RethRpcModule::Testing, testing_api)?;
|
||||
.merge_if_module_configured(RethRpcModule::Testing, testing_api.into_rpc())?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
|
||||
@@ -640,6 +640,13 @@ pub struct RpcServerArgs {
|
||||
value_parser = parse_duration_from_secs_or_ms,
|
||||
)]
|
||||
pub rpc_send_raw_transaction_sync_timeout: Duration,
|
||||
|
||||
/// Skip invalid transactions in `testing_buildBlockV1` instead of failing.
|
||||
///
|
||||
/// When enabled, transactions that fail execution will be skipped, and all subsequent
|
||||
/// transactions from the same sender will also be skipped.
|
||||
#[arg(long = "testing.skip-invalid-transactions", default_value_t = false)]
|
||||
pub testing_skip_invalid_transactions: bool,
|
||||
}
|
||||
|
||||
impl RpcServerArgs {
|
||||
@@ -852,6 +859,7 @@ impl Default for RpcServerArgs {
|
||||
rpc_state_cache,
|
||||
gas_price_oracle,
|
||||
rpc_send_raw_transaction_sync_timeout,
|
||||
testing_skip_invalid_transactions: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1026,6 +1034,7 @@ mod tests {
|
||||
default_suggested_fee: None,
|
||||
},
|
||||
rpc_send_raw_transaction_sync_timeout: std::time::Duration::from_secs(30),
|
||||
testing_skip_invalid_transactions: true,
|
||||
};
|
||||
|
||||
let parsed_args = CommandParser::<RpcServerArgs>::parse_from([
|
||||
@@ -1114,6 +1123,7 @@ mod tests {
|
||||
"60",
|
||||
"--rpc.send-raw-transaction-sync-timeout",
|
||||
"30s",
|
||||
"--testing.skip-invalid-transactions",
|
||||
])
|
||||
.args;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use alloy_consensus::{Header, Transaction};
|
||||
use alloy_evm::Evm;
|
||||
use alloy_primitives::U256;
|
||||
use alloy_primitives::{map::HashSet, Address, U256};
|
||||
use alloy_rpc_types_engine::ExecutionPayloadEnvelopeV5;
|
||||
use async_trait::async_trait;
|
||||
use jsonrpsee::core::RpcResult;
|
||||
@@ -19,19 +19,31 @@ use reth_rpc_eth_api::{helpers::Call, FromEthApiError};
|
||||
use reth_rpc_eth_types::{utils::recover_raw_transaction, EthApiError};
|
||||
use reth_storage_api::{BlockReader, HeaderProvider};
|
||||
use revm::context::Block;
|
||||
use revm_primitives::map::DefaultHashBuilder;
|
||||
use std::sync::Arc;
|
||||
use tracing::debug;
|
||||
|
||||
/// Testing API handler.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TestingApi<Eth, Evm> {
|
||||
eth_api: Eth,
|
||||
evm_config: Evm,
|
||||
/// If true, skip invalid transactions instead of failing.
|
||||
skip_invalid_transactions: bool,
|
||||
}
|
||||
|
||||
impl<Eth, Evm> TestingApi<Eth, Evm> {
|
||||
/// Create a new testing API handler.
|
||||
pub const fn new(eth_api: Eth, evm_config: Evm) -> Self {
|
||||
Self { eth_api, evm_config }
|
||||
Self { eth_api, evm_config, skip_invalid_transactions: false }
|
||||
}
|
||||
|
||||
/// Enable skipping invalid transactions instead of failing.
|
||||
/// When a transaction fails, all subsequent transactions from the same sender are also
|
||||
/// skipped.
|
||||
pub const fn with_skip_invalid_transactions(mut self) -> Self {
|
||||
self.skip_invalid_transactions = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +58,7 @@ where
|
||||
request: TestingBuildBlockRequestV1,
|
||||
) -> Result<ExecutionPayloadEnvelopeV5, Eth::Error> {
|
||||
let evm_config = self.evm_config.clone();
|
||||
let skip_invalid_transactions = self.skip_invalid_transactions;
|
||||
self.eth_api
|
||||
.spawn_with_state_at_block(request.parent_block_hash, move |eth_api, state| {
|
||||
let state = state.database.0;
|
||||
@@ -79,11 +92,33 @@ where
|
||||
let mut total_fees = U256::ZERO;
|
||||
let base_fee = builder.evm_mut().block().basefee();
|
||||
|
||||
let mut invalid_senders: HashSet<Address, DefaultHashBuilder> = HashSet::default();
|
||||
|
||||
for tx in request.transactions {
|
||||
let tx: Recovered<TxTy<Evm::Primitives>> = recover_raw_transaction(&tx)?;
|
||||
let sender = tx.signer();
|
||||
|
||||
if skip_invalid_transactions && invalid_senders.contains(&sender) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let tip = tx.effective_tip_per_gas(base_fee).unwrap_or_default();
|
||||
let gas_used =
|
||||
builder.execute_transaction(tx).map_err(Eth::Error::from_eth_err)?;
|
||||
let gas_used = match builder.execute_transaction(tx) {
|
||||
Ok(gas_used) => gas_used,
|
||||
Err(err) => {
|
||||
if skip_invalid_transactions {
|
||||
debug!(
|
||||
target: "rpc::testing",
|
||||
?sender,
|
||||
error = ?err,
|
||||
"Skipping invalid transaction"
|
||||
);
|
||||
invalid_senders.insert(sender);
|
||||
continue;
|
||||
}
|
||||
return Err(Eth::Error::from_eth_err(err));
|
||||
}
|
||||
};
|
||||
|
||||
total_fees += U256::from(tip) * U256::from(gas_used);
|
||||
}
|
||||
|
||||
@@ -530,6 +530,11 @@ Gas Price Oracle:
|
||||
|
||||
[default: 30s]
|
||||
|
||||
--testing.skip-invalid-transactions
|
||||
Skip invalid transactions in `testing_buildBlockV1` instead of failing.
|
||||
|
||||
When enabled, transactions that fail execution will be skipped, and all subsequent transactions from the same sender will also be skipped.
|
||||
|
||||
TxPool:
|
||||
--txpool.pending-max-count <PENDING_MAX_COUNT>
|
||||
Max number of transaction in the pending sub-pool
|
||||
|
||||
@@ -530,6 +530,11 @@ Gas Price Oracle:
|
||||
|
||||
[default: 30s]
|
||||
|
||||
--testing.skip-invalid-transactions
|
||||
Skip invalid transactions in `testing_buildBlockV1` instead of failing.
|
||||
|
||||
When enabled, transactions that fail execution will be skipped, and all subsequent transactions from the same sender will also be skipped.
|
||||
|
||||
TxPool:
|
||||
--txpool.pending-max-count <PENDING_MAX_COUNT>
|
||||
Max number of transaction in the pending sub-pool
|
||||
|
||||
Reference in New Issue
Block a user