hypersync_net_types/
lib.rs

1//! # HyperSync Network Types
2//!
3//! Core network types and query builders for the HyperSync protocol.
4//!
5//! This crate provides the fundamental types for constructing queries and handling
6//! responses when communicating with HyperSync servers. It supports both JSON
7//! and Cap'n Proto serialization formats for efficient network communication.
8//!
9//! ## Features
10//!
11//! - **Query builder API**: Fluent interface for building complex blockchain queries
12//! - **Type-safe filtering**: Strongly-typed filters for blocks, transactions, logs, and traces
13//! - **Field selection**: Choose exactly which data fields to retrieve
14//! - **Multiple serialization**: Support for JSON and Cap'n Proto protocols
15//! - **Validation**: Built-in query validation and optimization
16//!
17//! ## Key Types
18//!
19//! - [`Query`] - Main query builder for specifying blockchain data to retrieve
20//! - [`BlockFilter`] - Filter blocks by number, hash, or other criteria
21//! - [`TransactionFilter`] - Filter transactions by from/to addresses, value, etc.
22//! - [`LogFilter`] - Filter event logs by contract address, topics, etc.
23//! - [`TraceFilter`] - Filter execution traces by various criteria
24//!
25//! ## Example
26//!
27//! ```
28//! use hypersync_net_types::{Query, LogFilter, LogField};
29//!
30//! // Build a query for ERC20 transfer events
31//! let mut query = Query::new().from_block(19000000);
32//! query.to_block = Some(19001000);
33//! query = query.where_logs(
34//!     LogFilter::all()
35//!         .and_topic0(["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"])?
36//! ).select_log_fields([
37//!     LogField::Address,
38//!     LogField::Topic1,
39//!     LogField::Topic2,
40//!     LogField::Data,
41//! ]);
42//!
43//! println!("Query: {:?}", query);
44//! # Ok::<(), anyhow::Error>(())
45//! ```
46
47// Module declarations
48pub mod block;
49pub mod log;
50pub mod query;
51pub mod request;
52pub mod response;
53pub mod trace;
54pub mod transaction;
55pub mod types;
56
57// Cap'n Proto generated code
58mod __generated__;
59pub use __generated__::hypersync_net_types_capnp;
60
61// Re-export types from modules for backward compatibility and convenience
62pub use block::{BlockField, BlockFilter, BlockSelection};
63pub use log::{LogField, LogFilter, LogSelection};
64pub use query::{FieldSelection, JoinMode, Query};
65pub use response::{ArchiveHeight, ChainId, RollbackGuard};
66pub use trace::{TraceField, TraceFilter, TraceSelection};
67pub use transaction::{
68    AuthorizationSelection, TransactionField, TransactionFilter, TransactionSelection,
69};
70pub use types::Sighash;
71
72use serde::{Deserialize, Serialize};
73
74use crate::types::AnyOf;
75
76#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq)]
77pub struct Selection<T> {
78    /// Filters where matching values should be included in the response
79    /// Default::default() means include everything
80    #[serde(default, flatten)]
81    pub include: T,
82    /// Filters where matching values should be excluded from the response
83    /// None means exclude nothing, Some(Default::default()) means exclude everything
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub exclude: Option<T>,
86}
87
88impl<T> From<Selection<T>> for AnyOf<Selection<T>> {
89    fn from(selection: Selection<T>) -> AnyOf<Selection<T>> {
90        AnyOf::new(selection)
91    }
92}
93
94impl<T> Selection<T> {
95    /// Create a new selection with the given filter.
96    ///
97    /// # Arguments
98    /// * `filter` - The filter to include in the selection
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use hypersync_net_types::{LogSelection, LogFilter};
104    ///
105    /// // Create a selection that includes the filter
106    ///
107    /// let selection = LogSelection::new(
108    ///     LogFilter::all().and_address(["0xdadB0d80178819F2319190D340ce9A924f783711"])?,
109    /// );
110    ///
111    /// Ok::<(), anyhow::Error>(())
112    /// ```
113    pub fn new(filter: T) -> Self {
114        Self {
115            include: filter,
116            exclude: None,
117        }
118    }
119
120    /// Add a filter to exclude from the selection
121    ///
122    /// # Arguments
123    /// * `filter` - The filter to exclude from the selection
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// use hypersync_net_types::{LogSelection, LogFilter};
129    ///
130    /// // Create a selection with a filter that matches any log. (or your own filter)
131    /// let all = LogSelection::new(LogFilter::all());
132    ///
133    /// // Create a selection that excludes only logs from a specific address
134    /// let selection = all.and_not(
135    ///     LogFilter::all().and_address(["0xa0b86a33e6c11c8c0c5c0b5e6adee30d1a234567"])?,
136    /// );
137    ///
138    /// Ok::<(), anyhow::Error>(())
139    /// ```
140    pub fn and_not(mut self, filter: T) -> Self {
141        self.exclude = Some(filter);
142        self
143    }
144
145    /// Combine this selection with another selection using logical OR.
146    ///
147    /// This creates an `AnyOf` type that will match if either this selection
148    /// or the provided selection matches.
149    ///
150    /// # Arguments
151    /// * `selection` - Another selection to combine with this one
152    ///
153    /// # Returns
154    /// An `AnyOf<Self>` that represents the logical OR of both selections
155    ///
156    /// # Examples
157    ///
158    /// ```
159    /// use hypersync_net_types::{LogSelection, LogFilter};
160    ///
161    /// // Create two different selections
162    /// let selection1 = LogSelection::new(LogFilter::all())
163    ///     .and_not(LogFilter::all().and_address(["0xdadB0d80178819F2319190D340ce9A924f783711"])?);
164    /// let selection2 = LogSelection::new(
165    ///     LogFilter::all().and_address(["0xa0b86a33e6c11c8c0c5c0b5e6adee30d1a234567"])?,
166    /// );
167    ///
168    /// // Combine them with OR - matches logs from either address
169    /// let combined = selection1.or(selection2);
170    ///
171    /// Ok::<(), anyhow::Error>(())
172    /// ```
173    pub fn or(self, selection: Self) -> AnyOf<Self> {
174        AnyOf::new(self).or(selection)
175    }
176}
177
178impl<T> From<T> for Selection<T> {
179    fn from(include: T) -> Self {
180        Self {
181            include,
182            exclude: None,
183        }
184    }
185}
186
187pub trait CapnpBuilder<O: capnp::traits::Owned> {
188    fn populate_builder<'a>(&self, builder: &mut O::Builder<'a>) -> Result<(), capnp::Error>;
189}
190
191pub trait CapnpReader<O: capnp::traits::Owned> {
192    fn from_reader<'a>(reader: O::Reader<'a>) -> Result<Self, capnp::Error>
193    where
194        Self: Sized;
195}
196
197impl<O, T> CapnpBuilder<hypersync_net_types_capnp::selection::Owned<O>> for Selection<T>
198where
199    O: capnp::traits::Owned,
200    T: CapnpBuilder<O>,
201{
202    fn populate_builder<'a>(
203        &self,
204        builder: &mut hypersync_net_types_capnp::selection::Builder<'a, O>,
205    ) -> Result<(), capnp::Error> {
206        {
207            let mut include_builder = builder.reborrow().init_include();
208            self.include.populate_builder(&mut include_builder)?;
209        } // include borrow ends
210
211        if let Some(exclude) = &self.exclude {
212            let mut exclude_builder = builder.reborrow().init_exclude();
213            exclude.populate_builder(&mut exclude_builder)?;
214        } // exclude borrow ends
215
216        Ok(())
217    }
218}
219
220impl<O, T> CapnpReader<hypersync_net_types_capnp::selection::Owned<O>> for Selection<T>
221where
222    O: capnp::traits::Owned,
223    T: CapnpReader<O>,
224{
225    fn from_reader<'a>(
226        reader: hypersync_net_types_capnp::selection::Reader<'a, O>,
227    ) -> Result<Self, capnp::Error> {
228        let include = T::from_reader(reader.get_include()?)?;
229        let exclude = if reader.has_exclude() {
230            Some(T::from_reader(reader.get_exclude()?)?)
231        } else {
232            None
233        };
234        Ok(Self { include, exclude })
235    }
236}