1use alloy_primitives::{B256, U64};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "camelCase")]
9pub struct EthCapabilities {
10 pub head: EthCapabilitiesHead,
12 pub state: EthCapabilitiesResource,
14 pub tx: EthCapabilitiesResource,
16 pub logs: EthCapabilitiesResource,
18 pub receipts: EthCapabilitiesResource,
20 pub blocks: EthCapabilitiesResource,
22 #[serde(rename = "stateproofs")]
24 pub state_proofs: EthCapabilitiesResource,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct EthCapabilitiesHead {
31 #[serde(with = "alloy_serde::quantity")]
33 pub number: u64,
34 pub hash: B256,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(rename_all = "camelCase")]
41pub struct EthCapabilitiesResource {
42 pub disabled: bool,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub oldest_block: Option<U64>,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub delete_strategy: Option<EthCapabilitiesDeleteStrategy>,
50}
51
52impl EthCapabilitiesResource {
53 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 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 pub const fn disabled() -> Self {
72 Self { disabled: true, oldest_block: None, delete_strategy: None }
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78#[serde(rename_all = "camelCase")]
79pub struct EthCapabilitiesDeleteStrategy {
80 #[serde(rename = "type")]
82 pub strategy_type: EthCapabilitiesDeleteStrategyKind,
83 pub retention_blocks: u64,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
89#[serde(rename_all = "camelCase")]
90pub enum EthCapabilitiesDeleteStrategyKind {
91 #[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}