Skip to main content

reth_rpc_eth_types/
capabilities.rs

1//! Types for `eth_capabilities`.
2
3use alloy_primitives::{B256, U64};
4use serde::{Deserialize, Serialize};
5
6/// Effective routing capabilities for the `eth` namespace.
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "camelCase")]
9pub struct EthCapabilities {
10    /// Current chain head.
11    pub head: EthCapabilitiesHead,
12    /// Account and storage state availability.
13    pub state: EthCapabilitiesResource,
14    /// Transaction lookup availability.
15    pub tx: EthCapabilitiesResource,
16    /// Log query availability.
17    pub logs: EthCapabilitiesResource,
18    /// Receipt availability.
19    pub receipts: EthCapabilitiesResource,
20    /// Block header and body availability.
21    pub blocks: EthCapabilitiesResource,
22    /// State proof availability.
23    #[serde(rename = "stateproofs")]
24    pub state_proofs: EthCapabilitiesResource,
25}
26
27/// Current head block.
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct EthCapabilitiesHead {
31    /// Head block number.
32    #[serde(with = "alloy_serde::quantity")]
33    pub number: u64,
34    /// Head block hash.
35    pub hash: B256,
36}
37
38/// Effective capability for one resource.
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(rename_all = "camelCase")]
41pub struct EthCapabilitiesResource {
42    /// Whether this resource is unavailable.
43    pub disabled: bool,
44    /// Oldest block expected to be served correctly.
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub oldest_block: Option<U64>,
47    /// Deletion strategy, if the resource is pruned by a sliding window.
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub delete_strategy: Option<EthCapabilitiesDeleteStrategy>,
50}
51
52impl EthCapabilitiesResource {
53    /// Creates an enabled resource available from the given oldest block.
54    pub fn available_from(oldest_block: u64) -> Self {
55        Self { disabled: false, oldest_block: Some(U64::from(oldest_block)), delete_strategy: None }
56    }
57
58    /// Creates an enabled resource with a sliding window deletion strategy.
59    pub fn window(oldest_block: u64, retention_blocks: u64) -> Self {
60        Self {
61            disabled: false,
62            oldest_block: Some(U64::from(oldest_block)),
63            delete_strategy: Some(EthCapabilitiesDeleteStrategy {
64                strategy_type: EthCapabilitiesDeleteStrategyKind::Window,
65                retention_blocks,
66            }),
67        }
68    }
69
70    /// Creates a disabled resource.
71    pub const fn disabled() -> Self {
72        Self { disabled: true, oldest_block: None, delete_strategy: None }
73    }
74}
75
76/// Deletion strategy for a resource.
77#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78#[serde(rename_all = "camelCase")]
79pub struct EthCapabilitiesDeleteStrategy {
80    /// Strategy type.
81    #[serde(rename = "type")]
82    pub strategy_type: EthCapabilitiesDeleteStrategyKind,
83    /// Number of blocks retained by the sliding window.
84    #[serde(with = "alloy_serde::quantity")]
85    pub retention_blocks: u64,
86}
87
88/// Deletion strategy kind.
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub enum EthCapabilitiesDeleteStrategyKind {
92    /// Sliding window deletion.
93    #[serde(rename = "window")]
94    Window,
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use alloy_primitives::B256;
101    use serde_json::json;
102
103    #[test]
104    fn serializes_capabilities_schema_shape() {
105        let capabilities = EthCapabilities {
106            head: EthCapabilitiesHead { number: 1, hash: B256::ZERO },
107            state: EthCapabilitiesResource::window(10, 90),
108            tx: EthCapabilitiesResource::available_from(0),
109            logs: EthCapabilitiesResource::available_from(0),
110            receipts: EthCapabilitiesResource::available_from(0),
111            blocks: EthCapabilitiesResource::available_from(0),
112            state_proofs: EthCapabilitiesResource::disabled(),
113        };
114
115        let value = serde_json::to_value(capabilities).unwrap();
116
117        assert_eq!(
118            value,
119            json!({
120                "head": {
121                    "number": "0x1",
122                    "hash": B256::ZERO,
123                },
124                "state": {
125                    "disabled": false,
126                    "oldestBlock": "0xa",
127                    "deleteStrategy": {
128                        "type": "window",
129                        "retentionBlocks": "0x5a",
130                    },
131                },
132                "tx": {
133                    "disabled": false,
134                    "oldestBlock": "0x0",
135                },
136                "logs": {
137                    "disabled": false,
138                    "oldestBlock": "0x0",
139                },
140                "receipts": {
141                    "disabled": false,
142                    "oldestBlock": "0x0",
143                },
144                "blocks": {
145                    "disabled": false,
146                    "oldestBlock": "0x0",
147                },
148                "stateproofs": {
149                    "disabled": true,
150                },
151            })
152        );
153    }
154}