thegraph_headers/
graph_attestation.rs1use headers::{Error as HeaderError, HeaderName, HeaderValue};
29use thegraph_core::alloy::primitives::B256;
30pub use thegraph_core::attestation::Attestation;
31
32pub const HEADER_NAME: &str = "graph-attestation";
34
35#[derive(Debug, Clone)]
40pub struct GraphAttestation(pub Attestation);
41
42impl headers::Header for GraphAttestation {
43 fn name() -> &'static HeaderName {
44 static HTTP_HEADER_NAME: HeaderName = HeaderName::from_static(HEADER_NAME);
45 &HTTP_HEADER_NAME
46 }
47
48 fn decode<'i, I>(values: &mut I) -> Result<Self, HeaderError>
49 where
50 Self: Sized,
51 I: Iterator<Item = &'i HeaderValue>,
52 {
53 let value = values.next().ok_or_else(HeaderError::invalid)?;
55 let attestation = serde_json::from_slice::<'_, AttestationSerde>(value.as_bytes())
56 .map_err(|_| HeaderError::invalid())?;
57 Ok(Self(attestation.into()))
58 }
59
60 fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
61 let bytes =
63 serde_json::to_vec(&AttestationSerde::from(&self.0)).expect("header to be valid json");
64 let value = HeaderValue::from_bytes(&bytes).expect("header to be valid utf-8");
65 values.extend(std::iter::once(value));
66 }
67}
68
69#[derive(serde::Serialize, serde::Deserialize)]
70struct AttestationSerde {
71 #[serde(rename = "requestCID")]
72 request_cid: B256,
73 #[serde(rename = "responseCID")]
74 response_cid: B256,
75 #[serde(rename = "subgraphDeploymentID")]
76 deployment: B256,
77 r: B256,
78 s: B256,
79 v: u8,
80}
81
82impl From<AttestationSerde> for Attestation {
83 fn from(value: AttestationSerde) -> Self {
84 Self {
85 request_cid: value.request_cid,
86 response_cid: value.response_cid,
87 deployment: value.deployment,
88 r: value.r,
89 s: value.s,
90 v: value.v,
91 }
92 }
93}
94
95impl From<&Attestation> for AttestationSerde {
96 fn from(value: &Attestation) -> Self {
97 Self {
98 request_cid: value.request_cid,
99 response_cid: value.response_cid,
100 deployment: value.deployment,
101 r: value.r,
102 s: value.s,
103 v: value.v,
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use fake::{Fake, Faker};
111 use headers::{Header, HeaderValue};
112 use thegraph_core::attestation::Attestation;
113
114 use super::{AttestationSerde, GraphAttestation};
115
116 #[test]
117 fn encode_attestation_into_header() {
118 let attestation = Faker.fake::<Attestation>();
120
121 let mut headers = vec![];
122
123 let header = GraphAttestation(attestation.clone());
125
126 header.encode(&mut headers);
127
128 let value = headers.first().expect("header to have been encoded");
130
131 let att: AttestationSerde =
132 serde_json::from_slice(value.as_bytes()).expect("header to be valid json");
133 assert_eq!(attestation.request_cid, att.request_cid);
134 assert_eq!(attestation.response_cid, att.response_cid);
135 assert_eq!(attestation.deployment, att.deployment);
136 assert_eq!(attestation.r, att.r);
137 assert_eq!(attestation.s, att.s);
138 assert_eq!(attestation.v, att.v);
139 }
140
141 #[test]
142 fn decode_attestation_from_valid_header() {
143 let attestation = Faker.fake::<Attestation>();
145
146 let header = {
147 let value = serde_json::to_string(&AttestationSerde::from(&attestation)).unwrap();
148 HeaderValue::from_str(value.as_str()).unwrap()
149 };
150 let headers = [header];
151
152 let header = GraphAttestation::decode(&mut headers.iter());
154
155 let GraphAttestation(att) = header.expect("header to be valid");
157
158 assert_eq!(attestation.request_cid, att.request_cid);
159 assert_eq!(attestation.response_cid, att.response_cid);
160 assert_eq!(attestation.deployment, att.deployment);
161 assert_eq!(attestation.r, att.r);
162 assert_eq!(attestation.s, att.s);
163 assert_eq!(attestation.v, att.v);
164 }
165
166 #[test]
167 fn decode_attestation_from_first_header() {
168 let attestation = Faker.fake::<Attestation>();
170
171 let header = {
172 let value = serde_json::to_string(&AttestationSerde::from(&attestation)).unwrap();
173 HeaderValue::from_str(&value).unwrap()
174 };
175 let headers = [
176 header,
177 HeaderValue::from_static("invalid"),
178 HeaderValue::from_static(""),
179 ];
180
181 let result = GraphAttestation::decode(&mut headers.iter());
183
184 assert!(result.is_ok());
186 }
187
188 #[test]
189 fn fail_decode_attestation_from_empty_string_header() {
190 let header = HeaderValue::from_static("");
192 let headers = [header];
193
194 let result = GraphAttestation::decode(&mut headers.iter());
196
197 assert!(result.is_err());
199 }
200
201 #[test]
202 fn fail_decode_attestation_from_invalid_header() {
203 let header = HeaderValue::from_static("invalid");
205 let headers = [header];
206
207 let header = GraphAttestation::decode(&mut headers.iter());
209
210 assert!(header.is_err());
212 }
213
214 #[test]
215 fn fail_decode_attestation_if_no_headers() {
216 let headers = [];
218
219 let header = GraphAttestation::decode(&mut headers.iter());
221
222 assert!(header.is_err());
224 }
225}