thegraph_core/
proof_of_indexing.rs

1//! A Proof of Indexing (POI) a cryptographic proof submitted by indexers to demonstrate that they
2//! have accurately indexed a subgraph.
3//!
4//! The POI is essentially a signature over a message digest that is generated during the indexing
5//! of a subgraph from genesis. Each time a subgraph’s state is updated, so does the message digest.
6
7use alloy::primitives::B256;
8
9/// A Proof of Indexing, "POI", is a cryptographic proof submitted by indexers to demonstrate that
10/// they have accurately indexed a subgraph.
11///
12/// ## Generating test data
13///
14/// The `ProofOfIndexing` type implements the [`fake`] crate's [`fake::Dummy`] trait, allowing you
15/// to generate random `ProofOfIndexing` values for testing.
16///
17/// Note that the `fake` feature must be enabled to use this functionality.
18///
19/// See the [`Dummy`] trait impl for usage examples.
20///
21/// [`Dummy`]: #impl-Dummy<Faker>-for-ProofOfIndexing
22#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23#[doc(alias = "poi")]
24pub struct ProofOfIndexing(B256);
25
26impl ProofOfIndexing {
27    /// The "zero" [`ProofOfIndexing`].
28    ///
29    /// This is a constant value that represents the zero POI. It is equivalent to parsing a zeroed
30    /// 32-byte array.
31    pub const ZERO: Self = Self(B256::ZERO);
32
33    /// Creates a new [`ProofOfIndexing`].
34    pub const fn new(bytes: B256) -> Self {
35        Self(bytes)
36    }
37}
38
39impl AsRef<B256> for ProofOfIndexing {
40    fn as_ref(&self) -> &B256 {
41        &self.0
42    }
43}
44
45impl AsRef<[u8]> for ProofOfIndexing {
46    fn as_ref(&self) -> &[u8] {
47        self.0.as_ref()
48    }
49}
50
51impl AsRef<[u8; 32]> for ProofOfIndexing {
52    fn as_ref(&self) -> &[u8; 32] {
53        self.0.as_ref()
54    }
55}
56
57impl std::borrow::Borrow<[u8]> for ProofOfIndexing {
58    fn borrow(&self) -> &[u8] {
59        self.0.borrow()
60    }
61}
62
63impl std::borrow::Borrow<[u8; 32]> for ProofOfIndexing {
64    fn borrow(&self) -> &[u8; 32] {
65        self.0.borrow()
66    }
67}
68
69impl std::ops::Deref for ProofOfIndexing {
70    type Target = B256;
71
72    fn deref(&self) -> &Self::Target {
73        &self.0
74    }
75}
76
77impl From<B256> for ProofOfIndexing {
78    fn from(bytes: B256) -> Self {
79        Self(bytes)
80    }
81}
82
83impl From<[u8; 32]> for ProofOfIndexing {
84    fn from(value: [u8; 32]) -> Self {
85        Self(value.into())
86    }
87}
88
89impl<'a> From<&'a [u8; 32]> for ProofOfIndexing {
90    fn from(value: &'a [u8; 32]) -> Self {
91        Self(value.into())
92    }
93}
94
95impl<'a> TryFrom<&'a [u8]> for ProofOfIndexing {
96    type Error = <B256 as TryFrom<&'a [u8]>>::Error;
97
98    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
99        value.try_into().map(Self)
100    }
101}
102
103impl From<ProofOfIndexing> for B256 {
104    fn from(id: ProofOfIndexing) -> Self {
105        id.0
106    }
107}
108
109impl From<&ProofOfIndexing> for B256 {
110    fn from(id: &ProofOfIndexing) -> Self {
111        id.0
112    }
113}
114
115impl PartialEq<B256> for ProofOfIndexing {
116    fn eq(&self, other: &B256) -> bool {
117        self.0.eq(other)
118    }
119}
120
121impl std::fmt::Display for ProofOfIndexing {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        std::fmt::Display::fmt(&self.0, f)
124    }
125}
126
127impl std::fmt::Debug for ProofOfIndexing {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        write!(f, "ProofOfIndexing({})", self.0)
130    }
131}
132
133#[cfg(feature = "serde")]
134impl<'de> serde::Deserialize<'de> for ProofOfIndexing {
135    fn deserialize<D>(deserializer: D) -> Result<ProofOfIndexing, D::Error>
136    where
137        D: serde::Deserializer<'de>,
138    {
139        serde::Deserialize::deserialize(deserializer).map(Self)
140    }
141}
142
143#[cfg(feature = "serde")]
144impl serde::Serialize for ProofOfIndexing {
145    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
146    where
147        S: serde::Serializer,
148    {
149        self.0.serialize(serializer)
150    }
151}
152
153#[cfg(feature = "fake")]
154/// To use the [`fake`] crate to generate random [`ProofOfIndexing`] values, **the `fake` feature
155/// must be enabled.**
156///
157/// ```rust
158/// # use thegraph_core::ProofOfIndexing;
159/// # use fake::Fake;
160/// let poi = fake::Faker.fake::<ProofOfIndexing>();
161///
162/// println!("ProofOfIndexing: {}", poi);
163/// ```
164impl fake::Dummy<fake::Faker> for ProofOfIndexing {
165    fn dummy_with_rng<R: fake::Rng + ?Sized>(config: &fake::Faker, rng: &mut R) -> Self {
166        let bytes = <[u8; 32]>::dummy_with_rng(config, rng);
167        Self(B256::new(bytes))
168    }
169}
170
171/// Converts a sequence of string literals containing hex-encoded data into a new
172/// [`ProofOfIndexing`] at compile time.
173///
174/// To create an `ProofOfIndexing` from a string literal (no `0x` prefix) at compile time:
175///
176/// ```rust
177/// use thegraph_core::{proof_of_indexing, ProofOfIndexing};
178///
179/// const PROOF_OF_INDEXING: ProofOfIndexing =
180///     proof_of_indexing!("bb31abb3bb85428d894fb4b3cee8a0889bbe8585939b70910bbdda31b30d2240");
181/// ```
182///
183/// If no argument is provided, the macro will create an `ProofOfIndexing` with the zero POI:
184///
185/// ```rust
186/// use thegraph_core::{proof_of_indexing, ProofOfIndexing};
187///
188/// const PROOF_OF_INDEXING: ProofOfIndexing = proof_of_indexing!();
189///
190/// assert_eq!(PROOF_OF_INDEXING, ProofOfIndexing::ZERO);
191/// ```
192#[macro_export]
193#[doc(hidden)]
194macro_rules! __proof_of_indexing {
195    () => {
196        $crate::ProofOfIndexing::ZERO
197    };
198    ($id:tt) => {
199        $crate::ProofOfIndexing::new($crate::alloy::primitives::b256!($id))
200    };
201}