near_api/common/query/handlers/
mod.rs

1use borsh::BorshDeserialize;
2use near_api_types::{
3    json::U64, AccessKey, Account, AccountView, ContractCodeView, Data, PublicKey,
4    RpcBlockResponse, RpcValidatorResponse, ViewStateResult,
5};
6use near_openapi_client::types::RpcQueryResponse;
7use serde::de::DeserializeOwned;
8use std::marker::PhantomData;
9use tracing::{info, trace, warn};
10
11use crate::{
12    advanced::{
13        block_rpc::SimpleBlockRpc, query_rpc::SimpleQueryRpc, validator_rpc::SimpleValidatorRpc,
14        RpcType,
15    },
16    common::query::{ResultWithMethod, QUERY_EXECUTOR_TARGET},
17    errors::QueryError,
18};
19pub mod transformers;
20pub use transformers::*;
21
22const fn query_to_kind(response: &RpcQueryResponse) -> &'static str {
23    match response {
24        RpcQueryResponse::Variant0 { .. } => "ViewAccount",
25        RpcQueryResponse::Variant1 { .. } => "ViewCode",
26        RpcQueryResponse::Variant2 { .. } => "ViewState",
27        RpcQueryResponse::Variant3 { .. } => "CallResult",
28        RpcQueryResponse::Variant4 { .. } => "AccessKey",
29        RpcQueryResponse::Variant5 { .. } => "AccessKeyList",
30        RpcQueryResponse::Variant6 { .. } => "ViewGasKey",
31        RpcQueryResponse::Variant7 { .. } => "ViewGasKeyList",
32
33        #[allow(unreachable_patterns)]
34        _ => "UnknownQueryResponse",
35    }
36}
37
38pub trait ResponseHandler {
39    type Response;
40    type Query: RpcType;
41
42    /// NOTE: responses should always >= 1
43    fn process_response(
44        &self,
45        responses: Vec<<Self::Query as RpcType>::Response>,
46    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error>;
47    fn request_amount(&self) -> usize {
48        1
49    }
50}
51
52#[derive(Default, Debug, Clone)]
53pub struct CallResultHandler<Response: Send + Sync>(PhantomData<Response>);
54
55impl<Response: Send + Sync> CallResultHandler<Response> {
56    pub const fn new() -> Self {
57        Self(PhantomData::<Response>)
58    }
59}
60
61impl<Response> ResponseHandler for CallResultHandler<Response>
62where
63    Response: DeserializeOwned + Send + Sync,
64{
65    type Response = Data<Response>;
66    type Query = SimpleQueryRpc;
67
68    fn process_response(
69        &self,
70        response: Vec<RpcQueryResponse>,
71    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
72        let response = response
73            .into_iter()
74            .next()
75            .ok_or(QueryError::InternalErrorNoResponse)?;
76
77        if let RpcQueryResponse::Variant3 {
78            result,
79            logs: _logs,
80            block_height,
81            block_hash,
82        } = response
83        {
84            trace!(target: QUERY_EXECUTOR_TARGET, "Deserializing CallResult, result size: {} bytes", result.len());
85            let data: Response = serde_json::from_slice(&result)?;
86            Ok(Data {
87                data,
88                block_height,
89                block_hash: block_hash
90                    .try_into()
91                    .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
92            })
93        } else {
94            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
95            Err(QueryError::UnexpectedResponse {
96                expected: "CallResult",
97                got: query_to_kind(&response),
98            })
99        }
100    }
101}
102
103#[derive(Default, Debug, Clone)]
104pub struct CallResultBorshHandler<Response: Send + Sync>(PhantomData<Response>);
105
106impl<Response: Send + Sync> CallResultBorshHandler<Response> {
107    pub const fn new() -> Self {
108        Self(PhantomData::<Response>)
109    }
110}
111
112impl<Response> ResponseHandler for CallResultBorshHandler<Response>
113where
114    Response: BorshDeserialize + Send + Sync,
115{
116    type Response = Data<Response>;
117    type Query = SimpleQueryRpc;
118
119    fn process_response(
120        &self,
121        response: Vec<RpcQueryResponse>,
122    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
123        let response = response
124            .into_iter()
125            .next()
126            .ok_or(QueryError::InternalErrorNoResponse)?;
127
128        if let RpcQueryResponse::Variant3 {
129            result,
130            logs: _logs,
131            block_height,
132            block_hash,
133        } = response
134        {
135            trace!(target: QUERY_EXECUTOR_TARGET, "Deserializing CallResult using Borsh, result size: {} bytes", result.len());
136            let data: Response = Response::try_from_slice(&result)
137                .map_err(|e| QueryError::ConversionError(Box::new(e)))?;
138            Ok(Data {
139                data,
140                block_height,
141                block_hash: block_hash
142                    .try_into()
143                    .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
144            })
145        } else {
146            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
147            Err(QueryError::UnexpectedResponse {
148                expected: "CallResult",
149                got: query_to_kind(&response),
150            })
151        }
152    }
153}
154
155#[derive(Default, Debug, Clone)]
156pub struct AccountViewHandler;
157
158impl ResponseHandler for AccountViewHandler {
159    type Query = SimpleQueryRpc;
160    type Response = Data<Account>;
161
162    fn process_response(
163        &self,
164        response: Vec<RpcQueryResponse>,
165    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
166        let response = response
167            .into_iter()
168            .next()
169            .ok_or(QueryError::InternalErrorNoResponse)?;
170
171        if let RpcQueryResponse::Variant0 {
172            amount,
173            locked,
174            code_hash,
175            storage_usage,
176            storage_paid_at,
177            block_hash,
178            block_height,
179            global_contract_account_id,
180            global_contract_hash,
181        } = response
182        {
183            info!(
184                target: QUERY_EXECUTOR_TARGET,
185                "Processed ViewAccount response: balance: {}, locked: {}",
186                amount, locked
187            );
188            Ok(Data {
189                data: AccountView {
190                    amount,
191                    locked,
192                    code_hash,
193                    storage_usage,
194                    storage_paid_at,
195                    global_contract_account_id,
196                    global_contract_hash,
197                }
198                .try_into()
199                .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
200                block_height,
201                block_hash: block_hash
202                    .try_into()
203                    .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
204            })
205        } else {
206            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
207            Err(QueryError::UnexpectedResponse {
208                expected: "ViewAccount",
209                got: query_to_kind(&response),
210            })
211        }
212    }
213
214    fn request_amount(&self) -> usize {
215        1
216    }
217}
218
219#[derive(Default, Debug, Clone)]
220pub struct AccessKeyListHandler;
221
222impl ResponseHandler for AccessKeyListHandler {
223    type Response = Data<Vec<(PublicKey, AccessKey)>>;
224    type Query = SimpleQueryRpc;
225
226    fn process_response(
227        &self,
228        response: Vec<RpcQueryResponse>,
229    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
230        let response = response
231            .into_iter()
232            .next()
233            .ok_or(QueryError::InternalErrorNoResponse)?;
234        if let RpcQueryResponse::Variant5 {
235            keys,
236            block_height,
237            block_hash,
238        } = response
239        {
240            info!(
241                target: QUERY_EXECUTOR_TARGET,
242                "Processed AccessKeyList response, keys count: {}",
243                keys.len()
244            );
245            Ok(Data {
246                data: keys
247                    .into_iter()
248                    .filter_map(|key| {
249                        let public_key = key.public_key.try_into().ok()?;
250                        let access_key = key.access_key.try_into().ok()?;
251                        Some((public_key, access_key))
252                    })
253                    .collect(),
254                block_height,
255                block_hash: block_hash
256                    .try_into()
257                    .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
258            })
259        } else {
260            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
261            Err(QueryError::UnexpectedResponse {
262                expected: "AccessKeyList",
263                got: query_to_kind(&response),
264            })
265        }
266    }
267
268    fn request_amount(&self) -> usize {
269        1
270    }
271}
272
273#[derive(Default, Debug, Clone)]
274pub struct AccessKeyHandler;
275
276impl ResponseHandler for AccessKeyHandler {
277    type Response = Data<AccessKey>;
278    type Query = SimpleQueryRpc;
279
280    fn process_response(
281        &self,
282        response: Vec<RpcQueryResponse>,
283    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
284        let response = response
285            .into_iter()
286            .next()
287            .ok_or(QueryError::InternalErrorNoResponse)?;
288        if let RpcQueryResponse::Variant4 {
289            block_hash,
290            nonce,
291            block_height,
292            permission,
293        } = response
294        {
295            info!(
296                target: QUERY_EXECUTOR_TARGET,
297                "Processed AccessKey response, nonce: {}, permission: {:?}",
298                nonce,
299                permission
300            );
301            Ok(Data {
302                data: AccessKey {
303                    nonce: U64(nonce),
304                    permission: permission
305                        .try_into()
306                        .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
307                },
308                block_height,
309                block_hash: block_hash
310                    .try_into()
311                    .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
312            })
313        } else {
314            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
315            Err(QueryError::UnexpectedResponse {
316                expected: "AccessKey",
317                got: query_to_kind(&response),
318            })
319        }
320    }
321}
322
323#[derive(Default, Debug, Clone)]
324pub struct ViewStateHandler;
325
326impl ResponseHandler for ViewStateHandler {
327    type Response = Data<ViewStateResult>;
328    type Query = SimpleQueryRpc;
329
330    fn process_response(
331        &self,
332        response: Vec<RpcQueryResponse>,
333    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
334        let response = response
335            .into_iter()
336            .next()
337            .ok_or(QueryError::InternalErrorNoResponse)?;
338        if let RpcQueryResponse::Variant2 {
339            proof,
340            values,
341            block_height,
342            block_hash,
343        } = response
344        {
345            info!(
346                target: QUERY_EXECUTOR_TARGET,
347                "Processed ViewState response, values count: {}, proof nodes: {}",
348                values.len(),
349                proof.len()
350            );
351            Ok(Data {
352                data: ViewStateResult { proof, values },
353                block_height,
354                block_hash: block_hash
355                    .try_into()
356                    .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
357            })
358        } else {
359            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
360            Err(QueryError::UnexpectedResponse {
361                expected: "ViewState",
362                got: query_to_kind(&response),
363            })
364        }
365    }
366}
367
368#[derive(Default, Debug, Clone)]
369pub struct ViewCodeHandler;
370
371impl ResponseHandler for ViewCodeHandler {
372    type Response = Data<ContractCodeView>;
373    type Query = SimpleQueryRpc;
374
375    fn process_response(
376        &self,
377        response: Vec<RpcQueryResponse>,
378    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
379        let response = response
380            .into_iter()
381            .next()
382            .ok_or(QueryError::InternalErrorNoResponse)?;
383        if let RpcQueryResponse::Variant1 {
384            code_base64,
385            hash,
386            block_height,
387            block_hash,
388        } = response
389        {
390            info!(
391                target: QUERY_EXECUTOR_TARGET,
392                "Processed ViewCode response, code size: {} bytes, hash: {:?}",
393                code_base64.len(),
394                hash
395            );
396            Ok(Data {
397                data: ContractCodeView { code_base64, hash },
398                block_height,
399                block_hash: block_hash
400                    .try_into()
401                    .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
402            })
403        } else {
404            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
405            Err(QueryError::UnexpectedResponse {
406                expected: "ViewCode",
407                got: query_to_kind(&response),
408            })
409        }
410    }
411}
412
413#[derive(Clone, Debug)]
414pub struct RpcValidatorHandler;
415
416impl ResponseHandler for RpcValidatorHandler {
417    type Response = RpcValidatorResponse;
418    type Query = SimpleValidatorRpc;
419
420    fn process_response(
421        &self,
422        response: Vec<RpcValidatorResponse>,
423    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
424        let response = response
425            .into_iter()
426            .next()
427            .ok_or(QueryError::InternalErrorNoResponse)?;
428
429        info!(
430            target: QUERY_EXECUTOR_TARGET,
431            "Processed EpochValidatorInfo response, epoch height: {}, validators count: {}",
432            response.epoch_height,
433            response.current_validators.len()
434        );
435        Ok(response)
436    }
437}
438
439#[derive(Clone, Debug)]
440pub struct RpcBlockHandler;
441
442impl ResponseHandler for RpcBlockHandler {
443    type Response = RpcBlockResponse;
444    type Query = SimpleBlockRpc;
445
446    fn process_response(
447        &self,
448        response: Vec<RpcBlockResponse>,
449    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
450        let response = response
451            .into_iter()
452            .next()
453            .ok_or(QueryError::InternalErrorNoResponse)?;
454
455        info!(
456            target: QUERY_EXECUTOR_TARGET,
457            "Processed Block response, height: {}, hash: {:?}",
458            response.header.height,
459            response.header.hash
460        );
461        Ok(response)
462    }
463
464    fn request_amount(&self) -> usize {
465        1
466    }
467}
468
469impl<T: RpcType> ResponseHandler for T {
470    type Response = <T as RpcType>::Response;
471    type Query = T;
472
473    fn process_response(
474        &self,
475        response: Vec<<Self::Query as RpcType>::Response>,
476    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
477        let response = response
478            .into_iter()
479            .next()
480            .ok_or(QueryError::InternalErrorNoResponse)?;
481
482        trace!(target: QUERY_EXECUTOR_TARGET, "Processed empty response handler");
483
484        Ok(response)
485    }
486}