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 Ok(total_balance)
468 })
469 .await
470 .map_err(|e: JoinError| {
471 SuiError(Box::new(SuiErrorKind::ExecutionError(e.to_string())))
472 })??,
473 )
474 }
475
476 async fn get_all_balance(
477 &self,
478 owner: SuiAddress,
479 ) -> StateReadResult<Arc<HashMap<TypeTag, TotalBalance>>> {
480 let indexes = self.indexes.clone();
481 let child_object_resolver = self.get_child_object_resolver().clone();
482 Ok(tokio::task::spawn_blocking(
483 move || -> SuiResult<Arc<HashMap<TypeTag, TotalBalance>>> {
484 let indexes = indexes
485 .as_ref()
486 .ok_or(SuiErrorKind::IndexStoreNotAvailable)?;
487 let address_balances = get_all_balances_for_owner(
488 owner,
489 child_object_resolver.as_ref(),
490 indexes.tables(),
491 usize::MAX,
492 None,
493 )?;
494 let coin_balances = (*indexes.get_all_coin_object_balances(owner)?).clone();
495 let mut all_balances = coin_balances;
496 for (coin_type, balance) in address_balances {
497 let existing_balance = all_balances.entry(coin_type).or_insert(TotalBalance {
498 balance: 0,
499 num_coins: 0,
500 });
501 existing_balance.balance += balance as i128;
502 existing_balance.num_coins += 1;
503 }
504 Ok(Arc::new(all_balances))
505 },
506 )
507 .await
508 .map_err(|e: JoinError| {
509 SuiError(Box::new(SuiErrorKind::ExecutionError(e.to_string())))
510 })??)
511 }
512
513 fn get_verified_checkpoint_by_sequence_number(
514 &self,
515 sequence_number: CheckpointSequenceNumber,
516 ) -> StateReadResult<VerifiedCheckpoint> {
517 Ok(self.get_verified_checkpoint_by_sequence_number(sequence_number)?)
518 }
519
520 fn get_checkpoint_contents(
521 &self,
522 digest: CheckpointContentsDigest,
523 ) -> StateReadResult<CheckpointContents> {
524 Ok(self.get_checkpoint_contents(digest)?)
525 }
526
527 fn get_verified_checkpoint_summary_by_digest(
528 &self,
529 digest: CheckpointDigest,
530 ) -> StateReadResult<VerifiedCheckpoint> {
531 Ok(self.get_verified_checkpoint_summary_by_digest(digest)?)
532 }
533
534 fn deprecated_multi_get_transaction_checkpoint(
535 &self,
536 digests: &[TransactionDigest],
537 ) -> StateReadResult<Vec<Option<(EpochId, CheckpointSequenceNumber)>>> {
538 Ok(self
539 .get_checkpoint_cache()
540 .deprecated_multi_get_transaction_checkpoint(digests))
541 }
542
543 fn deprecated_get_transaction_checkpoint(
544 &self,
545 digest: &TransactionDigest,
546 ) -> StateReadResult<Option<(EpochId, CheckpointSequenceNumber)>> {
547 Ok(self
548 .get_checkpoint_cache()
549 .deprecated_get_transaction_checkpoint(digest))
550 }
551
552 fn multi_get_checkpoint_by_sequence_number(
553 &self,
554 sequence_numbers: &[CheckpointSequenceNumber],
555 ) -> StateReadResult<Vec<Option<VerifiedCheckpoint>>> {
556 Ok(self.multi_get_checkpoint_by_sequence_number(sequence_numbers)?)
557 }
558
559 fn get_total_transaction_blocks(&self) -> StateReadResult<u64> {
560 Ok(self.get_total_transaction_blocks()?)
561 }
562
563 fn get_checkpoint_by_sequence_number(
564 &self,
565 sequence_number: CheckpointSequenceNumber,
566 ) -> StateReadResult<Option<VerifiedCheckpoint>> {
567 Ok(self.get_checkpoint_by_sequence_number(sequence_number)?)
568 }
569
570 fn get_latest_checkpoint_sequence_number(&self) -> StateReadResult<CheckpointSequenceNumber> {
571 Ok(self.get_latest_checkpoint_sequence_number()?)
572 }
573
574 fn get_chain_identifier(&self) -> StateReadResult<ChainIdentifier> {
575 Ok(self.get_chain_identifier())
576 }
577}
578
579#[async_trait]
582impl<S: ?Sized + StateRead> ObjectProvider for Arc<S> {
583 type Error = StateReadError;
584
585 async fn get_object(
586 &self,
587 id: &ObjectID,
588 version: &SequenceNumber,
589 ) -> Result<Object, Self::Error> {
590 Ok(self.get_past_object_read(id, *version)?.into_object()?)
591 }
592
593 async fn find_object_lt_or_eq_version(
594 &self,
595 id: &ObjectID,
596 version: &SequenceNumber,
597 ) -> Result<Option<Object>, Self::Error> {
598 Ok(self
599 .get_cache_reader()
600 .find_object_lt_or_eq_version(*id, *version))
601 }
602}
603
604#[async_trait]
605impl<S: ?Sized + StateRead> ObjectProvider for (Arc<S>, Arc<TransactionKeyValueStore>) {
606 type Error = StateReadError;
607
608 async fn get_object(
609 &self,
610 id: &ObjectID,
611 version: &SequenceNumber,
612 ) -> Result<Object, Self::Error> {
613 let object_read = self.0.get_past_object_read(id, *version)?;
614 match object_read {
615 PastObjectRead::ObjectNotExists(_) | PastObjectRead::VersionNotFound(..) => {
616 match self.1.get_object(*id, *version).await? {
617 Some(object) => Ok(object),
618 None => Ok(PastObjectRead::VersionNotFound(*id, *version).into_object()?),
619 }
620 }
621 _ => Ok(object_read.into_object()?),
622 }
623 }
624
625 async fn find_object_lt_or_eq_version(
626 &self,
627 id: &ObjectID,
628 version: &SequenceNumber,
629 ) -> Result<Option<Object>, Self::Error> {
630 Ok(self
631 .0
632 .get_cache_reader()
633 .find_object_lt_or_eq_version(*id, *version))
634 }
635}
636
637#[derive(Debug, Error)]
638pub enum StateReadInternalError {
639 #[error(transparent)]
640 SuiError(#[from] SuiError),
641 #[error(transparent)]
642 JoinError(#[from] JoinError),
643 #[error(transparent)]
644 Anyhow(#[from] anyhow::Error),
645}
646
647impl From<SuiErrorKind> for StateReadInternalError {
648 fn from(e: SuiErrorKind) -> Self {
649 StateReadInternalError::SuiError(SuiError::from(e))
650 }
651}
652
653#[derive(Debug, Error)]
654pub enum StateReadClientError {
655 #[error(transparent)]
656 SuiError(#[from] SuiError),
657 #[error(transparent)]
658 UserInputError(#[from] UserInputError),
659}
660
661impl From<SuiErrorKind> for StateReadClientError {
662 fn from(e: SuiErrorKind) -> Self {
663 StateReadClientError::SuiError(SuiError::from(e))
664 }
665}
666
667#[derive(Debug, Error)]
672pub enum StateReadError {
673 #[error(transparent)]
675 Internal(#[from] StateReadInternalError),
676
677 #[error(transparent)]
679 Client(#[from] StateReadClientError),
680}
681
682impl From<SuiErrorKind> for StateReadError {
683 fn from(e: SuiErrorKind) -> Self {
684 match e {
685 SuiErrorKind::IndexStoreNotAvailable
686 | SuiErrorKind::TransactionNotFound { .. }
687 | SuiErrorKind::UnsupportedFeatureError { .. }
688 | SuiErrorKind::UserInputError { .. }
689 | SuiErrorKind::WrongMessageVersion { .. } => StateReadError::Client(e.into()),
690 _ => StateReadError::Internal(e.into()),
691 }
692 }
693}
694
695impl From<SuiError> for StateReadError {
696 fn from(e: SuiError) -> Self {
697 e.into_inner().into()
698 }
699}
700
701impl From<UserInputError> for StateReadError {
702 fn from(e: UserInputError) -> Self {
703 StateReadError::Client(e.into())
704 }
705}
706
707impl From<JoinError> for StateReadError {
708 fn from(e: JoinError) -> Self {
709 StateReadError::Internal(e.into())
710 }
711}
712
713impl From<anyhow::Error> for StateReadError {
714 fn from(e: anyhow::Error) -> Self {
715 StateReadError::Internal(e.into())
716 }
717}
718
719impl From<TypedStoreError> for StateReadError {
720 fn from(e: TypedStoreError) -> Self {
721 let error: SuiError = e.into();
722 StateReadError::Internal(error.into())
723 }
724}