Skip to main content

richat_filter/
config.rs

1use {
2    base64::{Engine, engine::general_purpose::STANDARD as base64_engine},
3    richat_proto::geyser::{
4        CommitmentLevel as CommitmentLevelProto, SubscribeRequest,
5        SubscribeRequestAccountsDataSlice, SubscribeRequestFilterAccounts,
6        SubscribeRequestFilterAccountsFilter, SubscribeRequestFilterAccountsFilterLamports,
7        SubscribeRequestFilterAccountsFilterMemcmp, SubscribeRequestFilterBlocks,
8        SubscribeRequestFilterSlots, SubscribeRequestFilterTransactions,
9        subscribe_request_filter_accounts_filter::Filter as AccountsFilterDataOneof,
10        subscribe_request_filter_accounts_filter_lamports::Cmp as AccountsFilterLamports,
11        subscribe_request_filter_accounts_filter_memcmp::Data as AccountsFilterMemcmpOneof,
12    },
13    richat_shared::{
14        config::{
15            deserialize_maybe_signature, deserialize_num_str, deserialize_pubkey_set,
16            deserialize_pubkey_vec,
17        },
18        five8::{pubkey_decode, pubkey_encode, signature_decode, signature_encode},
19    },
20    serde::{
21        Deserialize, Serialize,
22        de::{self, Deserializer},
23    },
24    solana_commitment_config::CommitmentLevel,
25    solana_pubkey::{ParsePubkeyError, Pubkey},
26    solana_signature::{ParseSignatureError, Signature},
27    std::collections::{HashMap, HashSet},
28    thiserror::Error,
29};
30
31pub const MAX_FILTERS: usize = 4;
32pub const MAX_DATA_SIZE: usize = 128;
33pub const MAX_DATA_BASE58_SIZE: usize = 175;
34pub const MAX_DATA_BASE64_SIZE: usize = 172;
35
36#[derive(Debug, Error)]
37pub enum ConfigLimitsError {
38    #[error("Filter name exceeds limit, max {max}")]
39    FilterNameOverflow { max: usize },
40    #[error("Max amount of filters/data_slices reached, only {max} allowed")]
41    FiltersOverflow { max: usize },
42    #[error("Subscribe on full stream with `any` is not allowed, at least one filter required")]
43    EmptyNotAllowed,
44    #[error("Max amount of Pubkeys is reached, only {max} allowed")]
45    PubkeysOverflow { max: usize },
46    #[error("Pubkey {pubkey} in filters is not allowed")]
47    PubkeyNotAllowed { pubkey: Pubkey },
48    #[error("Too much filters provided; max: {max}")]
49    TooMuchFilters { max: usize },
50    #[error("Filter data is too large, max size: {MAX_DATA_SIZE}")]
51    FilterDataOverflow,
52    #[error("Datasize used more than once")]
53    DatasizeDuplicated,
54    #[error("Failed to create filter: data slices out of order")]
55    DataSliceOutOfOrder,
56    #[error("Failed to create filter: data slices overlapped")]
57    DataSliceOverlap,
58    #[error("`include_{0}` is not allowed")]
59    BlocksNotAllowed(&'static str),
60}
61
62#[derive(Debug, Clone, Deserialize, Serialize)]
63#[serde(deny_unknown_fields, default)]
64pub struct ConfigLimits {
65    pub name_max: usize,
66    pub slots: ConfigLimitsSlots,
67    pub accounts: ConfigLimitsAccounts,
68    pub transactions: ConfigLimitsTransactions,
69    pub transactions_status: ConfigLimitsTransactions,
70    pub entries: ConfigLimitsEntries,
71    pub blocks_meta: ConfigLimitsBlocksMeta,
72    pub blocks: ConfigLimitsBlocks,
73}
74
75impl Default for ConfigLimits {
76    fn default() -> Self {
77        Self {
78            name_max: 128,
79            slots: Default::default(),
80            accounts: Default::default(),
81            transactions: Default::default(),
82            transactions_status: Default::default(),
83            entries: Default::default(),
84            blocks_meta: Default::default(),
85            blocks: Default::default(),
86        }
87    }
88}
89
90impl ConfigLimits {
91    const fn check_name_max(len: usize, max: usize) -> Result<(), ConfigLimitsError> {
92        if len <= max {
93            Ok(())
94        } else {
95            Err(ConfigLimitsError::FilterNameOverflow { max })
96        }
97    }
98
99    fn check_names_max<'a>(
100        names: impl Iterator<Item = &'a String>,
101        max: usize,
102    ) -> Result<(), ConfigLimitsError> {
103        for key in names {
104            Self::check_name_max(key.len(), max)?;
105        }
106        Ok(())
107    }
108
109    const fn check_max(len: usize, max: usize) -> Result<(), ConfigLimitsError> {
110        if len <= max {
111            Ok(())
112        } else {
113            Err(ConfigLimitsError::FiltersOverflow { max })
114        }
115    }
116
117    const fn check_any(is_empty: bool, any: bool) -> Result<(), ConfigLimitsError> {
118        if !is_empty || any {
119            Ok(())
120        } else {
121            Err(ConfigLimitsError::EmptyNotAllowed)
122        }
123    }
124
125    const fn check_pubkey_max(len: usize, max: usize) -> Result<(), ConfigLimitsError> {
126        if len <= max {
127            Ok(())
128        } else {
129            Err(ConfigLimitsError::PubkeysOverflow { max })
130        }
131    }
132
133    fn check_pubkey_reject(
134        pubkey: &Pubkey,
135        set: &HashSet<Pubkey>,
136    ) -> Result<(), ConfigLimitsError> {
137        if !set.contains(pubkey) {
138            Ok(())
139        } else {
140            Err(ConfigLimitsError::PubkeyNotAllowed { pubkey: *pubkey })
141        }
142    }
143
144    pub fn check_filter(&self, filter: &ConfigFilter) -> Result<(), ConfigLimitsError> {
145        self.slots.check_filter(self.name_max, &filter.slots)?;
146        self.accounts
147            .check_filter(self.name_max, &filter.accounts, &filter.accounts_data_slice)?;
148        self.transactions
149            .check_filter(self.name_max, &filter.transactions)?;
150        self.transactions_status
151            .check_filter(self.name_max, &filter.transactions_status)?;
152        self.entries.check_filter(self.name_max, &filter.entries)?;
153        self.blocks_meta
154            .check_filter(self.name_max, &filter.blocks_meta)?;
155        self.blocks.check_filter(self.name_max, &filter.blocks)?;
156
157        Ok(())
158    }
159}
160
161#[derive(Debug, Clone, Deserialize, Serialize)]
162#[serde(deny_unknown_fields, default)]
163pub struct ConfigLimitsSlots {
164    #[serde(deserialize_with = "deserialize_num_str")]
165    pub max: usize,
166}
167
168impl Default for ConfigLimitsSlots {
169    fn default() -> Self {
170        Self { max: usize::MAX }
171    }
172}
173
174impl ConfigLimitsSlots {
175    pub fn check_filter(
176        &self,
177        name_max: usize,
178        filters: &HashMap<String, ConfigFilterSlots>,
179    ) -> Result<(), ConfigLimitsError> {
180        ConfigLimits::check_names_max(filters.keys(), name_max)?;
181        ConfigLimits::check_max(filters.len(), self.max)
182    }
183}
184
185#[derive(Debug, Clone, Deserialize, Serialize)]
186#[serde(deny_unknown_fields, default)]
187pub struct ConfigLimitsAccounts {
188    pub max: usize,
189    pub any: bool,
190    pub account_max: usize,
191    #[serde(deserialize_with = "deserialize_pubkey_set")]
192    pub account_reject: HashSet<Pubkey>,
193    pub owner_max: usize,
194    #[serde(deserialize_with = "deserialize_pubkey_set")]
195    pub owner_reject: HashSet<Pubkey>,
196    pub data_slice_max: usize,
197}
198
199impl Default for ConfigLimitsAccounts {
200    fn default() -> Self {
201        Self {
202            max: usize::MAX,
203            any: true,
204            account_max: usize::MAX,
205            account_reject: HashSet::new(),
206            owner_max: usize::MAX,
207            owner_reject: HashSet::new(),
208            data_slice_max: usize::MAX,
209        }
210    }
211}
212
213impl ConfigLimitsAccounts {
214    pub fn check_filter(
215        &self,
216        name_max: usize,
217        filters: &HashMap<String, ConfigFilterAccounts>,
218        data_slices: &[ConfigFilterAccountsDataSlice],
219    ) -> Result<(), ConfigLimitsError> {
220        ConfigLimits::check_names_max(filters.keys(), name_max)?;
221        ConfigLimits::check_max(filters.len(), self.max)?;
222
223        for filter in filters.values() {
224            ConfigLimits::check_any(
225                filter.account.is_empty() && filter.owner.is_empty(),
226                self.any,
227            )?;
228            ConfigLimits::check_pubkey_max(filter.account.len(), self.account_max)?;
229            ConfigLimits::check_pubkey_max(filter.owner.len(), self.owner_max)?;
230
231            for pubkey in filter.account.iter() {
232                ConfigLimits::check_pubkey_reject(pubkey, &self.account_reject)?;
233            }
234            for pubkey in filter.owner.iter() {
235                ConfigLimits::check_pubkey_reject(pubkey, &self.owner_reject)?;
236            }
237
238            if filter.filters.len() > MAX_FILTERS {
239                return Err(ConfigLimitsError::TooMuchFilters { max: MAX_FILTERS });
240            }
241            let mut datasize_defined = false;
242            for filter in filter.filters.iter() {
243                match filter {
244                    ConfigFilterAccountsFilter::Memcmp {
245                        offset: _offset,
246                        data,
247                    } => {
248                        if data.len() > MAX_DATA_SIZE {
249                            return Err(ConfigLimitsError::FilterDataOverflow);
250                        }
251                    }
252                    ConfigFilterAccountsFilter::DataSize(_) => {
253                        if datasize_defined {
254                            return Err(ConfigLimitsError::DatasizeDuplicated);
255                        }
256                        datasize_defined = true;
257                    }
258                    ConfigFilterAccountsFilter::TokenAccountState => {}
259                    ConfigFilterAccountsFilter::Lamports(_) => {}
260                }
261            }
262        }
263
264        ConfigLimits::check_max(data_slices.len(), self.data_slice_max)?;
265        for (i, ds_a) in data_slices.iter().enumerate() {
266            // check order
267            for ds_b in data_slices[i + 1..].iter() {
268                if ds_a.offset > ds_b.offset {
269                    return Err(ConfigLimitsError::DataSliceOutOfOrder);
270                }
271            }
272
273            // check overlap
274            for slice_b in data_slices[0..i].iter() {
275                if ds_a.offset < slice_b.offset + slice_b.length {
276                    return Err(ConfigLimitsError::DataSliceOverlap);
277                }
278            }
279        }
280
281        Ok(())
282    }
283}
284
285#[derive(Debug, Clone, Deserialize, Serialize)]
286#[serde(deny_unknown_fields, default)]
287pub struct ConfigLimitsTransactions {
288    #[serde(deserialize_with = "deserialize_num_str")]
289    pub max: usize,
290    pub any: bool,
291    #[serde(deserialize_with = "deserialize_num_str")]
292    pub account_include_max: usize,
293    #[serde(deserialize_with = "deserialize_pubkey_set")]
294    pub account_include_reject: HashSet<Pubkey>,
295    #[serde(deserialize_with = "deserialize_num_str")]
296    pub account_exclude_max: usize,
297    #[serde(deserialize_with = "deserialize_num_str")]
298    pub account_required_max: usize,
299}
300
301impl Default for ConfigLimitsTransactions {
302    fn default() -> Self {
303        Self {
304            max: usize::MAX,
305            any: true,
306            account_include_max: usize::MAX,
307            account_include_reject: HashSet::new(),
308            account_exclude_max: usize::MAX,
309            account_required_max: usize::MAX,
310        }
311    }
312}
313
314impl ConfigLimitsTransactions {
315    pub fn check_filter(
316        &self,
317        name_max: usize,
318        filters: &HashMap<String, ConfigFilterTransactions>,
319    ) -> Result<(), ConfigLimitsError> {
320        ConfigLimits::check_names_max(filters.keys(), name_max)?;
321        ConfigLimits::check_max(filters.len(), self.max)?;
322
323        for filter in filters.values() {
324            ConfigLimits::check_any(
325                filter.vote.is_none()
326                    && filter.failed.is_none()
327                    && filter.account_include.is_empty()
328                    && filter.account_exclude.is_empty()
329                    && filter.account_required.is_empty(),
330                self.any,
331            )?;
332            ConfigLimits::check_pubkey_max(filter.account_include.len(), self.account_include_max)?;
333            ConfigLimits::check_pubkey_max(filter.account_exclude.len(), self.account_exclude_max)?;
334            ConfigLimits::check_pubkey_max(
335                filter.account_required.len(),
336                self.account_required_max,
337            )?;
338
339            for pubkey in filter.account_include.iter() {
340                ConfigLimits::check_pubkey_reject(pubkey, &self.account_include_reject)?;
341            }
342        }
343
344        Ok(())
345    }
346}
347
348#[derive(Debug, Clone, Deserialize, Serialize)]
349#[serde(deny_unknown_fields, default)]
350pub struct ConfigLimitsEntries {
351    #[serde(deserialize_with = "deserialize_num_str")]
352    pub max: usize,
353}
354
355impl Default for ConfigLimitsEntries {
356    fn default() -> Self {
357        Self { max: usize::MAX }
358    }
359}
360
361impl ConfigLimitsEntries {
362    pub fn check_filter(
363        &self,
364        name_max: usize,
365        filters: &HashSet<String>,
366    ) -> Result<(), ConfigLimitsError> {
367        ConfigLimits::check_names_max(filters.iter(), name_max)?;
368        ConfigLimits::check_max(filters.len(), self.max)
369    }
370}
371
372#[derive(Debug, Clone, Deserialize, Serialize)]
373#[serde(deny_unknown_fields, default)]
374pub struct ConfigLimitsBlocksMeta {
375    #[serde(deserialize_with = "deserialize_num_str")]
376    pub max: usize,
377}
378
379impl Default for ConfigLimitsBlocksMeta {
380    fn default() -> Self {
381        Self { max: usize::MAX }
382    }
383}
384
385impl ConfigLimitsBlocksMeta {
386    pub fn check_filter(
387        &self,
388        name_max: usize,
389        filters: &HashSet<String>,
390    ) -> Result<(), ConfigLimitsError> {
391        ConfigLimits::check_names_max(filters.iter(), name_max)?;
392        ConfigLimits::check_max(filters.len(), self.max)
393    }
394}
395
396#[derive(Debug, Clone, Deserialize, Serialize)]
397#[serde(deny_unknown_fields, default)]
398pub struct ConfigLimitsBlocks {
399    #[serde(deserialize_with = "deserialize_num_str")]
400    pub max: usize,
401    #[serde(deserialize_with = "deserialize_num_str")]
402    pub account_include_max: usize,
403    pub account_include_any: bool,
404    #[serde(deserialize_with = "deserialize_pubkey_set")]
405    pub account_include_reject: HashSet<Pubkey>,
406    pub include_transactions: bool,
407    pub include_accounts: bool,
408    pub include_entries: bool,
409}
410
411impl Default for ConfigLimitsBlocks {
412    fn default() -> Self {
413        Self {
414            max: usize::MAX,
415            account_include_max: usize::MAX,
416            account_include_any: true,
417            account_include_reject: HashSet::new(),
418            include_transactions: true,
419            include_accounts: true,
420            include_entries: true,
421        }
422    }
423}
424
425impl ConfigLimitsBlocks {
426    pub fn check_filter(
427        &self,
428        name_max: usize,
429        filters: &HashMap<String, ConfigFilterBlocks>,
430    ) -> Result<(), ConfigLimitsError> {
431        ConfigLimits::check_names_max(filters.keys(), name_max)?;
432        ConfigLimits::check_max(filters.len(), self.max)?;
433
434        for filter in filters.values() {
435            ConfigLimits::check_any(filter.account_include.is_empty(), self.account_include_any)?;
436            ConfigLimits::check_pubkey_max(filter.account_include.len(), self.account_include_max)?;
437            if !(filter.include_transactions == Some(false) || self.include_transactions) {
438                return Err(ConfigLimitsError::BlocksNotAllowed("transactions"));
439            }
440            if !(matches!(filter.include_accounts, None | Some(false)) || self.include_accounts) {
441                return Err(ConfigLimitsError::BlocksNotAllowed("accounts"));
442            }
443            if !(matches!(filter.include_entries, None | Some(false)) || self.include_accounts) {
444                return Err(ConfigLimitsError::BlocksNotAllowed("entries"));
445            }
446            for pubkey in filter.account_include.iter() {
447                ConfigLimits::check_pubkey_reject(pubkey, &self.account_include_reject)?;
448            }
449        }
450
451        Ok(())
452    }
453}
454
455#[derive(Debug, Error)]
456pub enum ConfigFilterError {
457    #[error(transparent)]
458    Limits(#[from] ConfigLimitsError),
459    #[error("Field `{0}` should be defined")]
460    FieldNotDefined(&'static str),
461    #[error("Token account state value is invalid")]
462    TokenAccountStateInvalid,
463    #[error("Invalid base58 encoding")]
464    InvalidBase58,
465    #[error("Invalid base64 encoding")]
466    InvalidBase64,
467    #[error("Invalid pubkey `{0}`: {1}")]
468    Pubkey(String, ParsePubkeyError),
469    #[error("Invalid signature `{0}`: {1}")]
470    Signature(String, ParseSignatureError),
471    #[error("Unknown commitment level: {0}")]
472    UnknownCommitment(i32),
473}
474
475#[derive(Debug, Clone, Default, Deserialize, Serialize)]
476#[serde(deny_unknown_fields, default)]
477pub struct ConfigFilter {
478    pub slots: HashMap<String, ConfigFilterSlots>,
479    pub accounts: HashMap<String, ConfigFilterAccounts>,
480    pub accounts_data_slice: Vec<ConfigFilterAccountsDataSlice>,
481    pub transactions: HashMap<String, ConfigFilterTransactions>,
482    pub transactions_status: HashMap<String, ConfigFilterTransactions>,
483    pub entries: HashSet<String>,
484    pub blocks_meta: HashSet<String>,
485    pub blocks: HashMap<String, ConfigFilterBlocks>,
486    pub commitment: Option<ConfigFilterCommitment>,
487}
488
489impl ConfigFilter {
490    fn try_conv_map<T, C>(map: HashMap<String, T>) -> Result<HashMap<String, C>, ConfigFilterError>
491    where
492        C: TryFrom<T, Error = ConfigFilterError>,
493    {
494        map.into_iter()
495            .map(|(key, value)| value.try_into().map(|value| (key, value)))
496            .collect::<Result<_, _>>()
497    }
498
499    fn conv_map<C, T>(map: HashMap<String, C>) -> HashMap<String, T>
500    where
501        T: From<C>,
502    {
503        map.into_iter()
504            .map(|(key, value)| (key, value.into()))
505            .collect()
506    }
507
508    fn conv_set<T: Default>(set: HashSet<String>) -> HashMap<String, T> {
509        set.into_iter().map(|key| (key, T::default())).collect()
510    }
511
512    fn parse_vec_pubkeys(pubkeys: Vec<String>) -> Result<Vec<Pubkey>, ConfigFilterError> {
513        pubkeys
514            .into_iter()
515            .map(|pubkey| {
516                pubkey_decode(&pubkey).map_err(|error| ConfigFilterError::Pubkey(pubkey, error))
517            })
518            .collect::<Result<Vec<_>, _>>()
519    }
520
521    fn conv_vec_pubkeys(pubkeys: Vec<Pubkey>) -> Vec<String> {
522        pubkeys
523            .into_iter()
524            .map(|pk| pubkey_encode(&pk.to_bytes()))
525            .collect()
526    }
527}
528
529impl TryFrom<SubscribeRequest> for ConfigFilter {
530    type Error = ConfigFilterError;
531
532    fn try_from(value: SubscribeRequest) -> Result<Self, Self::Error> {
533        Ok(Self {
534            slots: Self::try_conv_map(value.slots)?,
535            accounts: Self::try_conv_map(value.accounts)?,
536            accounts_data_slice: value
537                .accounts_data_slice
538                .into_iter()
539                .map(|ds| ds.try_into())
540                .collect::<Result<_, _>>()?,
541            transactions: Self::try_conv_map(value.transactions)?,
542            transactions_status: Self::try_conv_map(value.transactions_status)?,
543            entries: value.entry.into_keys().collect(),
544            blocks_meta: value.blocks_meta.into_keys().collect(),
545            blocks: Self::try_conv_map(value.blocks)?,
546            commitment: value.commitment.map(|value| value.try_into()).transpose()?,
547        })
548    }
549}
550
551impl From<ConfigFilter> for SubscribeRequest {
552    fn from(value: ConfigFilter) -> Self {
553        SubscribeRequest {
554            slots: ConfigFilter::conv_map(value.slots),
555            accounts: ConfigFilter::conv_map(value.accounts),
556            accounts_data_slice: value
557                .accounts_data_slice
558                .into_iter()
559                .map(|ds| ds.into())
560                .collect(),
561            transactions: ConfigFilter::conv_map(value.transactions),
562            transactions_status: ConfigFilter::conv_map(value.transactions_status),
563            entry: ConfigFilter::conv_set(value.entries),
564            blocks_meta: ConfigFilter::conv_set(value.blocks_meta),
565            blocks: ConfigFilter::conv_map(value.blocks),
566            commitment: value.commitment.map(|c| c.into()),
567            ping: None,
568            from_slot: None,
569        }
570    }
571}
572
573#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize)]
574#[serde(deny_unknown_fields, default)]
575pub struct ConfigFilterSlots {
576    pub filter_by_commitment: Option<bool>,
577    pub interslot_updates: Option<bool>,
578}
579
580impl TryFrom<SubscribeRequestFilterSlots> for ConfigFilterSlots {
581    type Error = ConfigFilterError;
582
583    fn try_from(value: SubscribeRequestFilterSlots) -> Result<Self, Self::Error> {
584        Ok(Self {
585            filter_by_commitment: value.filter_by_commitment,
586            interslot_updates: value.interslot_updates,
587        })
588    }
589}
590
591impl From<ConfigFilterSlots> for SubscribeRequestFilterSlots {
592    fn from(value: ConfigFilterSlots) -> Self {
593        Self {
594            filter_by_commitment: value.filter_by_commitment,
595            interslot_updates: value.interslot_updates,
596        }
597    }
598}
599
600#[derive(Debug, Default, Clone, Deserialize, Serialize)]
601#[serde(deny_unknown_fields, default)]
602pub struct ConfigFilterAccounts {
603    #[serde(deserialize_with = "deserialize_pubkey_vec")]
604    pub account: Vec<Pubkey>,
605    #[serde(deserialize_with = "deserialize_pubkey_vec")]
606    pub owner: Vec<Pubkey>,
607    pub filters: Vec<ConfigFilterAccountsFilter>,
608    pub nonempty_txn_signature: Option<bool>,
609}
610
611impl TryFrom<SubscribeRequestFilterAccounts> for ConfigFilterAccounts {
612    type Error = ConfigFilterError;
613
614    fn try_from(value: SubscribeRequestFilterAccounts) -> Result<Self, Self::Error> {
615        let account = ConfigFilter::parse_vec_pubkeys(value.account)?;
616        let owner = ConfigFilter::parse_vec_pubkeys(value.owner)?;
617
618        if value.filters.len() > MAX_FILTERS {
619            return Err(ConfigLimitsError::TooMuchFilters { max: MAX_FILTERS }.into());
620        }
621
622        let filters = value
623            .filters
624            .into_iter()
625            .map(|filter| filter.try_into())
626            .collect::<Result<Vec<_>, _>>()?;
627
628        Ok(Self {
629            account,
630            owner,
631            filters,
632            nonempty_txn_signature: value.nonempty_txn_signature,
633        })
634    }
635}
636
637impl From<ConfigFilterAccounts> for SubscribeRequestFilterAccounts {
638    fn from(value: ConfigFilterAccounts) -> Self {
639        Self {
640            account: ConfigFilter::conv_vec_pubkeys(value.account),
641            owner: ConfigFilter::conv_vec_pubkeys(value.owner),
642            filters: value.filters.into_iter().map(Into::into).collect(),
643            nonempty_txn_signature: value.nonempty_txn_signature,
644        }
645    }
646}
647
648#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
649#[serde(deny_unknown_fields)]
650pub enum ConfigFilterAccountsFilter {
651    Memcmp { offset: usize, data: Vec<u8> },
652    DataSize(u64),
653    TokenAccountState,
654    Lamports(ConfigFilterAccountsFilterLamports),
655}
656
657impl<'de> Deserialize<'de> for ConfigFilterAccountsFilter {
658    fn deserialize<D>(deserializer: D) -> Result<ConfigFilterAccountsFilter, D::Error>
659    where
660        D: Deserializer<'de>,
661    {
662        #[derive(Debug, Deserialize)]
663        enum ConfigMemcmpData {
664            Str(String),
665            Bytes(Vec<u8>),
666        }
667
668        #[derive(Debug, Deserialize)]
669        enum Config {
670            Memcmp {
671                offset: usize,
672                data: ConfigMemcmpData,
673            },
674            DataSize(u64),
675            TokenAccountState,
676            Lamports(ConfigFilterAccountsFilterLamports),
677        }
678
679        Ok(match Config::deserialize(deserializer)? {
680            Config::Memcmp { offset, data } => {
681                let data = match data {
682                    ConfigMemcmpData::Str(data) => match &data[0..7] {
683                        "base64:" => base64_engine
684                            .decode(&data[7..])
685                            .map_err(de::Error::custom)?,
686                        "base58:" => bs58::decode(&data[7..])
687                            .into_vec()
688                            .map_err(de::Error::custom)?,
689                        _ => data.as_bytes().to_vec(),
690                    },
691                    ConfigMemcmpData::Bytes(data) => data,
692                };
693                Self::Memcmp { offset, data }
694            }
695            Config::DataSize(size) => Self::DataSize(size),
696            Config::TokenAccountState => Self::TokenAccountState,
697            Config::Lamports(value) => Self::Lamports(value),
698        })
699    }
700}
701
702impl TryFrom<SubscribeRequestFilterAccountsFilter> for ConfigFilterAccountsFilter {
703    type Error = ConfigFilterError;
704
705    fn try_from(value: SubscribeRequestFilterAccountsFilter) -> Result<Self, Self::Error> {
706        let value = value
707            .filter
708            .ok_or(ConfigFilterError::FieldNotDefined("filter"))?;
709
710        Ok(match value {
711            AccountsFilterDataOneof::Memcmp(memcmp) => {
712                let value = memcmp
713                    .data
714                    .ok_or(ConfigFilterError::FieldNotDefined("data"))?;
715                let data = match &value {
716                    AccountsFilterMemcmpOneof::Bytes(data) => data.clone(),
717                    AccountsFilterMemcmpOneof::Base58(data) => {
718                        if data.len() > MAX_DATA_BASE58_SIZE {
719                            return Err(ConfigLimitsError::FilterDataOverflow.into());
720                        }
721                        bs58::decode(data)
722                            .into_vec()
723                            .map_err(|_| ConfigFilterError::InvalidBase58)?
724                    }
725                    AccountsFilterMemcmpOneof::Base64(data) => {
726                        if data.len() > MAX_DATA_BASE64_SIZE {
727                            return Err(ConfigLimitsError::FilterDataOverflow.into());
728                        }
729                        base64_engine
730                            .decode(data)
731                            .map_err(|_| ConfigFilterError::InvalidBase64)?
732                    }
733                };
734                if data.len() > MAX_DATA_SIZE {
735                    return Err(ConfigLimitsError::FilterDataOverflow.into());
736                }
737
738                Self::Memcmp {
739                    offset: memcmp.offset as usize,
740                    data,
741                }
742            }
743            AccountsFilterDataOneof::Datasize(size) => Self::DataSize(size),
744            AccountsFilterDataOneof::TokenAccountState(value) => {
745                if !value {
746                    return Err(ConfigFilterError::TokenAccountStateInvalid);
747                }
748                Self::TokenAccountState
749            }
750            AccountsFilterDataOneof::Lamports(lamports) => Self::Lamports(lamports.try_into()?),
751        })
752    }
753}
754
755impl From<ConfigFilterAccountsFilter> for SubscribeRequestFilterAccountsFilter {
756    fn from(value: ConfigFilterAccountsFilter) -> Self {
757        Self {
758            filter: Some(match value {
759                ConfigFilterAccountsFilter::Memcmp { offset, data } => {
760                    AccountsFilterDataOneof::Memcmp(SubscribeRequestFilterAccountsFilterMemcmp {
761                        offset: offset as u64,
762                        data: Some(AccountsFilterMemcmpOneof::Bytes(data)),
763                    })
764                }
765                ConfigFilterAccountsFilter::DataSize(size) => {
766                    AccountsFilterDataOneof::Datasize(size)
767                }
768                ConfigFilterAccountsFilter::TokenAccountState => {
769                    AccountsFilterDataOneof::TokenAccountState(true)
770                }
771                ConfigFilterAccountsFilter::Lamports(value) => {
772                    AccountsFilterDataOneof::Lamports(value.into())
773                }
774            }),
775        }
776    }
777}
778
779#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
780#[serde(deny_unknown_fields)]
781pub enum ConfigFilterAccountsFilterLamports {
782    Eq(u64),
783    Ne(u64),
784    Lt(u64),
785    Gt(u64),
786}
787
788impl TryFrom<SubscribeRequestFilterAccountsFilterLamports> for ConfigFilterAccountsFilterLamports {
789    type Error = ConfigFilterError;
790
791    fn try_from(value: SubscribeRequestFilterAccountsFilterLamports) -> Result<Self, Self::Error> {
792        let value = value.cmp.ok_or(ConfigFilterError::FieldNotDefined("cmp"))?;
793
794        Ok(match value {
795            AccountsFilterLamports::Eq(value) => Self::Eq(value),
796            AccountsFilterLamports::Ne(value) => Self::Ne(value),
797            AccountsFilterLamports::Lt(value) => Self::Lt(value),
798            AccountsFilterLamports::Gt(value) => Self::Gt(value),
799        })
800    }
801}
802
803impl From<ConfigFilterAccountsFilterLamports> for SubscribeRequestFilterAccountsFilterLamports {
804    fn from(value: ConfigFilterAccountsFilterLamports) -> Self {
805        Self {
806            cmp: Some(match value {
807                ConfigFilterAccountsFilterLamports::Eq(value) => AccountsFilterLamports::Eq(value),
808                ConfigFilterAccountsFilterLamports::Ne(value) => AccountsFilterLamports::Ne(value),
809                ConfigFilterAccountsFilterLamports::Lt(value) => AccountsFilterLamports::Lt(value),
810                ConfigFilterAccountsFilterLamports::Gt(value) => AccountsFilterLamports::Gt(value),
811            }),
812        }
813    }
814}
815
816#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
817#[serde(deny_unknown_fields)]
818pub struct ConfigFilterAccountsDataSlice {
819    pub offset: u64,
820    pub length: u64,
821}
822
823impl TryFrom<SubscribeRequestAccountsDataSlice> for ConfigFilterAccountsDataSlice {
824    type Error = ConfigFilterError;
825
826    fn try_from(value: SubscribeRequestAccountsDataSlice) -> Result<Self, Self::Error> {
827        Ok(Self {
828            offset: value.offset,
829            length: value.length,
830        })
831    }
832}
833
834impl From<ConfigFilterAccountsDataSlice> for SubscribeRequestAccountsDataSlice {
835    fn from(value: ConfigFilterAccountsDataSlice) -> Self {
836        Self {
837            offset: value.offset,
838            length: value.length,
839        }
840    }
841}
842
843#[derive(Debug, Default, Clone, Deserialize, Serialize)]
844#[serde(deny_unknown_fields, default)]
845pub struct ConfigFilterTransactions {
846    pub vote: Option<bool>,
847    pub failed: Option<bool>,
848    #[serde(deserialize_with = "deserialize_maybe_signature")]
849    pub signature: Option<Signature>,
850    #[serde(deserialize_with = "deserialize_pubkey_vec")]
851    pub account_include: Vec<Pubkey>,
852    #[serde(deserialize_with = "deserialize_pubkey_vec")]
853    pub account_exclude: Vec<Pubkey>,
854    #[serde(deserialize_with = "deserialize_pubkey_vec")]
855    pub account_required: Vec<Pubkey>,
856}
857
858impl TryFrom<SubscribeRequestFilterTransactions> for ConfigFilterTransactions {
859    type Error = ConfigFilterError;
860
861    fn try_from(value: SubscribeRequestFilterTransactions) -> Result<Self, Self::Error> {
862        Ok(Self {
863            vote: value.vote,
864            failed: value.failed,
865            signature: value
866                .signature
867                .map(|sig| {
868                    signature_decode(&sig).map_err(|error| ConfigFilterError::Signature(sig, error))
869                })
870                .transpose()?,
871            account_include: ConfigFilter::parse_vec_pubkeys(value.account_include)?,
872            account_exclude: ConfigFilter::parse_vec_pubkeys(value.account_exclude)?,
873            account_required: ConfigFilter::parse_vec_pubkeys(value.account_required)?,
874        })
875    }
876}
877
878impl From<ConfigFilterTransactions> for SubscribeRequestFilterTransactions {
879    fn from(value: ConfigFilterTransactions) -> Self {
880        Self {
881            vote: value.vote,
882            failed: value.failed,
883            signature: value.signature.map(|sig| signature_encode(&sig.into())),
884            account_include: ConfigFilter::conv_vec_pubkeys(value.account_include),
885            account_exclude: ConfigFilter::conv_vec_pubkeys(value.account_exclude),
886            account_required: ConfigFilter::conv_vec_pubkeys(value.account_required),
887        }
888    }
889}
890
891#[derive(Debug, Default, Clone, Deserialize, Serialize)]
892#[serde(deny_unknown_fields, default)]
893pub struct ConfigFilterBlocks {
894    #[serde(deserialize_with = "deserialize_pubkey_vec")]
895    pub account_include: Vec<Pubkey>,
896    pub include_transactions: Option<bool>,
897    pub include_accounts: Option<bool>,
898    pub include_entries: Option<bool>,
899}
900
901impl TryFrom<SubscribeRequestFilterBlocks> for ConfigFilterBlocks {
902    type Error = ConfigFilterError;
903
904    fn try_from(value: SubscribeRequestFilterBlocks) -> Result<Self, Self::Error> {
905        Ok(Self {
906            account_include: ConfigFilter::parse_vec_pubkeys(value.account_include)?,
907            include_transactions: value.include_transactions,
908            include_accounts: value.include_accounts,
909            include_entries: value.include_entries,
910        })
911    }
912}
913
914impl From<ConfigFilterBlocks> for SubscribeRequestFilterBlocks {
915    fn from(value: ConfigFilterBlocks) -> Self {
916        Self {
917            account_include: ConfigFilter::conv_vec_pubkeys(value.account_include),
918            include_transactions: value.include_transactions,
919            include_accounts: value.include_accounts,
920            include_entries: value.include_entries,
921        }
922    }
923}
924
925#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
926#[serde(deny_unknown_fields, rename_all = "lowercase")]
927pub enum ConfigFilterCommitment {
928    #[default]
929    Processed,
930    Confirmed,
931    Finalized,
932}
933
934impl TryFrom<i32> for ConfigFilterCommitment {
935    type Error = ConfigFilterError;
936
937    fn try_from(value: i32) -> Result<Self, Self::Error> {
938        CommitmentLevelProto::try_from(value)
939            .map(Into::into)
940            .map_err(|_error| ConfigFilterError::UnknownCommitment(value))
941    }
942}
943
944impl From<CommitmentLevelProto> for ConfigFilterCommitment {
945    fn from(value: CommitmentLevelProto) -> Self {
946        match value {
947            CommitmentLevelProto::Processed => Self::Processed,
948            CommitmentLevelProto::Confirmed => Self::Confirmed,
949            CommitmentLevelProto::Finalized => Self::Finalized,
950        }
951    }
952}
953
954impl From<ConfigFilterCommitment> for i32 {
955    fn from(value: ConfigFilterCommitment) -> Self {
956        (match value {
957            ConfigFilterCommitment::Processed => CommitmentLevelProto::Processed,
958            ConfigFilterCommitment::Confirmed => CommitmentLevelProto::Confirmed,
959            ConfigFilterCommitment::Finalized => CommitmentLevelProto::Finalized,
960        }) as i32
961    }
962}
963
964impl From<ConfigFilterCommitment> for CommitmentLevel {
965    fn from(value: ConfigFilterCommitment) -> Self {
966        match value {
967            ConfigFilterCommitment::Processed => Self::Processed,
968            ConfigFilterCommitment::Confirmed => Self::Confirmed,
969            ConfigFilterCommitment::Finalized => Self::Finalized,
970        }
971    }
972}