Skip to main content

near_api/common/query/handlers/
mod.rs

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