sui_indexer_alt_jsonrpc/api/transactions/
mod.rs1use futures::future;
5use jsonrpsee::core::RpcResult;
6use jsonrpsee::proc_macros::rpc;
7use mysten_common::ZipDebugEqIteratorExt;
8use sui_json_rpc_types::Page;
9use sui_json_rpc_types::SuiTransactionBlockResponse;
10use sui_json_rpc_types::SuiTransactionBlockResponseOptions;
11use sui_open_rpc::Module;
12use sui_open_rpc_macros::open_rpc;
13use sui_types::digests::TransactionDigest;
14
15use crate::api::rpc_module::RpcModule;
16use crate::api::transactions::error::Error;
17use crate::api::transactions::filter::SuiTransactionBlockResponseQuery;
18use crate::context::Context;
19use crate::error::InternalContext;
20use crate::error::RpcError;
21use crate::error::rpc_bail;
22
23mod error;
24mod filter;
25mod response;
26
27#[open_rpc(namespace = "sui", tag = "Transactions API")]
28#[rpc(server, namespace = "sui")]
29trait TransactionsApi {
30 #[method(name = "getTransactionBlock")]
32 async fn get_transaction_block(
33 &self,
34 digest: TransactionDigest,
36 options: Option<SuiTransactionBlockResponseOptions>,
38 ) -> RpcResult<SuiTransactionBlockResponse>;
39}
40
41#[open_rpc(namespace = "suix", tag = "Query Transactions API")]
42#[rpc(server, namespace = "suix")]
43trait QueryTransactionsApi {
44 #[method(name = "queryTransactionBlocks")]
56 async fn query_transaction_blocks(
57 &self,
58 query: SuiTransactionBlockResponseQuery,
60 cursor: Option<String>,
62 limit: Option<usize>,
64 descending_order: Option<bool>,
66 ) -> RpcResult<Page<SuiTransactionBlockResponse, String>>;
67}
68
69pub(crate) struct Transactions(pub Context);
70
71pub(crate) struct QueryTransactions(pub Context);
72
73#[async_trait::async_trait]
74impl TransactionsApiServer for Transactions {
75 async fn get_transaction_block(
76 &self,
77 digest: TransactionDigest,
78 options: Option<SuiTransactionBlockResponseOptions>,
79 ) -> RpcResult<SuiTransactionBlockResponse> {
80 let Self(ctx) = self;
81 Ok(
82 response::transaction(ctx, digest, &options.unwrap_or_default())
83 .await
84 .with_internal_context(|| format!("Failed to get transaction {digest}"))?,
85 )
86 }
87}
88
89#[async_trait::async_trait]
90impl QueryTransactionsApiServer for QueryTransactions {
91 async fn query_transaction_blocks(
92 &self,
93 query: SuiTransactionBlockResponseQuery,
94 cursor: Option<String>,
95 limit: Option<usize>,
96 descending_order: Option<bool>,
97 ) -> RpcResult<Page<SuiTransactionBlockResponse, String>> {
98 let Self(ctx) = self;
99
100 let Page {
101 data: digests,
102 next_cursor,
103 has_next_page,
104 } = filter::transactions(ctx, &query.filter, cursor.clone(), limit, descending_order)
105 .await?;
106
107 let options = query.options.unwrap_or_default();
108
109 let tx_futures = digests.iter().map(|d| {
110 async {
111 let mut tx = response::transaction(ctx, *d, &options).await;
112
113 let config = &ctx.config().transactions;
114 let mut interval = tokio::time::interval(std::time::Duration::from_millis(
115 config.tx_retry_interval_ms,
116 ));
117
118 let mut retries = 0;
119 for _ in 0..config.tx_retry_count {
120 if let Err(RpcError::InvalidParams(
123 _e @ (Error::BalanceChangesNotFound(_) | Error::NotFound(_)),
124 )) = tx
125 {
126 interval.tick().await;
127 retries += 1;
128 tx = response::transaction(ctx, *d, &options).await;
129 ctx.metrics()
130 .read_retries
131 .with_label_values(&["tx_response"])
132 .inc();
133 } else {
134 break;
135 }
136 }
137
138 ctx.metrics()
139 .read_retries_per_request
140 .with_label_values(&["tx_response"])
141 .observe(retries as f64);
142 tx
143 }
144 });
145
146 let data = future::join_all(tx_futures)
147 .await
148 .into_iter()
149 .zip_debug_eq(digests)
150 .map(|(r, d)| {
151 if let Err(RpcError::InvalidParams(e @ Error::NotFound(_))) = r {
152 rpc_bail!(e)
153 } else {
154 r.with_internal_context(|| format!("Failed to get transaction {d}"))
155 }
156 })
157 .collect::<Result<Vec<_>, _>>()?;
158
159 Ok(Page {
160 data,
161 next_cursor: next_cursor.or(cursor),
162 has_next_page,
163 })
164 }
165}
166
167impl RpcModule for Transactions {
168 fn schema(&self) -> Module {
169 TransactionsApiOpenRpc::module_doc()
170 }
171
172 fn into_impl(self) -> jsonrpsee::RpcModule<Self> {
173 self.into_rpc()
174 }
175}
176
177impl RpcModule for QueryTransactions {
178 fn schema(&self) -> Module {
179 QueryTransactionsApiOpenRpc::module_doc()
180 }
181
182 fn into_impl(self) -> jsonrpsee::RpcModule<Self> {
183 self.into_rpc()
184 }
185}