1use arc_swap::Guard;
5use async_trait::async_trait;
6use move_core_types::language_storage::TypeTag;
7use std::collections::{BTreeMap, HashMap};
8use std::sync::Arc;
9use sui_core::accumulators::balances::{get_all_balances_for_owner, get_balance};
10use sui_core::authority::AuthorityState;
11use sui_core::authority::authority_per_epoch_store::AuthorityPerEpochStore;
12use sui_core::execution_cache::ObjectCacheRead;
13use sui_core::jsonrpc_index::TotalBalance;
14use sui_core::subscription_handler::SubscriptionHandler;
15use sui_json_rpc_types::{
16 Coin as SuiCoin, DevInspectResults, DryRunTransactionBlockResponse, EventFilter, SuiEvent,
17 SuiObjectDataFilter, TransactionFilter,
18};
19use sui_storage::key_value_store::{
20 KVStoreTransactionData, TransactionKeyValueStore, TransactionKeyValueStoreTrait,
21};
22use sui_types::base_types::{
23 MoveObjectType, ObjectID, ObjectInfo, ObjectRef, SequenceNumber, SuiAddress,
24};
25use sui_types::bridge::Bridge;
26use sui_types::committee::{Committee, EpochId};
27use sui_types::digests::{ChainIdentifier, TransactionDigest};
28use sui_types::dynamic_field::DynamicFieldInfo;
29use sui_types::effects::TransactionEffects;
30use sui_types::error::{SuiError, SuiErrorKind, SuiResult, UserInputError};
31use sui_types::event::EventID;
32use sui_types::governance::StakedSui;
33use sui_types::messages_checkpoint::{
34 CheckpointContents, CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber,
35 VerifiedCheckpoint,
36};
37use sui_types::object::{Object, ObjectRead, PastObjectRead};
38use sui_types::storage::{BackingPackageStore, ObjectStore, WriteKind};
39use sui_types::sui_serde::BigInt;
40use sui_types::sui_system_state::SuiSystemState;
41use sui_types::transaction::{Transaction, TransactionData, TransactionKind};
42use thiserror::Error;
43use tokio::task::JoinError;
44
45use crate::ObjectProvider;
46#[cfg(test)]
47use mockall::automock;
48use typed_store_error::TypedStoreError;
49
50pub type StateReadResult<T = ()> = Result<T, StateReadError>;
51
52#[cfg_attr(test, automock)]
54#[async_trait]
55pub trait StateRead: Send + Sync {
56 async fn multi_get(
57 &self,
58 transactions: &[TransactionDigest],
59 effects: &[TransactionDigest],
60 ) -> StateReadResult<KVStoreTransactionData>;
61
62 fn get_object_read(&self, object_id: &ObjectID) -> StateReadResult<ObjectRead>;
63
64 fn get_past_object_read(
65 &self,
66 object_id: &ObjectID,
67 version: SequenceNumber,
68 ) -> StateReadResult<PastObjectRead>;
69
70 async fn get_object(&self, object_id: &ObjectID) -> StateReadResult<Option<Object>>;
71
72 fn load_epoch_store_one_call_per_task(&self) -> Guard<Arc<AuthorityPerEpochStore>>;
73
74 fn get_dynamic_fields(
75 &self,
76 owner: ObjectID,
77 cursor: Option<ObjectID>,
78 limit: usize,
79 ) -> StateReadResult<Vec<(ObjectID, DynamicFieldInfo)>>;
80
81 fn get_cache_reader(&self) -> &Arc<dyn ObjectCacheRead>;
82
83 fn get_object_store(&self) -> &Arc<dyn ObjectStore + Send + Sync>;
84
85 fn get_backing_package_store(&self) -> &Arc<dyn BackingPackageStore + Send + Sync>;
86
87 fn get_owner_objects(
88 &self,
89 owner: SuiAddress,
90 cursor: Option<ObjectID>,
91 filter: Option<SuiObjectDataFilter>,
92 ) -> StateReadResult<Vec<ObjectInfo>>;
93
94 async fn query_events(
95 &self,
96 kv_store: &Arc<TransactionKeyValueStore>,
97 query: EventFilter,
98 cursor: Option<EventID>,
100 limit: usize,
101 descending: bool,
102 ) -> StateReadResult<Vec<SuiEvent>>;
103
104 #[allow(clippy::type_complexity)]
106 async fn dry_exec_transaction(
107 &self,
108 transaction: TransactionData,
109 transaction_digest: TransactionDigest,
110 ) -> StateReadResult<(
111 DryRunTransactionBlockResponse,
112 BTreeMap<ObjectID, (ObjectRef, Object, WriteKind)>,
113 TransactionEffects,
114 Option<ObjectID>,
115 )>;
116
117 async fn dev_inspect_transaction_block(
118 &self,
119 sender: SuiAddress,
120 transaction_kind: TransactionKind,
121 gas_price: Option<u64>,
122 gas_budget: Option<u64>,
123 gas_sponsor: Option<SuiAddress>,
124 gas_objects: Option<Vec<ObjectRef>>,
125 show_raw_txn_data_and_effects: Option<bool>,
126 skip_checks: Option<bool>,
127 ) -> StateReadResult<DevInspectResults>;
128
129 fn get_subscription_handler(&self) -> Arc<SubscriptionHandler>;
131
132 fn get_owner_objects_with_limit(
133 &self,
134 owner: SuiAddress,
135 cursor: Option<ObjectID>,
136 limit: usize,
137 filter: Option<SuiObjectDataFilter>,
138 ) -> StateReadResult<Vec<ObjectInfo>>;
139
140 async fn get_transactions(
141 &self,
142 kv_store: &Arc<TransactionKeyValueStore>,
143 filter: Option<TransactionFilter>,
144 cursor: Option<TransactionDigest>,
145 limit: Option<usize>,
146 reverse: bool,
147 ) -> StateReadResult<Vec<TransactionDigest>>;
148
149 fn get_dynamic_field_object_id(
150 &self,
151 owner: ObjectID,
152 name_type: TypeTag,
153 name_bcs_bytes: &[u8],
154 ) -> StateReadResult<Option<ObjectID>>;
155
156 async fn get_staked_sui(&self, owner: SuiAddress) -> StateReadResult<Vec<StakedSui>>;
158 fn get_system_state(&self) -> StateReadResult<SuiSystemState>;
159 fn get_or_latest_committee(&self, epoch: Option<BigInt<u64>>) -> StateReadResult<Committee>;
160
161 fn get_bridge(&self) -> StateReadResult<Bridge>;
163
164 fn find_publish_txn_digest(&self, package_id: ObjectID) -> StateReadResult<TransactionDigest>;
166 fn get_owned_coins(
167 &self,
168 owner: SuiAddress,
169 cursor: (String, u64, ObjectID),
170 limit: usize,
171 one_coin_type_only: bool,
172 ) -> StateReadResult<Vec<SuiCoin>>;
173 async fn get_executed_transaction_and_effects(
174 &self,
175 digest: TransactionDigest,
176 kv_store: Arc<TransactionKeyValueStore>,
177 ) -> StateReadResult<(Transaction, TransactionEffects)>;
178 async fn get_balance(
179 &self,
180 owner: SuiAddress,
181 coin_type: TypeTag,
182 ) -> StateReadResult<TotalBalance>;
183 async fn get_all_balance(
184 &self,
185 owner: SuiAddress,
186 ) -> StateReadResult<Arc<HashMap<TypeTag, TotalBalance>>>;
187
188 fn get_verified_checkpoint_by_sequence_number(
190 &self,
191 sequence_number: CheckpointSequenceNumber,
192 ) -> StateReadResult<VerifiedCheckpoint>;
193
194 fn get_checkpoint_contents(
195 &self,
196 digest: CheckpointContentsDigest,
197 ) -> StateReadResult<CheckpointContents>;
198
199 fn get_verified_checkpoint_summary_by_digest(
200 &self,
201 digest: CheckpointDigest,
202 ) -> StateReadResult<VerifiedCheckpoint>;
203
204 fn deprecated_multi_get_transaction_checkpoint(
205 &self,
206 digests: &[TransactionDigest],
207 ) -> StateReadResult<Vec<Option<(EpochId, CheckpointSequenceNumber)>>>;
208
209 fn deprecated_get_transaction_checkpoint(
210 &self,
211 digest: &TransactionDigest,
212 ) -> StateReadResult<Option<(EpochId, CheckpointSequenceNumber)>>;
213
214 fn multi_get_checkpoint_by_sequence_number(
215 &self,
216 sequence_numbers: &[CheckpointSequenceNumber],
217 ) -> StateReadResult<Vec<Option<VerifiedCheckpoint>>>;
218
219 fn get_total_transaction_blocks(&self) -> StateReadResult<u64>;
220
221 fn get_checkpoint_by_sequence_number(
222 &self,
223 sequence_number: CheckpointSequenceNumber,
224 ) -> StateReadResult<Option<VerifiedCheckpoint>>;
225
226 fn get_latest_checkpoint_sequence_number(&self) -> StateReadResult<CheckpointSequenceNumber>;
227
228 fn get_chain_identifier(&self) -> StateReadResult<ChainIdentifier>;
229}
230
231#[async_trait]
232impl StateRead for AuthorityState {
233 async fn multi_get(
234 &self,
235 transactions: &[TransactionDigest],
236 effects: &[TransactionDigest],
237 ) -> StateReadResult<KVStoreTransactionData> {
238 Ok(
239 <AuthorityState as TransactionKeyValueStoreTrait>::multi_get(
240 self,
241 transactions,
242 effects,
243 )
244 .await?,
245 )
246 }
247
248 fn get_object_read(&self, object_id: &ObjectID) -> StateReadResult<ObjectRead> {
249 Ok(self.get_object_read(object_id)?)
250 }
251
252 async fn get_object(&self, object_id: &ObjectID) -> StateReadResult<Option<Object>> {
253 Ok(self.get_object(object_id).await)
254 }
255
256 fn get_past_object_read(
257 &self,
258 object_id: &ObjectID,
259 version: SequenceNumber,
260 ) -> StateReadResult<PastObjectRead> {
261 Ok(self.get_past_object_read(object_id, version)?)
262 }
263
264 fn load_epoch_store_one_call_per_task(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
265 self.load_epoch_store_one_call_per_task()
266 }
267
268 fn get_dynamic_fields(
269 &self,
270 owner: ObjectID,
271 cursor: Option<ObjectID>,
272 limit: usize,
273 ) -> StateReadResult<Vec<(ObjectID, DynamicFieldInfo)>> {
274 Ok(self.get_dynamic_fields(owner, cursor, limit)?)
275 }
276
277 fn get_cache_reader(&self) -> &Arc<dyn ObjectCacheRead> {
278 self.get_object_cache_reader()
279 }
280
281 fn get_object_store(&self) -> &Arc<dyn ObjectStore + Send + Sync> {
282 self.get_object_store()
283 }
284
285 fn get_backing_package_store(&self) -> &Arc<dyn BackingPackageStore + Send + Sync> {
286 self.get_backing_package_store()
287 }
288
289 fn get_owner_objects(
290 &self,
291 owner: SuiAddress,
292 cursor: Option<ObjectID>,
293 filter: Option<SuiObjectDataFilter>,
294 ) -> StateReadResult<Vec<ObjectInfo>> {
295 Ok(self
296 .get_owner_objects_iterator(owner, cursor, filter)?
297 .collect())
298 }
299
300 async fn query_events(
301 &self,
302 kv_store: &Arc<TransactionKeyValueStore>,
303 query: EventFilter,
304 cursor: Option<EventID>,
306 limit: usize,
307 descending: bool,
308 ) -> StateReadResult<Vec<SuiEvent>> {
309 Ok(self
310 .query_events(kv_store, query, cursor, limit, descending)
311 .await?)
312 }
313
314 #[allow(clippy::type_complexity)]
315 async fn dry_exec_transaction(
316 &self,
317 transaction: TransactionData,
318 transaction_digest: TransactionDigest,
319 ) -> StateReadResult<(
320 DryRunTransactionBlockResponse,
321 BTreeMap<ObjectID, (ObjectRef, Object, WriteKind)>,
322 TransactionEffects,
323 Option<ObjectID>,
324 )> {
325 Ok(self
326 .dry_exec_transaction(transaction, transaction_digest)
327 .await?)
328 }
329
330 async fn dev_inspect_transaction_block(
331 &self,
332 sender: SuiAddress,
333 transaction_kind: TransactionKind,
334 gas_price: Option<u64>,
335 gas_budget: Option<u64>,
336 gas_sponsor: Option<SuiAddress>,
337 gas_objects: Option<Vec<ObjectRef>>,
338 show_raw_txn_data_and_effects: Option<bool>,
339 skip_checks: Option<bool>,
340 ) -> StateReadResult<DevInspectResults> {
341 Ok(self
342 .dev_inspect_transaction_block(
343 sender,
344 transaction_kind,
345 gas_price,
346 gas_budget,
347 gas_sponsor,
348 gas_objects,
349 show_raw_txn_data_and_effects,
350 skip_checks,
351 )
352 .await?)
353 }
354
355 fn get_subscription_handler(&self) -> Arc<SubscriptionHandler> {
356 self.subscription_handler.clone()
357 }
358
359 fn get_owner_objects_with_limit(
360 &self,
361 owner: SuiAddress,
362 cursor: Option<ObjectID>,
363 limit: usize,
364 filter: Option<SuiObjectDataFilter>,
365 ) -> StateReadResult<Vec<ObjectInfo>> {
366 Ok(self.get_owner_objects(owner, cursor, limit, filter)?)
367 }
368
369 async fn get_transactions(
370 &self,
371 kv_store: &Arc<TransactionKeyValueStore>,
372 filter: Option<TransactionFilter>,
373 cursor: Option<TransactionDigest>,
374 limit: Option<usize>,
375 reverse: bool,
376 ) -> StateReadResult<Vec<TransactionDigest>> {
377 Ok(self
378 .get_transactions(kv_store, filter, cursor, limit, reverse)
379 .await?)
380 }
381
382 fn get_dynamic_field_object_id(
383 &self,
385 owner: ObjectID,
386 name_type: TypeTag,
387 name_bcs_bytes: &[u8],
388 ) -> StateReadResult<Option<ObjectID>> {
389 Ok(self.get_dynamic_field_object_id(owner, name_type, name_bcs_bytes)?)
390 }
391
392 async fn get_staked_sui(&self, owner: SuiAddress) -> StateReadResult<Vec<StakedSui>> {
393 Ok(self
394 .get_move_objects(owner, MoveObjectType::staked_sui())
395 .await?)
396 }
397 fn get_system_state(&self) -> StateReadResult<SuiSystemState> {
398 Ok(self
399 .get_object_cache_reader()
400 .get_sui_system_state_object_unsafe()?)
401 }
402 fn get_or_latest_committee(&self, epoch: Option<BigInt<u64>>) -> StateReadResult<Committee> {
403 Ok(self
404 .committee_store()
405 .get_or_latest_committee(epoch.map(|e| *e))?)
406 }
407
408 fn get_bridge(&self) -> StateReadResult<Bridge> {
409 self.get_cache_reader()
410 .get_bridge_object_unsafe()
411 .map_err(|err| err.into())
412 }
413
414 fn find_publish_txn_digest(&self, package_id: ObjectID) -> StateReadResult<TransactionDigest> {
415 Ok(self.find_publish_txn_digest(package_id)?)
416 }
417 fn get_owned_coins(
418 &self,
419 owner: SuiAddress,
420 cursor: (String, u64, ObjectID),
421 limit: usize,
422 one_coin_type_only: bool,
423 ) -> StateReadResult<Vec<SuiCoin>> {
424 Ok(self
425 .get_owned_coins_iterator_with_cursor(owner, cursor, limit, one_coin_type_only)?
426 .map(|(key, coin)| SuiCoin {
427 coin_type: key.coin_type,
428 coin_object_id: key.object_id,
429 version: coin.version,
430 digest: coin.digest,
431 balance: coin.balance,
432 previous_transaction: coin.previous_transaction,
433 })
434 .collect())
435 }
436
437 async fn get_executed_transaction_and_effects(
438 &self,
439 digest: TransactionDigest,
440 kv_store: Arc<TransactionKeyValueStore>,
441 ) -> StateReadResult<(Transaction, TransactionEffects)> {
442 Ok(self
443 .get_executed_transaction_and_effects(digest, kv_store)
444 .await?)
445 }
446
447 async fn get_balance(
448 &self,
449 owner: SuiAddress,
450 coin_type: TypeTag,
451 ) -> StateReadResult<TotalBalance> {
452 let indexes = self.indexes.clone();
453 let child_object_resolver = self.get_child_object_resolver().clone();
454 Ok(
455 tokio::task::spawn_blocking(move || -> SuiResult<TotalBalance> {
456 let address_balance =
457 get_balance(owner, child_object_resolver.as_ref(), coin_type.clone())?;
458 let coin_balance = indexes
459 .as_ref()
460 .ok_or(SuiErrorKind::IndexStoreNotAvailable)?
461 .get_coin_object_balance(owner, coin_type)?;
462 let mut total_balance = coin_balance;
463 if address_balance > 0 {
464 total_balance.balance += address_balance as i128;
465 total_balance.num_coins += 1;
466 }
467 total_balance.address_balance = address_balance;
468 Ok(total_balance)
469 })
470 .await
471 .map_err(|e: JoinError| {
472 SuiError(Box::new(SuiErrorKind::ExecutionError(e.to_string())))
473 })??,
474 )
475 }
476
477 async fn get_all_balance(
478 &self,
479 owner: SuiAddress,
480 ) -> StateReadResult<Arc<HashMap<TypeTag, TotalBalance>>> {
481 let indexes = self.indexes.clone();
482 let child_object_resolver = self.get_child_object_resolver().clone();
483 Ok(tokio::task::spawn_blocking(
484 move || -> SuiResult<Arc<HashMap<TypeTag, TotalBalance>>> {
485 let indexes = indexes
486 .as_ref()
487 .ok_or(SuiErrorKind::IndexStoreNotAvailable)?;
488 let address_balances =
489 get_all_balances_for_owner(owner, child_object_resolver.as_ref(), indexes)?;
490 let coin_balances = (*indexes.get_all_coin_object_balances(owner)?).clone();
491 let mut all_balances = coin_balances;
492 for (coin_type, balance) in address_balances {
493 let existing_balance = all_balances.entry(coin_type).or_insert(TotalBalance {
494 balance: 0,
495 num_coins: 0,
496 address_balance: 0,
497 });
498 existing_balance.balance += balance as i128;
499 existing_balance.num_coins += 1;
500 existing_balance.address_balance = balance;
501 }
502 Ok(Arc::new(all_balances))
503 },
504 )
505 .await
506 .map_err(|e: JoinError| {
507 SuiError(Box::new(SuiErrorKind::ExecutionError(e.to_string())))
508 })??)
509 }
510
511 fn get_verified_checkpoint_by_sequence_number(
512 &self,
513 sequence_number: CheckpointSequenceNumber,
514 ) -> StateReadResult<VerifiedCheckpoint> {
515 Ok(self.get_verified_checkpoint_by_sequence_number(sequence_number)?)
516 }
517
518 fn get_checkpoint_contents(
519 &self,
520 digest: CheckpointContentsDigest,
521 ) -> StateReadResult<CheckpointContents> {
522 Ok(self.get_checkpoint_contents(digest)?)
523 }
524
525 fn get_verified_checkpoint_summary_by_digest(
526 &self,
527 digest: CheckpointDigest,
528 ) -> StateReadResult<VerifiedCheckpoint> {
529 Ok(self.get_verified_checkpoint_summary_by_digest(digest)?)
530 }
531
532 fn deprecated_multi_get_transaction_checkpoint(
533 &self,
534 digests: &[TransactionDigest],
535 ) -> StateReadResult<Vec<Option<(EpochId, CheckpointSequenceNumber)>>> {
536 Ok(self
537 .get_checkpoint_cache()
538 .deprecated_multi_get_transaction_checkpoint(digests))
539 }
540
541 fn deprecated_get_transaction_checkpoint(
542 &self,
543 digest: &TransactionDigest,
544 ) -> StateReadResult<Option<(EpochId, CheckpointSequenceNumber)>> {
545 Ok(self
546 .get_checkpoint_cache()
547 .deprecated_get_transaction_checkpoint(digest))
548 }
549
550 fn multi_get_checkpoint_by_sequence_number(
551 &self,
552 sequence_numbers: &[CheckpointSequenceNumber],
553 ) -> StateReadResult<Vec<Option<VerifiedCheckpoint>>> {
554 Ok(self.multi_get_checkpoint_by_sequence_number(sequence_numbers)?)
555 }
556
557 fn get_total_transaction_blocks(&self) -> StateReadResult<u64> {
558 Ok(self.get_total_transaction_blocks()?)
559 }
560
561 fn get_checkpoint_by_sequence_number(
562 &self,
563 sequence_number: CheckpointSequenceNumber,
564 ) -> StateReadResult<Option<VerifiedCheckpoint>> {
565 Ok(self.get_checkpoint_by_sequence_number(sequence_number)?)
566 }
567
568 fn get_latest_checkpoint_sequence_number(&self) -> StateReadResult<CheckpointSequenceNumber> {
569 Ok(self.get_latest_checkpoint_sequence_number()?)
570 }
571
572 fn get_chain_identifier(&self) -> StateReadResult<ChainIdentifier> {
573 Ok(self.get_chain_identifier())
574 }
575}
576
577#[async_trait]
580impl<S: ?Sized + StateRead> ObjectProvider for Arc<S> {
581 type Error = StateReadError;
582
583 async fn get_object(
584 &self,
585 id: &ObjectID,
586 version: &SequenceNumber,
587 ) -> Result<Object, Self::Error> {
588 Ok(self.get_past_object_read(id, *version)?.into_object()?)
589 }
590
591 async fn find_object_lt_or_eq_version(
592 &self,
593 id: &ObjectID,
594 version: &SequenceNumber,
595 ) -> Result<Option<Object>, Self::Error> {
596 Ok(self
597 .get_cache_reader()
598 .find_object_lt_or_eq_version(*id, *version))
599 }
600}
601
602#[async_trait]
603impl<S: ?Sized + StateRead> ObjectProvider for (Arc<S>, Arc<TransactionKeyValueStore>) {
604 type Error = StateReadError;
605
606 async fn get_object(
607 &self,
608 id: &ObjectID,
609 version: &SequenceNumber,
610 ) -> Result<Object, Self::Error> {
611 let object_read = self.0.get_past_object_read(id, *version)?;
612 match object_read {
613 PastObjectRead::ObjectNotExists(_) | PastObjectRead::VersionNotFound(..) => {
614 match self.1.get_object(*id, *version).await? {
615 Some(object) => Ok(object),
616 None => Ok(PastObjectRead::VersionNotFound(*id, *version).into_object()?),
617 }
618 }
619 _ => Ok(object_read.into_object()?),
620 }
621 }
622
623 async fn find_object_lt_or_eq_version(
624 &self,
625 id: &ObjectID,
626 version: &SequenceNumber,
627 ) -> Result<Option<Object>, Self::Error> {
628 Ok(self
629 .0
630 .get_cache_reader()
631 .find_object_lt_or_eq_version(*id, *version))
632 }
633}
634
635#[derive(Debug, Error)]
636pub enum StateReadInternalError {
637 #[error(transparent)]
638 SuiError(#[from] SuiError),
639 #[error(transparent)]
640 JoinError(#[from] JoinError),
641 #[error(transparent)]
642 Anyhow(#[from] anyhow::Error),
643}
644
645impl From<SuiErrorKind> for StateReadInternalError {
646 fn from(e: SuiErrorKind) -> Self {
647 StateReadInternalError::SuiError(SuiError::from(e))
648 }
649}
650
651#[derive(Debug, Error)]
652pub enum StateReadClientError {
653 #[error(transparent)]
654 SuiError(#[from] SuiError),
655 #[error(transparent)]
656 UserInputError(#[from] UserInputError),
657}
658
659impl From<SuiErrorKind> for StateReadClientError {
660 fn from(e: SuiErrorKind) -> Self {
661 StateReadClientError::SuiError(SuiError::from(e))
662 }
663}
664
665#[derive(Debug, Error)]
670pub enum StateReadError {
671 #[error(transparent)]
673 Internal(#[from] StateReadInternalError),
674
675 #[error(transparent)]
677 Client(#[from] StateReadClientError),
678}
679
680impl From<SuiErrorKind> for StateReadError {
681 fn from(e: SuiErrorKind) -> Self {
682 match e {
683 SuiErrorKind::IndexStoreNotAvailable
684 | SuiErrorKind::TransactionNotFound { .. }
685 | SuiErrorKind::UnsupportedFeatureError { .. }
686 | SuiErrorKind::UserInputError { .. }
687 | SuiErrorKind::WrongMessageVersion { .. } => StateReadError::Client(e.into()),
688 _ => StateReadError::Internal(e.into()),
689 }
690 }
691}
692
693impl From<SuiError> for StateReadError {
694 fn from(e: SuiError) -> Self {
695 e.into_inner().into()
696 }
697}
698
699impl From<UserInputError> for StateReadError {
700 fn from(e: UserInputError) -> Self {
701 StateReadError::Client(e.into())
702 }
703}
704
705impl From<JoinError> for StateReadError {
706 fn from(e: JoinError) -> Self {
707 StateReadError::Internal(e.into())
708 }
709}
710
711impl From<anyhow::Error> for StateReadError {
712 fn from(e: anyhow::Error) -> Self {
713 StateReadError::Internal(e.into())
714 }
715}
716
717impl From<TypedStoreError> for StateReadError {
718 fn from(e: TypedStoreError) -> Self {
719 let error: SuiError = e.into();
720 StateReadError::Internal(error.into())
721 }
722}