cfx_rpc_builder/
module.rs

1// Copyright 2023-2024 Paradigm.xyz
2// This file is part of reth.
3// Reth is a modular, contributor-friendly and blazing-fast implementation of
4// the Ethereum protocol
5
6// Permission is hereby granted, free of charge, to any
7// person obtaining a copy of this software and associated
8// documentation files (the "Software"), to deal in the
9// Software without restriction, including without
10// limitation the rights to use, copy, modify, merge,
11// publish, distribute, sublicense, and/or sell copies of
12// the Software, and to permit persons to whom the Software
13// is furnished to do so, subject to the following
14// conditions:
15
16// The above copyright notice and this permission notice
17// shall be included in all copies or substantial portions
18// of the Software.
19
20// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
21// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
22// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
23// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
24// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
27// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28// DEALINGS IN THE SOFTWARE.
29use std::{collections::HashSet, fmt, str::FromStr};
30
31use serde::{Deserialize, Serialize, Serializer};
32use strum::{
33    AsRefStr, EnumIter, IntoStaticStr, ParseError, VariantArray, VariantNames,
34};
35
36/// Describes the modules that should be installed.
37#[derive(Debug, Default, Clone, Eq, PartialEq)]
38pub enum RpcModuleSelection {
39    /// Use _all_ available modules.
40    All,
41    /// The default modules `eth`, `net`, `web3`
42    #[default]
43    Standard,
44    /// eth, pubsub, net, web3, parity, trace
45    Evm,
46    /// Only use the configured modules.
47    Selection(HashSet<EthRpcModule>),
48}
49
50impl RpcModuleSelection {
51    pub const EVM_MODULES: [EthRpcModule; 6] = [
52        EthRpcModule::Eth,
53        EthRpcModule::PubSub,
54        EthRpcModule::Net,
55        EthRpcModule::Web3,
56        EthRpcModule::Parity,
57        EthRpcModule::Trace,
58    ];
59    /// The standard modules to instantiate by default `eth`, `net`, `web3`
60    pub const STANDARD_MODULES: [EthRpcModule; 3] =
61        [EthRpcModule::Eth, EthRpcModule::Net, EthRpcModule::Web3];
62
63    /// Returns a selection of [`EthRpcModule`] with all
64    /// [`EthRpcModule::all_variants`].
65    pub fn all_modules() -> HashSet<EthRpcModule> {
66        EthRpcModule::modules().into_iter().collect()
67    }
68
69    /// Returns the [`RpcModuleSelection::STANDARD_MODULES`] as a selection.
70    pub fn standard_modules() -> HashSet<EthRpcModule> {
71        HashSet::from(Self::STANDARD_MODULES)
72    }
73
74    pub fn evm_modules() -> HashSet<EthRpcModule> {
75        HashSet::from(Self::EVM_MODULES)
76    }
77
78    /// All modules that are available by default on IPC.
79    ///
80    /// By default all modules are available on IPC.
81    pub fn default_ipc_modules() -> HashSet<EthRpcModule> {
82        Self::all_modules()
83    }
84
85    /// Creates a new _unique_ [`RpcModuleSelection::Selection`] from the given
86    /// items.
87    ///
88    /// # Note
89    ///
90    /// This will dedupe the selection and remove duplicates while preserving
91    /// the order.
92    pub fn try_from_selection<I, T>(selection: I) -> Result<Self, T::Error>
93    where
94        I: IntoIterator<Item = T>,
95        T: TryInto<EthRpcModule>,
96    {
97        selection.into_iter().map(TryInto::try_into).collect()
98    }
99
100    /// Returns the number of modules in the selection
101    pub fn len(&self) -> usize {
102        match self {
103            Self::All => EthRpcModule::variant_count(),
104            Self::Standard => Self::STANDARD_MODULES.len(),
105            Self::Evm => Self::EVM_MODULES.len(),
106            Self::Selection(s) => s.len(),
107        }
108    }
109
110    /// Returns true if no selection is configured
111    pub fn is_empty(&self) -> bool {
112        match self {
113            Self::Selection(sel) => sel.is_empty(),
114            _ => false,
115        }
116    }
117
118    /// Returns an iterator over all configured [`EthRpcModule`]
119    pub fn iter_selection(
120        &self,
121    ) -> Box<dyn Iterator<Item = EthRpcModule> + '_> {
122        match self {
123            Self::All => Box::new(EthRpcModule::modules().into_iter()),
124            Self::Standard => Box::new(Self::STANDARD_MODULES.iter().copied()),
125            Self::Evm => Box::new(Self::EVM_MODULES.iter().copied()),
126            Self::Selection(s) => Box::new(s.iter().copied()),
127        }
128    }
129
130    /// Clones the set of configured [`EthRpcModule`].
131    pub fn to_selection(&self) -> HashSet<EthRpcModule> {
132        match self {
133            Self::All => Self::all_modules(),
134            Self::Standard => Self::standard_modules(),
135            Self::Evm => Self::evm_modules(),
136            Self::Selection(s) => s.clone(),
137        }
138    }
139
140    /// Converts the selection into a [`HashSet`].
141    pub fn into_selection(self) -> HashSet<EthRpcModule> {
142        match self {
143            Self::All => Self::all_modules(),
144            Self::Standard => Self::standard_modules(),
145            Self::Evm => Self::evm_modules(),
146            Self::Selection(s) => s,
147        }
148    }
149
150    /// Returns true if both selections are identical.
151    pub fn are_identical(http: Option<&Self>, ws: Option<&Self>) -> bool {
152        match (http, ws) {
153            // Shortcut for common case to avoid iterating later
154            (Some(Self::All), Some(other)) | (Some(other), Some(Self::All)) => {
155                other.len() == EthRpcModule::variant_count()
156            }
157
158            // If either side is disabled, then the other must be empty
159            (Some(some), None) | (None, Some(some)) => some.is_empty(),
160
161            (Some(http), Some(ws)) => http.to_selection() == ws.to_selection(),
162            (None, None) => true,
163        }
164    }
165}
166
167impl From<&HashSet<EthRpcModule>> for RpcModuleSelection {
168    fn from(s: &HashSet<EthRpcModule>) -> Self { Self::from(s.clone()) }
169}
170
171impl From<HashSet<EthRpcModule>> for RpcModuleSelection {
172    fn from(s: HashSet<EthRpcModule>) -> Self { Self::Selection(s) }
173}
174
175impl From<&[EthRpcModule]> for RpcModuleSelection {
176    fn from(s: &[EthRpcModule]) -> Self {
177        Self::Selection(s.iter().copied().collect())
178    }
179}
180
181impl From<Vec<EthRpcModule>> for RpcModuleSelection {
182    fn from(s: Vec<EthRpcModule>) -> Self {
183        Self::Selection(s.into_iter().collect())
184    }
185}
186
187impl<const N: usize> From<[EthRpcModule; N]> for RpcModuleSelection {
188    fn from(s: [EthRpcModule; N]) -> Self {
189        Self::Selection(s.iter().copied().collect())
190    }
191}
192
193impl<'a> FromIterator<&'a EthRpcModule> for RpcModuleSelection {
194    fn from_iter<I>(iter: I) -> Self
195    where I: IntoIterator<Item = &'a EthRpcModule> {
196        iter.into_iter().copied().collect()
197    }
198}
199
200impl FromIterator<EthRpcModule> for RpcModuleSelection {
201    fn from_iter<I>(iter: I) -> Self
202    where I: IntoIterator<Item = EthRpcModule> {
203        Self::Selection(iter.into_iter().collect())
204    }
205}
206
207impl FromStr for RpcModuleSelection {
208    type Err = String;
209
210    fn from_str(s: &str) -> Result<Self, Self::Err> {
211        if s.is_empty() {
212            return Ok(Self::Selection(Default::default()));
213        }
214        let mut modules = s.split(',').map(str::trim).peekable();
215        let first = modules
216            .peek()
217            .copied()
218            .ok_or(ParseError::VariantNotFound.to_string())?;
219        match first {
220            "all" | "All" => Ok(Self::All),
221            "none" | "None" => Ok(Self::Selection(Default::default())),
222            "standard" | "Standard" => Ok(Self::Standard),
223            "evm" | "Evm" => Ok(Self::Evm),
224            _ => Self::try_from_selection(modules).map_err(|e| e.to_string()),
225        }
226    }
227}
228
229impl fmt::Display for RpcModuleSelection {
230    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231        write!(
232            f,
233            "[{}]",
234            self.iter_selection()
235                .map(|s| s.to_string())
236                .collect::<Vec<_>>()
237                .join(", ")
238        )
239    }
240}
241
242#[derive(
243    Debug,
244    Clone,
245    Copy,
246    Eq,
247    PartialEq,
248    Hash,
249    AsRefStr,
250    IntoStaticStr,
251    VariantNames,
252    VariantArray,
253    EnumIter,
254    Deserialize,
255)]
256#[serde(rename_all = "snake_case")]
257#[strum(serialize_all = "kebab-case")]
258pub enum EthRpcModule {
259    /// `admin_` module
260    // Admin,
261    /// `debug_` module
262    Debug,
263    /// `eth_` module
264    Eth,
265    /// `net_` module
266    Net,
267    /// `trace_` module
268    Trace,
269    /// `txpool_` module
270    Txpool,
271    /// `web3_` module
272    Web3,
273    /// `rpc_` module
274    Rpc,
275    /// `parity_` module
276    Parity,
277    /// pubsub
278    PubSub,
279}
280
281impl EthRpcModule {
282    /// Returns the number of variants in the enum
283    pub const fn variant_count() -> usize {
284        <Self as VariantArray>::VARIANTS.len()
285    }
286
287    /// Returns all variant names of the enum
288    pub const fn all_variant_names() -> &'static [&'static str] {
289        <Self as VariantNames>::VARIANTS
290    }
291
292    /// Returns all variants of the enum
293    pub const fn all_variants() -> &'static [Self] {
294        <Self as VariantArray>::VARIANTS
295    }
296
297    /// Returns all variants of the enum
298    pub fn modules() -> impl IntoIterator<Item = Self> {
299        use strum::IntoEnumIterator;
300        Self::iter()
301    }
302
303    /// Returns the string representation of the module.
304    #[inline]
305    pub fn as_str(&self) -> &'static str { self.into() }
306}
307
308impl FromStr for EthRpcModule {
309    type Err = ParseError;
310
311    fn from_str(s: &str) -> Result<Self, Self::Err> {
312        Ok(match s {
313            // "admin" => Self::Admin,
314            "debug" | "ethdebug" => Self::Debug,
315            "eth" => Self::Eth,
316            "net" => Self::Net,
317            "trace" => Self::Trace,
318            "txpool" => Self::Txpool,
319            "web3" => Self::Web3,
320            "rpc" => Self::Rpc,
321            "parity" => Self::Parity,
322            "pubsub" | "ethpubsub" => Self::PubSub,
323            _ => return Err(ParseError::VariantNotFound),
324        })
325    }
326}
327
328impl TryFrom<&str> for EthRpcModule {
329    type Error = ParseError;
330
331    fn try_from(s: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
332        FromStr::from_str(s)
333    }
334}
335
336impl fmt::Display for EthRpcModule {
337    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338        f.pad(self.as_ref())
339    }
340}
341
342impl Serialize for EthRpcModule {
343    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
344    where S: Serializer {
345        s.serialize_str(self.as_ref())
346    }
347}