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.into(),
90            })
91        } else {
92            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
93            Err(QueryError::UnexpectedResponse {
94                expected: "CallResult",
95                got: query_to_kind(&response),
96            })
97        }
98    }
99}
100
101#[derive(Default, Debug, Clone)]
102pub struct CallResultRawHandler;
103
104impl CallResultRawHandler {
105    pub const fn new() -> Self {
106        Self
107    }
108}
109
110impl ResponseHandler for CallResultRawHandler {
111    type Response = Data<Vec<u8>>;
112    type Query = SimpleQueryRpc;
113
114    fn process_response(
115        &self,
116        response: Vec<RpcQueryResponse>,
117    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
118        let response = response
119            .into_iter()
120            .next()
121            .ok_or(QueryError::InternalErrorNoResponse)?;
122
123        if let RpcQueryResponse::Variant3 {
124            result,
125            logs: _logs,
126            block_height,
127            block_hash,
128        } = response
129        {
130            trace!(target: QUERY_EXECUTOR_TARGET, "Returning CallResult raw bytes, result size: {} bytes", result.len());
131            Ok(Data {
132                data: result,
133                block_height,
134                block_hash: block_hash.into(),
135            })
136        } else {
137            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
138            Err(QueryError::UnexpectedResponse {
139                expected: "CallResult",
140                got: query_to_kind(&response),
141            })
142        }
143    }
144}
145
146#[derive(Default, Debug, Clone)]
147pub struct CallResultBorshHandler<Response: Send + Sync>(PhantomData<Response>);
148
149impl<Response: Send + Sync> CallResultBorshHandler<Response> {
150    pub const fn new() -> Self {
151        Self(PhantomData::<Response>)
152    }
153}
154
155impl<Response> ResponseHandler for CallResultBorshHandler<Response>
156where
157    Response: BorshDeserialize + Send + Sync,
158{
159    type Response = Data<Response>;
160    type Query = SimpleQueryRpc;
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::Variant3 {
172            result,
173            logs: _logs,
174            block_height,
175            block_hash,
176        } = response
177        {
178            trace!(target: QUERY_EXECUTOR_TARGET, "Deserializing CallResult using Borsh, result size: {} bytes", result.len());
179            let data: Response = Response::try_from_slice(&result)
180                .map_err(|e| QueryError::ConversionError(Box::new(e)))?;
181            Ok(Data {
182                data,
183                block_height,
184                block_hash: block_hash.into(),
185            })
186        } else {
187            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
188            Err(QueryError::UnexpectedResponse {
189                expected: "CallResult",
190                got: query_to_kind(&response),
191            })
192        }
193    }
194}
195
196#[derive(Default, Debug, Clone)]
197pub struct AccountViewHandler;
198
199impl ResponseHandler for AccountViewHandler {
200    type Query = SimpleQueryRpc;
201    type Response = Data<Account>;
202
203    fn process_response(
204        &self,
205        response: Vec<RpcQueryResponse>,
206    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
207        let response = response
208            .into_iter()
209            .next()
210            .ok_or(QueryError::InternalErrorNoResponse)?;
211
212        if let RpcQueryResponse::Variant0 {
213            amount,
214            locked,
215            code_hash,
216            storage_usage,
217            storage_paid_at,
218            block_hash,
219            block_height,
220            global_contract_account_id,
221            global_contract_hash,
222        } = response
223        {
224            info!(
225                target: QUERY_EXECUTOR_TARGET,
226                "Processed ViewAccount response: balance: {}, locked: {}",
227                amount, locked
228            );
229            Ok(Data {
230                data: AccountView {
231                    amount,
232                    locked,
233                    code_hash,
234                    storage_usage,
235                    storage_paid_at,
236                    global_contract_account_id,
237                    global_contract_hash,
238                }
239                .try_into()
240                .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
241                block_height,
242                block_hash: block_hash.into(),
243            })
244        } else {
245            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
246            Err(QueryError::UnexpectedResponse {
247                expected: "ViewAccount",
248                got: query_to_kind(&response),
249            })
250        }
251    }
252
253    fn request_amount(&self) -> usize {
254        1
255    }
256}
257
258#[derive(Default, Debug, Clone)]
259pub struct AccessKeyListHandler;
260
261impl ResponseHandler for AccessKeyListHandler {
262    type Response = Data<Vec<(PublicKey, AccessKey)>>;
263    type Query = SimpleQueryRpc;
264
265    fn process_response(
266        &self,
267        response: Vec<RpcQueryResponse>,
268    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
269        let response = response
270            .into_iter()
271            .next()
272            .ok_or(QueryError::InternalErrorNoResponse)?;
273        if let RpcQueryResponse::Variant5 {
274            keys,
275            block_height,
276            block_hash,
277        } = response
278        {
279            info!(
280                target: QUERY_EXECUTOR_TARGET,
281                "Processed AccessKeyList response, keys count: {}",
282                keys.len()
283            );
284            Ok(Data {
285                data: keys
286                    .into_iter()
287                    .filter_map(|key| {
288                        let public_key = key.public_key.try_into().ok()?;
289                        let access_key = key.access_key.try_into().ok()?;
290                        Some((public_key, access_key))
291                    })
292                    .collect(),
293                block_height,
294                block_hash: block_hash.into(),
295            })
296        } else {
297            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
298            Err(QueryError::UnexpectedResponse {
299                expected: "AccessKeyList",
300                got: query_to_kind(&response),
301            })
302        }
303    }
304
305    fn request_amount(&self) -> usize {
306        1
307    }
308}
309
310#[derive(Default, Debug, Clone)]
311pub struct AccessKeyHandler;
312
313impl ResponseHandler for AccessKeyHandler {
314    type Response = Data<AccessKey>;
315    type Query = SimpleQueryRpc;
316
317    fn process_response(
318        &self,
319        response: Vec<RpcQueryResponse>,
320    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
321        let response = response
322            .into_iter()
323            .next()
324            .ok_or(QueryError::InternalErrorNoResponse)?;
325        if let RpcQueryResponse::Variant4 {
326            block_hash,
327            nonce,
328            block_height,
329            permission,
330        } = response
331        {
332            info!(
333                target: QUERY_EXECUTOR_TARGET,
334                "Processed AccessKey response, nonce: {}, permission: {:?}",
335                nonce,
336                permission
337            );
338            Ok(Data {
339                data: AccessKey {
340                    nonce: U64(nonce),
341                    permission: permission
342                        .try_into()
343                        .map_err(|e| QueryError::ConversionError(Box::new(e)))?,
344                },
345                block_height,
346                block_hash: block_hash.into(),
347            })
348        } else {
349            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
350            Err(QueryError::UnexpectedResponse {
351                expected: "AccessKey",
352                got: query_to_kind(&response),
353            })
354        }
355    }
356}
357
358#[derive(Default, Debug, Clone)]
359pub struct ViewStateHandler;
360
361impl ResponseHandler for ViewStateHandler {
362    type Response = Data<ViewStateResult>;
363    type Query = SimpleQueryRpc;
364
365    fn process_response(
366        &self,
367        response: Vec<RpcQueryResponse>,
368    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
369        let response = response
370            .into_iter()
371            .next()
372            .ok_or(QueryError::InternalErrorNoResponse)?;
373        if let RpcQueryResponse::Variant2 {
374            proof,
375            values,
376            block_height,
377            block_hash,
378        } = response
379        {
380            info!(
381                target: QUERY_EXECUTOR_TARGET,
382                "Processed ViewState response, values count: {}, proof nodes: {}",
383                values.len(),
384                proof.len()
385            );
386            Ok(Data {
387                data: ViewStateResult { proof, values },
388                block_height,
389                block_hash: block_hash.into(),
390            })
391        } else {
392            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
393            Err(QueryError::UnexpectedResponse {
394                expected: "ViewState",
395                got: query_to_kind(&response),
396            })
397        }
398    }
399}
400
401#[derive(Default, Debug, Clone)]
402pub struct ViewCodeHandler;
403
404impl ResponseHandler for ViewCodeHandler {
405    type Response = Data<ContractCodeView>;
406    type Query = SimpleQueryRpc;
407
408    fn process_response(
409        &self,
410        response: Vec<RpcQueryResponse>,
411    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
412        let response = response
413            .into_iter()
414            .next()
415            .ok_or(QueryError::InternalErrorNoResponse)?;
416        if let RpcQueryResponse::Variant1 {
417            code_base64,
418            hash,
419            block_height,
420            block_hash,
421        } = response
422        {
423            info!(
424                target: QUERY_EXECUTOR_TARGET,
425                "Processed ViewCode response, code size: {} bytes, hash: {:?}",
426                code_base64.len(),
427                hash
428            );
429            Ok(Data {
430                data: ContractCodeView { code_base64, hash },
431                block_height,
432                block_hash: block_hash.into(),
433            })
434        } else {
435            warn!(target: QUERY_EXECUTOR_TARGET, "Unexpected response kind: {:?}", response);
436            Err(QueryError::UnexpectedResponse {
437                expected: "ViewCode",
438                got: query_to_kind(&response),
439            })
440        }
441    }
442}
443
444#[derive(Clone, Debug)]
445pub struct RpcValidatorHandler;
446
447impl ResponseHandler for RpcValidatorHandler {
448    type Response = RpcValidatorResponse;
449    type Query = SimpleValidatorRpc;
450
451    fn process_response(
452        &self,
453        response: Vec<RpcValidatorResponse>,
454    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
455        let response = response
456            .into_iter()
457            .next()
458            .ok_or(QueryError::InternalErrorNoResponse)?;
459
460        info!(
461            target: QUERY_EXECUTOR_TARGET,
462            "Processed EpochValidatorInfo response, epoch height: {}, validators count: {}",
463            response.epoch_height,
464            response.current_validators.len()
465        );
466        Ok(response)
467    }
468}
469
470#[derive(Clone, Debug)]
471pub struct RpcBlockHandler;
472
473impl ResponseHandler for RpcBlockHandler {
474    type Response = RpcBlockResponse;
475    type Query = SimpleBlockRpc;
476
477    fn process_response(
478        &self,
479        response: Vec<RpcBlockResponse>,
480    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
481        let response = response
482            .into_iter()
483            .next()
484            .ok_or(QueryError::InternalErrorNoResponse)?;
485
486        info!(
487            target: QUERY_EXECUTOR_TARGET,
488            "Processed Block response, height: {}, hash: {:?}",
489            response.header.height,
490            response.header.hash
491        );
492        Ok(response)
493    }
494
495    fn request_amount(&self) -> usize {
496        1
497    }
498}
499
500impl<T: RpcType> ResponseHandler for T {
501    type Response = <T as RpcType>::Response;
502    type Query = T;
503
504    fn process_response(
505        &self,
506        response: Vec<<Self::Query as RpcType>::Response>,
507    ) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
508        let response = response
509            .into_iter()
510            .next()
511            .ok_or(QueryError::InternalErrorNoResponse)?;
512
513        trace!(target: QUERY_EXECUTOR_TARGET, "Processed empty response handler");
514
515        Ok(response)
516    }
517}