Skip to main content

rain_metadata/meta/query/
mod.rs

1use std::sync::Arc;
2use reqwest::Client;
3use alloy::primitives::hex::decode;
4use serde::{Deserialize, Serialize};
5use graphql_client::{GraphQLQuery, Response, QueryBody};
6use super::{
7    RainMetaDocumentV1Item, KnownMagic, types::authoring::v1::AuthoringMeta, super::error::Error,
8};
9
10type Bytes = String;
11
12#[derive(GraphQLQuery)]
13#[graphql(
14    schema_path = "src/meta/query/schema.json",
15    query_path = "src/meta/query/meta.graphql",
16    response_derives = "Debug, Serialize, Deserialize"
17)]
18pub(super) struct MetaQuery;
19
20#[derive(GraphQLQuery)]
21#[graphql(
22    schema_path = "src/meta/query/schema.json",
23    query_path = "src/meta/query/deployer.graphql",
24    response_derives = "Debug, Serialize, Deserialize"
25)]
26pub(super) struct DeployerQuery;
27
28/// response data struct for a meta
29#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
30pub struct MetaResponse {
31    #[serde(with = "serde_bytes")]
32    pub bytes: Vec<u8>,
33}
34
35/// response data struct for an ExpressionDeployer
36#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
37#[serde(rename_all = "camelCase")]
38pub struct DeployerResponse {
39    #[serde(with = "serde_bytes")]
40    pub tx_hash: Vec<u8>,
41    #[serde(with = "serde_bytes")]
42    pub bytecode_meta_hash: Vec<u8>,
43    #[serde(with = "serde_bytes")]
44    pub meta_hash: Vec<u8>,
45    #[serde(with = "serde_bytes")]
46    pub meta_bytes: Vec<u8>,
47    #[serde(with = "serde_bytes")]
48    pub bytecode: Vec<u8>,
49    #[serde(with = "serde_bytes")]
50    pub parser: Vec<u8>,
51    #[serde(with = "serde_bytes")]
52    pub store: Vec<u8>,
53    #[serde(with = "serde_bytes")]
54    pub interpreter: Vec<u8>,
55}
56
57impl DeployerResponse {
58    /// get authoring meta bytes of this deployer meta
59    pub fn get_authoring_meta(&self) -> Option<AuthoringMeta> {
60        if let Ok(meta_maps) = RainMetaDocumentV1Item::cbor_decode(&self.meta_bytes) {
61            for meta_map in &meta_maps {
62                if meta_map.magic == KnownMagic::AuthoringMetaV1 {
63                    if let Ok(v) = meta_map.unpack() {
64                        match AuthoringMeta::abi_decode_validate(&v) {
65                            Ok(am) => return Some(am),
66                            Err(_) => return None,
67                        }
68                    }
69                }
70            }
71            None
72        } else {
73            None
74        }
75    }
76}
77
78/// Process a response for a meta by resolving if a record was found or reject if nothing found or rejected with error
79/// This is because graphql responses are not rejected even if there was no record found for the request
80pub(super) async fn process_meta_query(
81    client: Arc<Client>,
82    request_body: &QueryBody<meta_query::Variables>,
83    url: &str,
84) -> Result<MetaResponse, Error> {
85    Ok(MetaResponse {
86        bytes: decode(
87            client
88                .post(url)
89                .json(request_body)
90                .send()
91                .await
92                .map_err(Error::ReqwestError)?
93                .json::<Response<meta_query::ResponseData>>()
94                .await
95                .map_err(Error::ReqwestError)?
96                .data
97                .ok_or(Error::NoRecordFound)?
98                .meta
99                .ok_or(Error::NoRecordFound)?
100                .raw_bytes,
101        )
102        .or(Err(Error::NoRecordFound))?,
103    })
104}
105
106/// process a response for a deployer by resolving if a record was found or reject if nothing found or rejected with error
107/// This is because graphql responses are not rejected even if there was no record found for the request
108pub(super) async fn process_deployer_query(
109    client: Arc<Client>,
110    request_body: &QueryBody<deployer_query::Variables>,
111    url: &str,
112) -> Result<DeployerResponse, Error> {
113    let res = client
114        .post(url)
115        .json(request_body)
116        .send()
117        .await
118        .map_err(Error::ReqwestError)?
119        .json::<Response<deployer_query::ResponseData>>()
120        .await
121        .map_err(Error::ReqwestError)?
122        .data
123        .ok_or(Error::NoRecordFound)?
124        .expression_deployers;
125
126    if !res.is_empty() {
127        let bytecode = if let Some(v) = &res[0].bytecode {
128            decode(v).or(Err(Error::NoRecordFound))?
129        } else {
130            return Err(Error::NoRecordFound);
131        };
132        let parser = if let Some(v) = &res[0].parser {
133            decode(&v.parser.deployed_bytecode).or(Err(Error::NoRecordFound))?
134        } else {
135            return Err(Error::NoRecordFound);
136        };
137        let store = if let Some(v) = &res[0].store {
138            decode(&v.store.deployed_bytecode).or(Err(Error::NoRecordFound))?
139        } else {
140            return Err(Error::NoRecordFound);
141        };
142        let interpreter = if let Some(v) = &res[0].interpreter {
143            decode(&v.interpreter.deployed_bytecode).or(Err(Error::NoRecordFound))?
144        } else {
145            return Err(Error::NoRecordFound);
146        };
147        let bytecode_meta_hash = if res[0].meta.len() == 1 {
148            decode(&res[0].meta[0].id).or(Err(Error::NoRecordFound))?
149        } else {
150            return Err(Error::NoRecordFound);
151        };
152        let tx_hash = if let Some(v) = &res[0].deploy_transaction {
153            decode(&v.id).or(Err(Error::NoRecordFound))?
154        } else {
155            return Err(Error::NoRecordFound);
156        };
157        let meta_hash = decode(&res[0].constructor_meta_hash).or(Err(Error::NoRecordFound))?;
158        let meta_bytes = decode(&res[0].constructor_meta).or(Err(Error::NoRecordFound))?;
159        Ok(DeployerResponse {
160            meta_hash,
161            meta_bytes,
162            bytecode,
163            parser,
164            store,
165            interpreter,
166            bytecode_meta_hash,
167            tx_hash,
168        })
169    } else {
170        Err(Error::NoRecordFound)
171    }
172}