near_jsonrpc_primitives/types/
transactions.rs

1use near_primitives::hash::CryptoHash;
2use near_primitives::types::AccountId;
3use serde_json::Value;
4
5#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
6#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
7pub struct RpcSendTransactionRequest {
8    #[serde(rename = "signed_tx_base64")]
9    pub signed_transaction: near_primitives::transaction::SignedTransaction,
10    #[serde(default)]
11    pub wait_until: near_primitives::views::TxExecutionStatus,
12}
13
14#[derive(Debug, serde::Serialize, serde::Deserialize)]
15#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
16pub struct RpcTransactionStatusRequest {
17    #[serde(flatten)]
18    pub transaction_info: TransactionInfo,
19    #[serde(default)]
20    pub wait_until: near_primitives::views::TxExecutionStatus,
21}
22
23#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
24#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
25#[serde(untagged)]
26#[allow(clippy::large_enum_variant)]
27pub enum TransactionInfo {
28    Transaction {
29        #[serde(rename = "signed_tx_base64")]
30        signed_tx: near_primitives::transaction::SignedTransaction,
31    },
32    TransactionId {
33        tx_hash: CryptoHash,
34        sender_account_id: AccountId,
35    },
36}
37
38#[derive(thiserror::Error, Debug, Clone, serde::Serialize, serde::Deserialize)]
39#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
40#[serde(tag = "name", content = "info", rename_all = "SCREAMING_SNAKE_CASE")]
41pub enum RpcTransactionError {
42    #[error("An error happened during transaction execution: {context:?}")]
43    InvalidTransaction {
44        #[serde(skip_serializing)]
45        context: near_primitives::errors::InvalidTxError,
46    },
47    #[error("Node doesn't track this shard. Cannot determine whether the transaction is valid")]
48    DoesNotTrackShard,
49    #[error("Transaction with hash {transaction_hash} was routed")]
50    RequestRouted { transaction_hash: near_primitives::hash::CryptoHash },
51    #[error("Transaction {requested_transaction_hash} doesn't exist")]
52    UnknownTransaction { requested_transaction_hash: near_primitives::hash::CryptoHash },
53    #[error("The node reached its limits. Try again later. More details: {debug_info}")]
54    InternalError { debug_info: String },
55    #[error("Timeout")]
56    TimeoutError,
57}
58
59#[derive(serde::Serialize, serde::Deserialize, Debug)]
60#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
61pub struct RpcTransactionResponse {
62    #[serde(flatten)]
63    pub final_execution_outcome: Option<near_primitives::views::FinalExecutionOutcomeViewEnum>,
64    pub final_execution_status: near_primitives::views::TxExecutionStatus,
65}
66
67#[derive(serde::Serialize, serde::Deserialize, Debug)]
68#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
69pub struct RpcBroadcastTxSyncResponse {
70    pub transaction_hash: near_primitives::hash::CryptoHash,
71}
72
73impl TransactionInfo {
74    pub fn from_signed_tx(signed_tx: near_primitives::transaction::SignedTransaction) -> Self {
75        Self::Transaction { signed_tx }
76    }
77
78    pub fn to_signed_tx(&self) -> Option<&near_primitives::transaction::SignedTransaction> {
79        match self {
80            TransactionInfo::Transaction { signed_tx } => Some(signed_tx),
81            TransactionInfo::TransactionId { .. } => None,
82        }
83    }
84
85    pub fn to_tx_hash_and_account(&self) -> (CryptoHash, &AccountId) {
86        match self {
87            TransactionInfo::Transaction { signed_tx } => {
88                (signed_tx.get_hash(), &signed_tx.transaction.signer_id())
89            }
90            TransactionInfo::TransactionId { tx_hash, sender_account_id } => {
91                (*tx_hash, sender_account_id)
92            }
93        }
94    }
95}
96
97impl From<near_primitives::transaction::SignedTransaction> for TransactionInfo {
98    fn from(signed_tx: near_primitives::transaction::SignedTransaction) -> Self {
99        Self::Transaction { signed_tx }
100    }
101}
102
103impl From<near_primitives::views::TxStatusView> for RpcTransactionResponse {
104    fn from(view: near_primitives::views::TxStatusView) -> Self {
105        Self {
106            final_execution_outcome: view.execution_outcome,
107            final_execution_status: view.status,
108        }
109    }
110}
111
112impl From<RpcTransactionError> for crate::errors::RpcError {
113    fn from(error: RpcTransactionError) -> Self {
114        let error_data = match &error {
115            RpcTransactionError::InvalidTransaction { context } => {
116                if let Ok(value) =
117                    serde_json::to_value(crate::errors::ServerError::TxExecutionError(
118                        near_primitives::errors::TxExecutionError::InvalidTxError(context.clone()),
119                    ))
120                {
121                    value
122                } else {
123                    Value::String(error.to_string())
124                }
125            }
126            _ => Value::String(error.to_string()),
127        };
128
129        let error_data_value = match serde_json::to_value(error) {
130            Ok(value) => value,
131            Err(err) => {
132                return Self::new_internal_error(
133                    None,
134                    format!("Failed to serialize RpcTransactionError: {:?}", err),
135                );
136            }
137        };
138
139        Self::new_internal_or_handler_error(Some(error_data), error_data_value)
140    }
141}