Skip to main content

near_api/common/query/
tx_rpc.rs

1use near_api_types::{AccountId, CryptoHash, TxExecutionStatus};
2use near_openapi_client::Client;
3use near_openapi_client::types::{
4    ErrorWrapperForRpcLightClientProofError, ErrorWrapperForRpcReceiptError,
5    JsonRpcRequestForExperimentalReceipt, JsonRpcRequestForExperimentalReceiptMethod,
6    JsonRpcRequestForLightClientProof, JsonRpcRequestForLightClientProofMethod,
7    JsonRpcRequestForTx, JsonRpcRequestForTxMethod,
8    JsonRpcResponseForRpcLightClientExecutionProofResponseAndRpcLightClientProofError,
9    JsonRpcResponseForRpcReceiptResponseAndRpcReceiptError,
10    JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError,
11    RpcLightClientExecutionProofRequest, RpcLightClientExecutionProofRequestVariant0Type,
12    RpcLightClientExecutionProofResponse, RpcLightClientProofError, RpcReceiptError,
13    RpcReceiptRequest, RpcReceiptResponse, RpcTransactionError, RpcTransactionStatusRequest,
14};
15
16use crate::common::utils::to_retry_error;
17use crate::{
18    NetworkConfig,
19    advanced::RpcType,
20    common::utils::{
21        is_critical_light_client_proof_error, is_critical_receipt_error,
22        is_critical_transaction_status_error,
23    },
24    config::RetryResponse,
25    errors::SendRequestError,
26};
27
28/// Reference type for transaction status queries.
29///
30/// Identifies a transaction by its hash, sender account, and the desired execution status to wait for.
31#[derive(Clone, Debug)]
32pub struct TransactionStatusRef {
33    pub sender_account_id: AccountId,
34    pub tx_hash: CryptoHash,
35    pub wait_until: TxExecutionStatus,
36}
37
38/// RPC type for fetching transaction status by hash.
39///
40/// Uses the `tx` RPC method to query the status of a previously submitted transaction.
41#[derive(Clone, Debug)]
42pub struct TransactionStatusRpc;
43
44#[async_trait::async_trait]
45impl RpcType for TransactionStatusRpc {
46    type RpcReference = TransactionStatusRef;
47    type Response = near_openapi_client::types::RpcTransactionResponse;
48    type Error = RpcTransactionError;
49
50    async fn send_query(
51        &self,
52        client: &Client,
53        _network: &NetworkConfig,
54        reference: &TransactionStatusRef,
55    ) -> RetryResponse<Self::Response, SendRequestError<RpcTransactionError>> {
56        let response = client
57            .tx(&JsonRpcRequestForTx {
58                id: "0".to_string(),
59                jsonrpc: "2.0".to_string(),
60                method: JsonRpcRequestForTxMethod::Tx,
61                params: RpcTransactionStatusRequest::Variant1 {
62                    sender_account_id: reference.sender_account_id.clone(),
63                    tx_hash: reference.tx_hash.into(),
64                    wait_until: reference.wait_until,
65                },
66            })
67            .await
68            .map(|r| r.into_inner())
69            .map_err(SendRequestError::from);
70
71        match response {
72            Ok(JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError::Variant0 {
73                result,
74                ..
75            }) => RetryResponse::Ok(result),
76            Ok(JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError::Variant1 {
77                error,
78                ..
79            }) => {
80                let error = SendRequestError::from(error);
81                to_retry_error(error, is_critical_transaction_status_error)
82            }
83            Err(err) => to_retry_error(err, is_critical_transaction_status_error),
84        }
85    }
86}
87
88/// Reference type for receipt queries.
89///
90/// Identifies a receipt by its ID.
91#[derive(Clone, Debug)]
92pub struct ReceiptRef {
93    pub receipt_id: CryptoHash,
94}
95
96/// RPC type for fetching a receipt by its ID.
97///
98/// Uses the `EXPERIMENTAL_receipt` RPC method.
99#[derive(Clone, Debug)]
100pub struct ReceiptRpc;
101
102#[async_trait::async_trait]
103impl RpcType for ReceiptRpc {
104    type RpcReference = ReceiptRef;
105    type Response = RpcReceiptResponse;
106    type Error = RpcReceiptError;
107
108    async fn send_query(
109        &self,
110        client: &Client,
111        _network: &NetworkConfig,
112        reference: &ReceiptRef,
113    ) -> RetryResponse<RpcReceiptResponse, SendRequestError<RpcReceiptError>> {
114        let response = client
115            .experimental_receipt(&JsonRpcRequestForExperimentalReceipt {
116                id: "0".to_string(),
117                jsonrpc: "2.0".to_string(),
118                method: JsonRpcRequestForExperimentalReceiptMethod::ExperimentalReceipt,
119                params: RpcReceiptRequest {
120                    receipt_id: reference.receipt_id.into(),
121                },
122            })
123            .await
124            .map(|r| r.into_inner())
125            .map_err(SendRequestError::from);
126
127        match response {
128            Ok(JsonRpcResponseForRpcReceiptResponseAndRpcReceiptError::Variant0 {
129                result, ..
130            }) => RetryResponse::Ok(result),
131            Ok(JsonRpcResponseForRpcReceiptResponseAndRpcReceiptError::Variant1 {
132                error, ..
133            }) => {
134                let error = SendRequestError::from(error);
135                to_retry_error(error, is_critical_receipt_error)
136            }
137            Err(err) => to_retry_error(err, is_critical_receipt_error),
138        }
139    }
140}
141
142impl From<ErrorWrapperForRpcReceiptError> for SendRequestError<RpcReceiptError> {
143    fn from(err: ErrorWrapperForRpcReceiptError) -> Self {
144        match err {
145            ErrorWrapperForRpcReceiptError::InternalError(internal_error) => {
146                Self::InternalError(internal_error)
147            }
148            ErrorWrapperForRpcReceiptError::RequestValidationError(
149                rpc_request_validation_error_kind,
150            ) => Self::RequestValidationError(rpc_request_validation_error_kind),
151            ErrorWrapperForRpcReceiptError::HandlerError(server_error) => {
152                Self::ServerError(server_error)
153            }
154        }
155    }
156}
157
158/// Reference type for transaction proof queries.
159///
160/// Identifies a transaction proof by the sender, transaction hash, and the light client head block hash.
161#[derive(Clone, Debug)]
162pub struct TransactionProofRef {
163    pub sender_id: AccountId,
164    pub transaction_hash: CryptoHash,
165    pub light_client_head: CryptoHash,
166}
167
168/// RPC type for fetching a light client execution proof for a transaction.
169///
170/// Uses the `light_client_proof` RPC method to retrieve the proof needed to verify
171/// a transaction execution against a light client block.
172#[derive(Clone, Debug)]
173pub struct TransactionProofRpc;
174
175#[async_trait::async_trait]
176impl RpcType for TransactionProofRpc {
177    type RpcReference = TransactionProofRef;
178    type Response = RpcLightClientExecutionProofResponse;
179    type Error = RpcLightClientProofError;
180
181    async fn send_query(
182        &self,
183        client: &Client,
184        _network: &NetworkConfig,
185        reference: &TransactionProofRef,
186    ) -> RetryResponse<
187        RpcLightClientExecutionProofResponse,
188        SendRequestError<RpcLightClientProofError>,
189    > {
190        let response = client
191            .light_client_proof(&JsonRpcRequestForLightClientProof {
192                id: "0".to_string(),
193                jsonrpc: "2.0".to_string(),
194                method: JsonRpcRequestForLightClientProofMethod::LightClientProof,
195                params: RpcLightClientExecutionProofRequest::Variant0 {
196                    sender_id: reference.sender_id.clone(),
197                    transaction_hash: reference.transaction_hash.into(),
198                    light_client_head: reference.light_client_head.into(),
199                    type_: RpcLightClientExecutionProofRequestVariant0Type::Transaction,
200                },
201            })
202            .await
203            .map(|r| r.into_inner())
204            .map_err(SendRequestError::from);
205
206        match response {
207            Ok(
208                JsonRpcResponseForRpcLightClientExecutionProofResponseAndRpcLightClientProofError::Variant0 {
209                    result,
210                    ..
211                },
212            ) => RetryResponse::Ok(result),
213            Ok(
214                JsonRpcResponseForRpcLightClientExecutionProofResponseAndRpcLightClientProofError::Variant1 {
215                    error,
216                    ..
217                },
218            ) => {
219                let error = SendRequestError::from(error);
220                to_retry_error(error, is_critical_light_client_proof_error)
221            }
222            Err(err) => to_retry_error(err, is_critical_light_client_proof_error),
223        }
224    }
225}
226
227impl From<ErrorWrapperForRpcLightClientProofError> for SendRequestError<RpcLightClientProofError> {
228    fn from(err: ErrorWrapperForRpcLightClientProofError) -> Self {
229        match err {
230            ErrorWrapperForRpcLightClientProofError::InternalError(internal_error) => {
231                Self::InternalError(internal_error)
232            }
233            ErrorWrapperForRpcLightClientProofError::RequestValidationError(
234                rpc_request_validation_error_kind,
235            ) => Self::RequestValidationError(rpc_request_validation_error_kind),
236            ErrorWrapperForRpcLightClientProofError::HandlerError(server_error) => {
237                Self::ServerError(server_error)
238            }
239        }
240    }
241}