1use anyhow::anyhow;
5use serde::{Serialize, de::DeserializeOwned};
6use std::{path::PathBuf, str::FromStr};
7use sui_types::digests::TransactionDigest;
8use typed_store::rocks::{DBMap, MetricConf};
9use typed_store::traits::Map;
10
11use crate::get_db_entries;
12use move_core_types::language_storage::ModuleId;
13use std::fmt::Debug;
14use sui_core::jsonrpc_index::IndexStoreTables;
15use sui_types::{
16 Identifier,
17 base_types::{ObjectID, SuiAddress, TxSequenceNumber},
18};
19
20#[derive(Clone, Debug)]
21pub enum SearchRange<T: Serialize + Clone + Debug> {
22 ExclusiveLastKey(T),
23 Count(u64),
24}
25
26impl<T: Serialize + Clone + Debug + FromStr> FromStr for SearchRange<T>
27where
28 <T as std::str::FromStr>::Err: std::fmt::Debug,
29{
30 type Err = anyhow::Error;
31
32 fn from_str(s: &str) -> Result<Self, Self::Err> {
33 let last_key = T::from_str(s).map_err(|e| anyhow!("Failed to parse last_key: {:?}", e))?;
34 Ok(SearchRange::ExclusiveLastKey(last_key))
35 }
36}
37
38pub fn search_index(
41 db_path: PathBuf,
42 table_name: String,
43 start: String,
44 termination: SearchRange<String>,
45) -> Result<Vec<(String, String)>, anyhow::Error> {
46 let start = start.as_str();
47 println!("Opening db at {:?} ...", db_path);
48 let db_read_only_handle =
49 IndexStoreTables::get_read_only_handle(db_path, None, None, MetricConf::default());
50 match table_name.as_str() {
51 "transactions_from_addr" => {
52 get_db_entries!(
53 db_read_only_handle.transactions_from_addr,
54 from_addr_seq,
55 start,
56 termination
57 )
58 }
59 "transactions_to_addr" => {
60 get_db_entries!(
61 db_read_only_handle.transactions_to_addr,
62 from_addr_seq,
63 start,
64 termination
65 )
66 }
67 "transactions_by_input_object_id" => {
68 get_db_entries!(
69 db_read_only_handle.transactions_by_input_object_id,
70 from_id_seq,
71 start,
72 termination
73 )
74 }
75 "transactions_by_mutated_object_id" => {
76 get_db_entries!(
77 db_read_only_handle.transactions_by_mutated_object_id,
78 from_id_seq,
79 start,
80 termination
81 )
82 }
83 "transactions_by_move_function" => {
84 get_db_entries!(
85 db_read_only_handle.transactions_by_move_function,
86 from_id_module_function_txseq,
87 start,
88 termination
89 )
90 }
91 "transaction_order" => {
92 get_db_entries!(
93 db_read_only_handle.transaction_order,
94 u64::from_str,
95 start,
96 termination
97 )
98 }
99 "transactions_seq" => {
100 get_db_entries!(
101 db_read_only_handle.transactions_seq,
102 TransactionDigest::from_str,
103 start,
104 termination
105 )
106 }
107 "owner_index" => {
108 get_db_entries!(
109 db_read_only_handle.owner_index,
110 from_addr_oid,
111 start,
112 termination
113 )
114 }
115 "dynamic_field_index" => {
116 get_db_entries!(
117 db_read_only_handle.dynamic_field_index,
118 from_oid_oid,
119 start,
120 termination
121 )
122 }
123 "event_by_event_module" => {
124 get_db_entries!(
125 db_read_only_handle.event_by_event_module,
126 from_module_id_and_event_id,
127 start,
128 termination
129 )
130 }
131 "event_by_move_module" => {
132 get_db_entries!(
133 db_read_only_handle.event_by_move_module,
134 from_module_id_and_event_id,
135 start,
136 termination
137 )
138 }
139 "event_order" => {
140 get_db_entries!(
141 db_read_only_handle.event_order,
142 from_event_id,
143 start,
144 termination
145 )
146 }
147 "event_by_sender" => {
148 get_db_entries!(
149 db_read_only_handle.event_by_sender,
150 from_address_and_event_id,
151 start,
152 termination
153 )
154 }
155 _ => Err(anyhow!("Invalid or unsupported table: {}", table_name)),
156 }
157}
158
159#[macro_export]
160macro_rules! get_db_entries {
161 ($db_map:expr, $key_converter:expr, $start:expr, $term:expr) => {{
162 let key = $key_converter($start)?;
163 println!("Searching from key: {:?}", key);
164 let termination = match $term {
165 SearchRange::ExclusiveLastKey(last_key) => {
166 println!(
167 "Retrieving all keys up to (but not including) key: {:?}",
168 key
169 );
170 SearchRange::ExclusiveLastKey($key_converter(last_key.as_str())?)
171 }
172 SearchRange::Count(count) => {
173 println!("Retrieving up to {} keys", count);
174 SearchRange::Count(count)
175 }
176 };
177
178 $db_map.try_catch_up_with_primary().unwrap();
179 get_entries_to_str(&$db_map, key, termination)
180 }};
181}
182
183fn get_entries_to_str<K, V>(
184 db_map: &DBMap<K, V>,
185 start: K,
186 termination: SearchRange<K>,
187) -> Result<Vec<(String, String)>, anyhow::Error>
188where
189 K: Serialize + serde::de::DeserializeOwned + Clone + Debug,
190 V: serde::Serialize + DeserializeOwned + Clone + Debug,
191{
192 get_entries(db_map, start, termination).map(|entries| {
193 entries
194 .into_iter()
195 .map(|(k, v)| (format!("{:?}", k), format!("{:?}", v)))
196 .collect()
197 })
198}
199
200fn get_entries<K, V>(
201 db_map: &DBMap<K, V>,
202 start: K,
203 termination: SearchRange<K>,
204) -> Result<Vec<(K, V)>, anyhow::Error>
205where
206 K: Serialize + serde::de::DeserializeOwned + Clone + std::fmt::Debug,
207 V: serde::Serialize + DeserializeOwned + Clone,
208{
209 let mut entries = Vec::new();
210 match termination {
211 SearchRange::ExclusiveLastKey(exclusive_last_key) => {
212 let iter = db_map.safe_iter_with_bounds(Some(start), Some(exclusive_last_key));
213
214 for result in iter {
215 let (key, value) = result?;
216 entries.push((key.clone(), value.clone()));
217 }
218 }
219 SearchRange::Count(mut count) => {
220 let mut iter = db_map.safe_iter_with_bounds(Some(start), None);
221
222 while count > 0 {
223 if let Some(result) = iter.next() {
224 let (key, value) = result?;
225 entries.push((key.clone(), value.clone()));
226 } else {
227 break;
228 }
229 count -= 1;
230 }
231 }
232 }
233 Ok(entries)
234}
235
236fn from_addr_seq(s: &str) -> Result<(SuiAddress, TxSequenceNumber), anyhow::Error> {
237 let s = s.trim();
239 let tokens = s.split(',').collect::<Vec<&str>>();
240 if tokens.len() != 2 {
241 return Err(anyhow!("Invalid address, sequence number pair"));
242 }
243 let address = SuiAddress::from_str(tokens[0].trim())?;
244 let sequence_number = TxSequenceNumber::from_str(tokens[1].trim())?;
245
246 Ok((address, sequence_number))
247}
248
249fn from_id_seq(s: &str) -> Result<(ObjectID, TxSequenceNumber), anyhow::Error> {
250 let s = s.trim();
252 let tokens = s.split(',').collect::<Vec<&str>>();
253 if tokens.len() != 2 {
254 return Err(anyhow!("Invalid object id, sequence number pair"));
255 }
256 let oid = ObjectID::from_str(tokens[0].trim())?;
257 let sequence_number = TxSequenceNumber::from_str(tokens[1].trim())?;
258
259 Ok((oid, sequence_number))
260}
261
262fn from_id_module_function_txseq(
263 s: &str,
264) -> Result<(ObjectID, String, String, TxSequenceNumber), anyhow::Error> {
265 let s = s.trim();
267 let tokens = s.split(',').collect::<Vec<&str>>();
268 if tokens.len() != 4 {
269 return Err(anyhow!(
270 "Invalid object id, module name, function name, TX sequence number quad"
271 ));
272 }
273 let pid = ObjectID::from_str(tokens[0].trim())?;
274 let module: Identifier = Identifier::from_str(tokens[1].trim())?;
275 let func: Identifier = Identifier::from_str(tokens[2].trim())?;
276 let seq: TxSequenceNumber = TxSequenceNumber::from_str(tokens[3].trim())?;
277
278 Ok((pid, module.to_string(), func.to_string(), seq))
279}
280
281fn from_addr_oid(s: &str) -> Result<(SuiAddress, ObjectID), anyhow::Error> {
282 let s = s.trim();
284 let tokens = s.split(',').collect::<Vec<&str>>();
285 if tokens.len() != 2 {
286 return Err(anyhow!("Invalid address, object id pair"));
287 }
288 let addr = SuiAddress::from_str(tokens[0].trim())?;
289 let oid = ObjectID::from_str(tokens[1].trim())?;
290
291 Ok((addr, oid))
292}
293
294fn from_oid_oid(s: &str) -> Result<(ObjectID, ObjectID), anyhow::Error> {
295 let s = s.trim();
297 let tokens = s.split(',').collect::<Vec<&str>>();
298 if tokens.len() != 2 {
299 return Err(anyhow!("Invalid object id, object id triplet"));
300 }
301 let oid1 = ObjectID::from_str(tokens[0].trim())?;
302 let oid2: ObjectID = ObjectID::from_str(tokens[1].trim())?;
303
304 Ok((oid1, oid2))
305}
306
307fn from_module_id_and_event_id(
308 s: &str,
309) -> Result<(ModuleId, (TxSequenceNumber, usize)), anyhow::Error> {
310 let tokens = s.split(' ').collect::<Vec<&str>>();
312 if tokens.len() != 3 {
313 return Err(anyhow!("Invalid input"));
314 }
315 let tx_seq = TxSequenceNumber::from_str(tokens[1])?;
316 let event_seq = usize::from_str(tokens[2])?;
317 let tokens = tokens[0].split("::").collect::<Vec<&str>>();
318 if tokens.len() != 2 {
319 return Err(anyhow!("Invalid module id"));
320 }
321 let package = ObjectID::from_str(tokens[0].trim())?;
322
323 Ok((
324 ModuleId::new(package.into(), Identifier::from_str(tokens[1].trim())?),
325 (tx_seq, event_seq),
326 ))
327}
328
329fn from_event_id(s: &str) -> Result<(TxSequenceNumber, usize), anyhow::Error> {
330 let tokens = s.split(' ').collect::<Vec<&str>>();
332 if tokens.len() != 2 {
333 return Err(anyhow!("Invalid input"));
334 }
335 let tx_seq = TxSequenceNumber::from_str(tokens[0])?;
336 let event_seq = usize::from_str(tokens[1])?;
337 Ok((tx_seq, event_seq))
338}
339
340fn from_address_and_event_id(
341 s: &str,
342) -> Result<(SuiAddress, (TxSequenceNumber, usize)), anyhow::Error> {
343 let tokens = s.split(' ').collect::<Vec<&str>>();
345 if tokens.len() != 3 {
346 return Err(anyhow!("Invalid input"));
347 }
348 let tx_seq = TxSequenceNumber::from_str(tokens[1])?;
349 let event_seq = usize::from_str(tokens[2])?;
350 let address = SuiAddress::from_str(tokens[0].trim())?;
351 Ok((address, (tx_seq, event_seq)))
352}