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(_e @ Error::NotFound(_))) = tx {
123 interval.tick().await;
124 retries += 1;
125 tx = response::transaction(ctx, *d, &options).await;
126 ctx.metrics()
127 .read_retries
128 .with_label_values(&["tx_response"])
129 .inc();
130 } else {
131 break;
132 }
133 }
134
135 ctx.metrics()
136 .read_retries_per_request
137 .with_label_values(&["tx_response"])
138 .observe(retries as f64);
139 tx
140 }
141 });
142
143 let data = future::join_all(tx_futures)
144 .await
145 .into_iter()
146 .zip_debug_eq(digests)
147 .map(|(r, d)| {
148 if let Err(RpcError::InvalidParams(e @ Error::NotFound(_))) = r {
149 rpc_bail!(e)
150 } else {
151 r.with_internal_context(|| format!("Failed to get transaction {d}"))
152 }
153 })
154 .collect::<Result<Vec<_>, _>>()?;
155
156 Ok(Page {
157 data,
158 next_cursor: next_cursor.or(cursor),
159 has_next_page,
160 })
161 }
162}
163
164impl RpcModule for Transactions {
165 fn schema(&self) -> Module {
166 TransactionsApiOpenRpc::module_doc()
167 }
168
169 fn into_impl(self) -> jsonrpsee::RpcModule<Self> {
170 self.into_rpc()
171 }
172}
173
174impl RpcModule for QueryTransactions {
175 fn schema(&self) -> Module {
176 QueryTransactionsApiOpenRpc::module_doc()
177 }
178
179 fn into_impl(self) -> jsonrpsee::RpcModule<Self> {
180 self.into_rpc()
181 }
182}