Skip to content

Commit

Permalink
Add tracing rpc to rpc-api
Browse files Browse the repository at this point in the history
  • Loading branch information
pgherveou committed Jan 13, 2025
1 parent 2c8d27d commit 62597ca
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 0 deletions.
34 changes: 34 additions & 0 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3301,6 +3301,40 @@ impl_runtime_apis! {
key
)
}

fn trace_tx(
block: Block,
tx_index: u32,
) -> Result<pallet_revive::evm::Traces, sp_runtime::DispatchError> {
let mut t = pallet_revive::debug::Tracer::new_call_tracer(true);
Executive::initialize_block(block.header());

for (index, ext) in block.extrinsics().into_iter().enumerate() {
if index as u32 == tx_index {
pallet_revive::using_tracer(&mut t, || {
let _ = Executive::apply_extrinsic(ext.clone());
});
break;
} else {
let _ = Executive::apply_extrinsic(ext.clone());
}
}
Ok(t.traces())
}

fn trace_block(
block: Block,
) -> Result<pallet_revive::evm::Traces, sp_runtime::DispatchError> {
let mut t = pallet_revive::debug::Tracer::new_call_tracer(true);
pallet_revive::using_tracer(&mut t, || {
Executive::initialize_block(block.header());

for ext in block.extrinsics().into_iter() {
let _ = Executive::apply_extrinsic(ext.clone());
}
});
Ok(t.traces())
}
}

impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
Expand Down
7 changes: 7 additions & 0 deletions substrate/client/rpc-api/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ pub trait StateApi<Hash> {
#[method(name = "state_call", aliases = ["state_callAt"], blocking)]
fn call(&self, name: String, bytes: Bytes, hash: Option<Hash>) -> Result<Bytes, Error>;

/// Debug a method from the runtime API.
/// The method will be called at the block's parent state.
/// and passed the block to be replayed, followed by the decoded `bytes`
/// arguments.
#[method(name = "state_debugBlock", blocking, with_extensions)]
fn debug_block(&self, name: String, block: Hash, bytes: Bytes) -> Result<Bytes, Error>;

/// Returns the keys with prefix, leave empty to get all the keys.
#[method(name = "state_getKeys", blocking)]
#[deprecated(since = "2.0.0", note = "Please use `getKeysPaged` with proper paging support")]
Expand Down
20 changes: 20 additions & 0 deletions substrate/client/rpc/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ where
call_data: Bytes,
) -> Result<Bytes, Error>;

/// Call the runtime method at the block's parent state.
/// and pass the block to be replayed, followed by the call data.
fn debug_block(
&self,
method: String,
block: Block::Hash,
extra_call_data: Bytes,
) -> Result<Bytes, Error>;

/// Returns the keys with prefix, leave empty to get all the keys.
fn storage_keys(
&self,
Expand Down Expand Up @@ -209,6 +218,17 @@ where
self.backend.call(block, method, data).map_err(Into::into)
}

fn debug_block(
&self,
ext: &Extensions,
method: String,
block: Block::Hash,
data: Bytes,
) -> Result<Bytes, Error> {
check_if_safe(ext)?;
self.backend.debug_block(method, block, data).map_err(Into::into)
}

fn storage_keys(
&self,
key_prefix: StorageKey,
Expand Down
33 changes: 33 additions & 0 deletions substrate/client/rpc/src/state/state_full.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,39 @@ where
.map_err(client_err)
}

fn debug_block(
&self,
method: String,
block: Block::Hash,
extra_call_data: Bytes,
) -> std::result::Result<Bytes, Error> {
use sp_runtime::traits::Header;
let header = self
.client
.header(block)
.map_err(|err| Error::Client(Box::new(err)))?
.ok_or_else(|| Error::Client("Block hash not found".into()))?;

let parent_hash = header.parent_hash().clone();
let extrinsics = self
.client
.block_body(block)
.map_err(|err| Error::Client(Box::new(err)))?
.ok_or_else(|| Error::Client("Block hash not found".into()))?;

let call_data = Block::new(header, extrinsics)
.encode()
.into_iter()
.chain(extra_call_data.0.into_iter())
.collect::<Vec<u8>>();

self.client
.executor()
.call(parent_hash, &method, &call_data, CallContext::Offchain)
.map(Into::into)
.map_err(client_err)
}

// TODO: This is horribly broken; either remove it, or make it streaming.
fn storage_keys(
&self,
Expand Down
15 changes: 15 additions & 0 deletions substrate/frame/revive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1569,5 +1569,20 @@ sp_api::decl_runtime_apis! {
address: H160,
key: [u8; 32],
) -> GetStorageResult;

/// Replay the block with the given hash.
/// This is intended to called through `state_debugBlock` RPC. Using [`using_tracer`]
/// function to record traces.
fn trace_block(
block: Block,
) -> Result<Traces, sp_runtime::DispatchError>;

/// Replay the block with the given hash.
/// This is intended to called through `state_debugBlock` RPC. Using [`using_tracer`]
/// function to record trace for the specified transaction index in the block.
fn trace_tx(
block: Block,
tx_index: u32,
) -> Result<Traces, sp_runtime::DispatchError>;
}
}

0 comments on commit 62597ca

Please sign in to comment.