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    pub retention_blocks: u64,
85}
86
87/// Deletion strategy kind.
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
89#[serde(rename_all = "camelCase")]
90pub enum EthCapabilitiesDeleteStrategyKind {
91    /// Sliding window deletion.
92    #[serde(rename = "window")]
93    Window,
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use alloy_primitives::B256;
100    use serde_json::json;
101
102    #[test]
103    fn serializes_capabilities_schema_shape() {
104        let capabilities = EthCapabilities {
105            head: EthCapabilitiesHead { number: 1, hash: B256::ZERO },
106            state: EthCapabilitiesResource::window(10, 90),
107            tx: EthCapabilitiesResource::available_from(0),
108            logs: EthCapabilitiesResource::available_from(0),
109            receipts: EthCapabilitiesResource::available_from(0),
110            blocks: EthCapabilitiesResource::available_from(0),
111            state_proofs: EthCapabilitiesResource::disabled(),
112        };
113
114        let value = serde_json::to_value(capabilities).unwrap();
115
116        assert_eq!(
117            value,
118            json!({
119                "head": {
120                    "number": "0x1",
121                    "hash": B256::ZERO,
122                },
123                "state": {
124                    "disabled": false,
125                    "oldestBlock": "0xa",
126                    "deleteStrategy": {
127                        "type": "window",
128                        "retentionBlocks": 90,
129                    },
130                },
131                "tx": {
132                    "disabled": false,
133                    "oldestBlock": "0x0",
134                },
135                "logs": {
136                    "disabled": false,
137                    "oldestBlock": "0x0",
138                },
139                "receipts": {
140                    "disabled": false,
141                    "oldestBlock": "0x0",
142                },
143                "blocks": {
144                    "disabled": false,
145                    "oldestBlock": "0x0",
146                },
147                "stateproofs": {
148                    "disabled": true,
149                },
150            })
151        );
152    }
153}