mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(rpc): add replay transaction (#2107)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
This commit is contained in:
@ -161,6 +161,10 @@ where
|
|||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
TraceApiClient::trace_call_many(client, vec![], None).await.err().unwrap();
|
TraceApiClient::trace_call_many(client, vec![], None).await.err().unwrap();
|
||||||
|
TraceApiClient::replay_transaction(client, H256::default(), HashSet::default())
|
||||||
|
.await
|
||||||
|
.err()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(is_unimplemented(
|
assert!(is_unimplemented(
|
||||||
TraceApiClient::replay_block_transactions(client, block_id, HashSet::default())
|
TraceApiClient::replay_block_transactions(client, block_id, HashSet::default())
|
||||||
@ -168,12 +172,6 @@ where
|
|||||||
.err()
|
.err()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
));
|
));
|
||||||
assert!(is_unimplemented(
|
|
||||||
TraceApiClient::replay_transaction(client, H256::default(), HashSet::default())
|
|
||||||
.await
|
|
||||||
.err()
|
|
||||||
.unwrap()
|
|
||||||
));
|
|
||||||
assert!(is_unimplemented(TraceApiClient::trace_block(client, block_id).await.err().unwrap()));
|
assert!(is_unimplemented(TraceApiClient::trace_block(client, block_id).await.err().unwrap()));
|
||||||
assert!(is_unimplemented(
|
assert!(is_unimplemented(
|
||||||
TraceApiClient::trace_filter(client, trace_filter).await.err().unwrap()
|
TraceApiClient::trace_filter(client, trace_filter).await.err().unwrap()
|
||||||
|
|||||||
@ -19,6 +19,7 @@ use reth_primitives::{
|
|||||||
use reth_provider::{BlockProvider, EvmEnvProvider, StateProviderBox, StateProviderFactory};
|
use reth_provider::{BlockProvider, EvmEnvProvider, StateProviderBox, StateProviderFactory};
|
||||||
use reth_revm::{
|
use reth_revm::{
|
||||||
database::{State, SubState},
|
database::{State, SubState},
|
||||||
|
env::tx_env_with_recovered,
|
||||||
tracing::{TracingInspector, TracingInspectorConfig},
|
tracing::{TracingInspector, TracingInspectorConfig},
|
||||||
};
|
};
|
||||||
use reth_rpc_types::{
|
use reth_rpc_types::{
|
||||||
@ -121,6 +122,16 @@ pub trait EthTransactions: Send + Sync {
|
|||||||
) -> EthResult<R>
|
) -> EthResult<R>
|
||||||
where
|
where
|
||||||
F: FnOnce(TracingInspector, ResultAndState) -> EthResult<R>;
|
F: FnOnce(TracingInspector, ResultAndState) -> EthResult<R>;
|
||||||
|
|
||||||
|
/// Retrieves the transaction if it exists and returns its trace
|
||||||
|
async fn trace_transaction<F, R>(
|
||||||
|
&self,
|
||||||
|
hash: H256,
|
||||||
|
config: TracingInspectorConfig,
|
||||||
|
f: F,
|
||||||
|
) -> EthResult<Option<R>>
|
||||||
|
where
|
||||||
|
F: FnOnce(TransactionInfo, TracingInspector, ResultAndState) -> EthResult<R> + Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -376,6 +387,29 @@ where
|
|||||||
f(inspector, res)
|
f(inspector, res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn trace_transaction<F, R>(
|
||||||
|
&self,
|
||||||
|
hash: H256,
|
||||||
|
config: TracingInspectorConfig,
|
||||||
|
f: F,
|
||||||
|
) -> EthResult<Option<R>>
|
||||||
|
where
|
||||||
|
F: FnOnce(TransactionInfo, TracingInspector, ResultAndState) -> EthResult<R> + Send,
|
||||||
|
{
|
||||||
|
let (transaction, at) = match self.transaction_by_hash_at(hash).await? {
|
||||||
|
None => return Ok(None),
|
||||||
|
Some(res) => res,
|
||||||
|
};
|
||||||
|
|
||||||
|
let (cfg, block, at) = self.evm_env_at(at).await?;
|
||||||
|
let (tx, tx_info) = transaction.split();
|
||||||
|
let tx = tx_env_with_recovered(&tx);
|
||||||
|
let env = Env { cfg, block, tx };
|
||||||
|
|
||||||
|
// execute the trace
|
||||||
|
self.trace_at(env, config, at, move |insp, res| f(tx_info, insp, res)).map(Some)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === impl EthApi ===
|
// === impl EthApi ===
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
eth::{
|
eth::{
|
||||||
cache::EthStateCache,
|
cache::EthStateCache,
|
||||||
error::EthResult,
|
error::{EthApiError, EthResult},
|
||||||
revm_utils::{inspect, prepare_call_env},
|
revm_utils::{inspect, prepare_call_env},
|
||||||
utils::recover_raw_transaction,
|
utils::recover_raw_transaction,
|
||||||
EthTransactions,
|
EthTransactions,
|
||||||
@ -147,6 +147,24 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replays a transaction, returning the traces.
|
||||||
|
pub async fn replay_transaction(
|
||||||
|
&self,
|
||||||
|
hash: H256,
|
||||||
|
trace_types: HashSet<TraceType>,
|
||||||
|
) -> EthResult<TraceResults> {
|
||||||
|
let config = tracing_config(&trace_types);
|
||||||
|
self.eth_api
|
||||||
|
.trace_transaction(hash, config, |_, inspector, res| {
|
||||||
|
let trace_res =
|
||||||
|
inspector.into_parity_builder().into_trace_results(res.result, &trace_types);
|
||||||
|
Ok(trace_res)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.transpose()
|
||||||
|
.ok_or_else(|| EthApiError::TransactionNotFound)?
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns transaction trace with the given address.
|
/// Returns transaction trace with the given address.
|
||||||
pub async fn trace_get(
|
pub async fn trace_get(
|
||||||
&self,
|
&self,
|
||||||
@ -172,22 +190,17 @@ where
|
|||||||
) -> EthResult<Option<Vec<LocalizedTransactionTrace>>> {
|
) -> EthResult<Option<Vec<LocalizedTransactionTrace>>> {
|
||||||
let _permit = self.acquire_trace_permit().await;
|
let _permit = self.acquire_trace_permit().await;
|
||||||
|
|
||||||
let (transaction, at) = match self.eth_api.transaction_by_hash_at(hash).await? {
|
self.eth_api
|
||||||
None => return Ok(None),
|
.trace_transaction(
|
||||||
Some(res) => res,
|
hash,
|
||||||
};
|
TracingInspectorConfig::default_parity(),
|
||||||
|
|tx_info, inspector, _| {
|
||||||
let (cfg, block, at) = self.eth_api.evm_env_at(at).await?;
|
let traces =
|
||||||
|
inspector.into_parity_builder().into_localized_transaction_traces(tx_info);
|
||||||
let (tx, tx_info) = transaction.split();
|
Ok(traces)
|
||||||
let tx = tx_env_with_recovered(&tx);
|
},
|
||||||
let env = Env { cfg, block, tx };
|
)
|
||||||
|
.await
|
||||||
// execute the trace
|
|
||||||
self.eth_api.trace_at(env, TracingInspectorConfig::default_parity(), at, |inspector, _| {
|
|
||||||
let traces = inspector.into_parity_builder().into_localized_transaction_traces(tx_info);
|
|
||||||
Ok(Some(traces))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,10 +253,10 @@ where
|
|||||||
/// Handler for `trace_replayTransaction`
|
/// Handler for `trace_replayTransaction`
|
||||||
async fn replay_transaction(
|
async fn replay_transaction(
|
||||||
&self,
|
&self,
|
||||||
_transaction: H256,
|
transaction: H256,
|
||||||
_trace_types: HashSet<TraceType>,
|
trace_types: HashSet<TraceType>,
|
||||||
) -> Result<TraceResults> {
|
) -> Result<TraceResults> {
|
||||||
Err(internal_rpc_err("unimplemented"))
|
Ok(TraceApi::replay_transaction(self, transaction, trace_types).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handler for `trace_block`
|
/// Handler for `trace_block`
|
||||||
|
|||||||
Reference in New Issue
Block a user