mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-19 03:04:27 -05:00
feat(rpc): implement movePrecompileToAddress for eth_simulateV1 (#21414)
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -20,8 +20,8 @@ use alloy_rpc_types_eth::{
|
||||
use futures::Future;
|
||||
use reth_errors::{ProviderError, RethError};
|
||||
use reth_evm::{
|
||||
env::BlockEnvironment, ConfigureEvm, Evm, EvmEnvFor, HaltReasonFor, InspectorFor,
|
||||
TransactionEnv, TxEnvFor,
|
||||
env::BlockEnvironment, execute::BlockBuilder, ConfigureEvm, Evm, EvmEnvFor, HaltReasonFor,
|
||||
InspectorFor, TransactionEnv, TxEnvFor,
|
||||
};
|
||||
use reth_node_api::BlockBody;
|
||||
use reth_primitives_traits::Recovered;
|
||||
@@ -135,8 +135,8 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
|
||||
evm_env.block_env.inner_mut(),
|
||||
);
|
||||
}
|
||||
if let Some(state_overrides) = state_overrides {
|
||||
apply_state_overrides(state_overrides, &mut db)
|
||||
if let Some(ref state_overrides) = state_overrides {
|
||||
apply_state_overrides(state_overrides.clone(), &mut db)
|
||||
.map_err(Self::Error::from_eth_err)?;
|
||||
}
|
||||
|
||||
@@ -192,7 +192,16 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
|
||||
let evm = this
|
||||
.evm_config()
|
||||
.evm_with_env_and_inspector(&mut db, evm_env, inspector);
|
||||
let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
|
||||
let mut builder = this.evm_config().create_block_builder(evm, &parent, ctx);
|
||||
|
||||
if let Some(ref state_overrides) = state_overrides {
|
||||
simulate::apply_precompile_overrides(
|
||||
state_overrides,
|
||||
builder.evm_mut().precompiles_mut(),
|
||||
)
|
||||
.map_err(|e| Self::Error::from_eth_err(EthApiError::other(e)))?;
|
||||
}
|
||||
|
||||
simulate::execute_transactions(
|
||||
builder,
|
||||
calls,
|
||||
@@ -203,7 +212,16 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
|
||||
.map_err(map_err)?
|
||||
} else {
|
||||
let evm = this.evm_config().evm_with_env(&mut db, evm_env);
|
||||
let builder = this.evm_config().create_block_builder(evm, &parent, ctx);
|
||||
let mut builder = this.evm_config().create_block_builder(evm, &parent, ctx);
|
||||
|
||||
if let Some(ref state_overrides) = state_overrides {
|
||||
simulate::apply_precompile_overrides(
|
||||
state_overrides,
|
||||
builder.evm_mut().precompiles_mut(),
|
||||
)
|
||||
.map_err(|e| Self::Error::from_eth_err(EthApiError::other(e)))?;
|
||||
}
|
||||
|
||||
simulate::execute_transactions(
|
||||
builder,
|
||||
calls,
|
||||
|
||||
@@ -6,9 +6,11 @@ use crate::{
|
||||
};
|
||||
use alloy_consensus::{transaction::TxHashRef, BlockHeader, Transaction as _};
|
||||
use alloy_eips::eip2718::WithEncoded;
|
||||
use alloy_evm::precompiles::PrecompilesMap;
|
||||
use alloy_network::TransactionBuilder;
|
||||
use alloy_rpc_types_eth::{
|
||||
simulate::{SimCallResult, SimulateError, SimulatedBlock},
|
||||
state::StateOverride,
|
||||
BlockTransactionsKind,
|
||||
};
|
||||
use jsonrpsee_types::ErrorObject;
|
||||
@@ -79,6 +81,9 @@ pub enum EthSimulateError {
|
||||
/// Multiple `MovePrecompileToAddress` referencing the same address.
|
||||
#[error("Multiple MovePrecompileToAddress referencing the same address")]
|
||||
PrecompileDuplicateAddress,
|
||||
/// Attempted to move a non-precompile address.
|
||||
#[error("account {0} is not a precompile")]
|
||||
NotAPrecompile(Address),
|
||||
}
|
||||
|
||||
impl EthSimulateError {
|
||||
@@ -98,6 +103,7 @@ impl EthSimulateError {
|
||||
Self::SenderNotEOA => -38024,
|
||||
Self::MaxInitCodeSizeExceeded => -38025,
|
||||
Self::GasLimitReached => -38026,
|
||||
Self::NotAPrecompile(_) => -32000,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,6 +114,76 @@ impl ToRpcError for EthSimulateError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies precompile move overrides from state overrides to the EVM's precompiles map.
|
||||
///
|
||||
/// This function processes `movePrecompileToAddress` entries from the state overrides and
|
||||
/// moves precompiles from their original addresses to new addresses. The original address
|
||||
/// is cleared (precompile removed) and the precompile is installed at the destination address.
|
||||
///
|
||||
/// # Validation
|
||||
///
|
||||
/// - The source address must be a precompile (exists in the precompiles map)
|
||||
/// - Moving multiple precompiles to the same destination is allowed
|
||||
/// - Self-references (moving to the same address) are not explicitly forbidden here since that
|
||||
/// would be a no-op
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `state_overrides` - The state overrides containing potential `movePrecompileToAddress` entries
|
||||
/// * `precompiles` - Mutable reference to the EVM's precompiles map
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns `Ok(())` on success, or an `EthSimulateError::NotAPrecompile` if a source address
|
||||
/// is not a precompile.
|
||||
pub fn apply_precompile_overrides(
|
||||
state_overrides: &StateOverride,
|
||||
precompiles: &mut PrecompilesMap,
|
||||
) -> Result<(), EthSimulateError> {
|
||||
use alloy_evm::precompiles::DynPrecompile;
|
||||
|
||||
let moves: Vec<_> = state_overrides
|
||||
.iter()
|
||||
.filter_map(|(source, account_override)| {
|
||||
account_override.move_precompile_to.map(|dest| (*source, dest))
|
||||
})
|
||||
.collect();
|
||||
|
||||
if moves.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for (source, _dest) in &moves {
|
||||
if precompiles.get(source).is_none() {
|
||||
return Err(EthSimulateError::NotAPrecompile(*source));
|
||||
}
|
||||
}
|
||||
|
||||
let mut extracted: Vec<(Address, Address, DynPrecompile)> = Vec::with_capacity(moves.len());
|
||||
|
||||
for (source, dest) in moves {
|
||||
if source == dest {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut found_precompile: Option<DynPrecompile> = None;
|
||||
precompiles.apply_precompile(&source, |existing| {
|
||||
found_precompile = existing;
|
||||
None
|
||||
});
|
||||
|
||||
if let Some(precompile) = found_precompile {
|
||||
extracted.push((source, dest, precompile));
|
||||
}
|
||||
}
|
||||
|
||||
for (_source, dest, precompile) in extracted {
|
||||
precompiles.apply_precompile(&dest, |_| Some(precompile));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Converts all [`TransactionRequest`]s into [`Recovered`] transactions and applies them to the
|
||||
/// given [`BlockExecutor`].
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user