alloy_rpc_types_debug/
debug.rs

1//! Types for the `debug` API.
2
3use alloc::{collections::btree_map::BTreeMap, vec::Vec};
4use alloy_primitives::{Bytes, StorageKey, B256};
5use derive_more::{AsMut, AsRef, Deref, DerefMut};
6use serde::{Deserialize, Serialize};
7
8/// Represents the result of a storage slot query.
9#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct StorageResult {
12    /// The storage key
13    pub key: StorageKey,
14    /// The value stored at the slot
15    pub value: B256,
16}
17
18impl From<(StorageKey, B256)> for StorageResult {
19    fn from((key, value): (StorageKey, B256)) -> Self {
20        Self { key, value }
21    }
22}
23
24impl From<StorageResult> for (StorageKey, B256) {
25    fn from(result: StorageResult) -> Self {
26        (result.key, result.value)
27    }
28}
29
30/// Wrapper type for a map of storage slots.
31#[derive(
32    Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, AsRef, Deref, AsMut, DerefMut,
33)]
34#[serde(rename_all = "camelCase")]
35pub struct StorageMap(pub BTreeMap<B256, StorageResult>);
36
37impl From<BTreeMap<B256, StorageResult>> for StorageMap {
38    fn from(map: BTreeMap<B256, StorageResult>) -> Self {
39        Self(map)
40    }
41}
42
43impl From<StorageMap> for BTreeMap<B256, StorageResult> {
44    fn from(map: StorageMap) -> Self {
45        map.0
46    }
47}
48
49/// Represents the result of a storage range query.
50#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub struct StorageRangeResult {
53    /// A map of storage slots
54    pub storage: StorageMap,
55    /// The next key
56    pub next_key: Option<B256>,
57}
58
59impl From<(StorageMap, Option<B256>)> for StorageRangeResult {
60    fn from((storage, next_key): (StorageMap, Option<B256>)) -> Self {
61        Self { storage, next_key }
62    }
63}
64
65impl From<StorageRangeResult> for (StorageMap, Option<B256>) {
66    fn from(result: StorageRangeResult) -> Self {
67        (result.storage, result.next_key)
68    }
69}
70
71/// Represents the execution witness of a block. Contains an optional map of state preimages.
72#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
73pub struct ExecutionWitness {
74    /// List of all hashed trie nodes preimages that were required during the execution of
75    /// the block, including during state root recomputation.
76    pub state: Vec<Bytes>,
77    /// List of all contract codes (created / accessed) preimages that were required during
78    /// the execution of the block, including during state root recomputation.
79    pub codes: Vec<Bytes>,
80    /// List of all hashed account and storage keys (addresses and slots) preimages
81    /// (unhashed account addresses and storage slots, respectively) that were required during
82    /// the execution of the block.
83    pub keys: Vec<Bytes>,
84    /// Block headers required for proving correctness of stateless execution.
85    ///
86    /// This collection stores ancestor(parent) block headers needed to verify:
87    /// - State reads are correct (ie the code and accounts are correct wrt the pre-state root)
88    /// - BLOCKHASH opcode execution results are correct
89    ///
90    /// ## Why this field will be empty in the future
91    ///
92    /// This field is expected to be empty in the future because:
93    /// - EIP-2935 (Prague) will include block hashes directly in the state
94    /// - Verkle/Delayed execution will change the block structure to contain the pre-state root
95    ///   instead of the post-state root.
96    ///
97    /// Once both of these upgrades have been implemented, this field will be empty
98    /// moving forward because the data that this was proving will either be in the
99    /// current block or in the state.
100    ///
101    /// ## State Read Verification
102    ///
103    /// To verify state reads are correct, we need the pre-state root of the current block,
104    /// which is (currently) equal to the post-state root of the previous block. We therefore
105    /// need the previous block's header in order to prove that the state reads are correct.
106    ///
107    /// Note: While the pre-state root is located in the previous block, this field
108    /// will always have one or more items.
109    ///
110    /// ## BLOCKHASH Opcode Verification
111    ///
112    /// The BLOCKHASH opcode returns the block hash for a given block number, but it
113    /// only works for the 256 most recent blocks, not including the current block.
114    /// To verify that a block hash is indeed correct wrt the BLOCKHASH opcode
115    /// and not an arbitrary set of block hashes, we need a contiguous set of
116    /// block headers starting from the current block.
117    ///
118    /// ### Example
119    ///
120    /// Consider a blockchain at block 200, and inside of block 200, a transaction
121    /// calls BLOCKHASH(100):
122    /// - This is valid because block 100 is within the 256-block lookback window
123    /// - To verify this, we need all of the headers from block 100 through block 200
124    /// - These headers form a chain proving the correctness of block 100's hash.
125    ///
126    /// The naive way to construct the headers would be to unconditionally include the last
127    /// 256 block headers. However note, we may not need all 256, like in the example above.
128    pub headers: Vec<Bytes>,
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134    use serde_json::json;
135
136    #[test]
137    fn test_storage_range_result_roundtrip() {
138        let json_input = json!({
139          "storage": {
140            "0x0000000000000000000000000000000000000000000000000000000000000002": {
141              "key": "0x0000000000000000000000000000000000000000000000000000000000000002",
142              "value": "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
143            },
144            "0x0000000000000000000000000000000000000000000000000000000000000003": {
145              "key": "0x0000000000000000000000000000000000000000000000000000000000000003",
146              "value": "0x0000000000000000000000000000000000000000000000000000000000000006"
147            }
148          },
149          "nextKey": "0x0000000000000000000000000000000000000000000000000000000000000004"
150        });
151
152        let parsed: StorageRangeResult = serde_json::from_value(json_input.clone()).unwrap();
153
154        let output = serde_json::to_value(&parsed).unwrap();
155
156        assert_eq!(json_input, output);
157    }
158}