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 #[serde(with = "alloy_serde::quantity")]
85 pub retention_blocks: u64,
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub enum EthCapabilitiesDeleteStrategyKind {
92 #[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}