use headers::{Error as HeaderError, HeaderName, HeaderValue};
use thegraph_core::alloy::primitives::B256;
pub use thegraph_core::attestation::Attestation;
pub const HEADER_NAME: &str = "graph-attestation";
#[derive(Debug, Clone)]
pub struct GraphAttestation(pub Attestation);
impl headers::Header for GraphAttestation {
fn name() -> &'static HeaderName {
static HTTP_HEADER_NAME: HeaderName = HeaderName::from_static(HEADER_NAME);
&HTTP_HEADER_NAME
}
fn decode<'i, I>(values: &mut I) -> Result<Self, HeaderError>
where
Self: Sized,
I: Iterator<Item = &'i HeaderValue>,
{
let value = values.next().ok_or_else(HeaderError::invalid)?;
let attestation = serde_json::from_slice::<'_, AttestationSerde>(value.as_bytes())
.map_err(|_| HeaderError::invalid())?;
Ok(Self(attestation.into()))
}
fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
let bytes =
serde_json::to_vec(&AttestationSerde::from(&self.0)).expect("header to be valid json");
let value = HeaderValue::from_bytes(&bytes).expect("header to be valid utf-8");
values.extend(std::iter::once(value));
}
}
#[derive(serde::Serialize, serde::Deserialize)]
struct AttestationSerde {
#[serde(rename = "requestCID")]
request_cid: B256,
#[serde(rename = "responseCID")]
response_cid: B256,
#[serde(rename = "subgraphDeploymentID")]
deployment: B256,
r: B256,
s: B256,
v: u8,
}
impl From<AttestationSerde> for Attestation {
fn from(value: AttestationSerde) -> Self {
Self {
request_cid: value.request_cid,
response_cid: value.response_cid,
deployment: value.deployment,
r: value.r,
s: value.s,
v: value.v,
}
}
}
impl From<&Attestation> for AttestationSerde {
fn from(value: &Attestation) -> Self {
Self {
request_cid: value.request_cid,
response_cid: value.response_cid,
deployment: value.deployment,
r: value.r,
s: value.s,
v: value.v,
}
}
}
#[cfg(test)]
mod tests {
use fake::{Fake, Faker};
use headers::{Header, HeaderValue};
use thegraph_core::attestation::Attestation;
use super::{AttestationSerde, GraphAttestation};
#[test]
fn encode_attestation_into_header() {
let attestation = Faker.fake::<Attestation>();
let mut headers = vec![];
let header = GraphAttestation(attestation.clone());
header.encode(&mut headers);
let value = headers.first().expect("header to have been encoded");
let att: AttestationSerde =
serde_json::from_slice(value.as_bytes()).expect("header to be valid json");
assert_eq!(attestation.request_cid, att.request_cid);
assert_eq!(attestation.response_cid, att.response_cid);
assert_eq!(attestation.deployment, att.deployment);
assert_eq!(attestation.r, att.r);
assert_eq!(attestation.s, att.s);
assert_eq!(attestation.v, att.v);
}
#[test]
fn decode_attestation_from_valid_header() {
let attestation = Faker.fake::<Attestation>();
let header = {
let value = serde_json::to_string(&AttestationSerde::from(&attestation)).unwrap();
HeaderValue::from_str(value.as_str()).unwrap()
};
let headers = [header];
let header = GraphAttestation::decode(&mut headers.iter());
let GraphAttestation(att) = header.expect("header to be valid");
assert_eq!(attestation.request_cid, att.request_cid);
assert_eq!(attestation.response_cid, att.response_cid);
assert_eq!(attestation.deployment, att.deployment);
assert_eq!(attestation.r, att.r);
assert_eq!(attestation.s, att.s);
assert_eq!(attestation.v, att.v);
}
#[test]
fn decode_attestation_from_first_header() {
let attestation = Faker.fake::<Attestation>();
let header = {
let value = serde_json::to_string(&AttestationSerde::from(&attestation)).unwrap();
HeaderValue::from_str(&value).unwrap()
};
let headers = [
header,
HeaderValue::from_static("invalid"),
HeaderValue::from_static(""),
];
let result = GraphAttestation::decode(&mut headers.iter());
assert!(result.is_ok());
}
#[test]
fn fail_decode_attestation_from_empty_string_header() {
let header = HeaderValue::from_static("");
let headers = [header];
let result = GraphAttestation::decode(&mut headers.iter());
assert!(result.is_err());
}
#[test]
fn fail_decode_attestation_from_invalid_header() {
let header = HeaderValue::from_static("invalid");
let headers = [header];
let header = GraphAttestation::decode(&mut headers.iter());
assert!(header.is_err());
}
#[test]
fn fail_decode_attestation_if_no_headers() {
let headers = [];
let header = GraphAttestation::decode(&mut headers.iter());
assert!(header.is_err());
}
}