Skip to main content

ethrex_rpc/debug/
execution_witness_by_hash.rs

1use ethrex_common::types::BlockHash;
2use ethrex_common::types::block_execution_witness::RpcExecutionWitness;
3use serde_json::Value;
4use tracing::debug;
5
6use crate::{RpcApiContext, RpcErr, RpcHandler};
7
8pub struct ExecutionWitnessByBlockHashRequest {
9    pub block_hash: BlockHash,
10}
11
12impl RpcHandler for ExecutionWitnessByBlockHashRequest {
13    fn parse(params: &Option<Vec<Value>>) -> Result<Self, RpcErr> {
14        let params = params
15            .as_ref()
16            .ok_or(RpcErr::BadParams("No params provided".to_owned()))?;
17        if params.len() != 1 {
18            return Err(RpcErr::BadParams(format!(
19                "Expected one param and {} were provided",
20                params.len()
21            )));
22        }
23
24        let block_hash: BlockHash = serde_json::from_value(params[0].clone())
25            .map_err(|e| RpcErr::BadParams(format!("Invalid block hash: {e}")))?;
26
27        Ok(ExecutionWitnessByBlockHashRequest { block_hash })
28    }
29
30    async fn handle(&self, context: RpcApiContext) -> Result<Value, RpcErr> {
31        debug!(
32            "Requested execution witness for block hash: {:?}",
33            self.block_hash
34        );
35
36        let block = context
37            .storage
38            .get_block_by_hash(self.block_hash)
39            .await?
40            .ok_or(RpcErr::Internal("Block not found".to_string()))?;
41
42        // Check if we have a cached witness for this block
43        if let Some(json_bytes) = context
44            .storage
45            .get_witness_json_bytes(block.header.number, block.hash())?
46        {
47            return serde_json::from_slice(&json_bytes)
48                .map_err(|e| RpcErr::Internal(format!("Failed to parse cached witness: {e}")));
49        }
50
51        let execution_witness = context
52            .blockchain
53            .generate_witness_for_blocks(&[block])
54            .await
55            .map_err(|e| RpcErr::Internal(format!("Failed to build execution witness {e}")))?;
56
57        let rpc_execution_witness = RpcExecutionWitness::try_from(execution_witness)
58            .map_err(|e| RpcErr::Internal(format!("Failed to create rpc execution witness {e}")))?;
59
60        serde_json::to_value(rpc_execution_witness)
61            .map_err(|error| RpcErr::Internal(error.to_string()))
62    }
63}