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