From b7625b65114d57377d1ad755c2ee22a3f47d0578 Mon Sep 17 00:00:00 2001 From: wlmyng <127570466+wlmyng@users.noreply.github.com> Date: Thu, 11 May 2023 21:29:17 -0700 Subject: [PATCH] 2/n improve sui-json-rpc error codes and handling (#11833) --- crates/sui-core/src/authority.rs | 209 +++++++++--------- .../sui-core/src/authority/authority_store.rs | 2 +- .../sui-core/src/transaction_input_checker.rs | 4 +- .../src/unit_tests/authority_tests.rs | 2 +- .../sui-json-rpc-types/src/sui_transaction.rs | 6 +- crates/sui-json-rpc/src/indexer_api.rs | 11 +- crates/sui-json-rpc/src/read_api.rs | 32 ++- .../src/transaction_execution_api.rs | 3 +- crates/sui-storage/src/indexes.rs | 9 +- crates/sui-types/src/error.rs | 22 +- 10 files changed, 168 insertions(+), 132 deletions(-) diff --git a/crates/sui-core/src/authority.rs b/crates/sui-core/src/authority.rs index 5e361236fac29..1a946b854e0c6 100644 --- a/crates/sui-core/src/authority.rs +++ b/crates/sui-core/src/authority.rs @@ -630,7 +630,7 @@ impl AuthorityState { &self, epoch_store: &Arc, transaction: VerifiedTransaction, - ) -> Result { + ) -> SuiResult { fp_ensure!( !transaction.is_system_tx(), SuiError::InvalidSystemTransaction @@ -1178,25 +1178,26 @@ impl AuthorityState { &self, transaction: TransactionData, transaction_digest: TransactionDigest, - ) -> Result< - ( - DryRunTransactionBlockResponse, - BTreeMap, - TransactionEffects, - Option, - ), - anyhow::Error, - > { + ) -> SuiResult<( + DryRunTransactionBlockResponse, + BTreeMap, + TransactionEffects, + Option, + )> { let epoch_store = self.load_epoch_store_one_call_per_task(); if !self.is_fullnode(&epoch_store) { - return Err(anyhow!("dry-exec is only supported on fullnodes")); + return Err(SuiError::UnsupportedFeatureError { + error: "dry-exec is only supported on fullnodes".to_string(), + }); } match transaction.kind() { TransactionKind::ProgrammableTransaction(_) => (), TransactionKind::ChangeEpoch(_) | TransactionKind::Genesis(_) | TransactionKind::ConsensusCommitPrologue(_) => { - return Err(anyhow!("dry-exec does not support system transactions")); + return Err(SuiError::UnsupportedFeatureError { + error: "dry-exec does not support system transactions".to_string(), + }); } } @@ -1291,7 +1292,13 @@ impl AuthorityState { Ok(( DryRunTransactionBlockResponse { - input: SuiTransactionBlockData::try_from(transaction.clone(), &module_cache)?, + input: SuiTransactionBlockData::try_from(transaction.clone(), &module_cache) + .map_err(|e| SuiError::TransactionSerializationError { + error: format!( + "Failed to convert transaction to SuiTransactionBlockData: {}", + e + ), + })?, // TODO: replace the underlying try_from to SuiError. This one goes deep effects: effects.clone().try_into()?, events: SuiTransactionBlockEvents::try_from( inner_temp_store.events.clone(), @@ -1314,10 +1321,12 @@ impl AuthorityState { sender: SuiAddress, transaction_kind: TransactionKind, gas_price: Option, - ) -> Result { + ) -> SuiResult { let epoch_store = self.load_epoch_store_one_call_per_task(); if !self.is_fullnode(&epoch_store) { - return Err(anyhow!("dev-inspect is only supported on fullnodes")); + return Err(SuiError::UnsupportedFeatureError { + error: "dev-inspect is only supported on fullnodes".to_string(), + }); } transaction_kind.check_version_supported(epoch_store.protocol_config())?; @@ -1470,7 +1479,7 @@ impl AuthorityState { &self, effects: &TransactionEffects, epoch_store: &Arc, - ) -> Result { + ) -> SuiResult { let modified_at_version = effects .modified_at_versions() .iter() @@ -1710,7 +1719,7 @@ impl AuthorityState { pub async fn handle_transaction_info_request( &self, request: TransactionInfoRequest, - ) -> Result { + ) -> SuiResult { let epoch_store = self.load_epoch_store_one_call_per_task(); let (transaction, status) = self .get_transaction_status(&request.transaction_digest, &epoch_store)? @@ -1726,7 +1735,7 @@ impl AuthorityState { pub async fn handle_object_info_request( &self, request: ObjectInfoRequest, - ) -> Result { + ) -> SuiResult { let epoch_store = self.load_epoch_store_one_call_per_task(); let requested_object_seq = match request.request_kind { @@ -1785,7 +1794,7 @@ impl AuthorityState { pub fn handle_checkpoint_request( &self, request: &CheckpointRequest, - ) -> Result { + ) -> SuiResult { let summary = match request.sequence_number { Some(seq) => self .checkpoint_store @@ -1808,7 +1817,7 @@ impl AuthorityState { pub fn load_fastpath_input_objects( &self, effects: &TransactionEffects, - ) -> Result, SuiError> { + ) -> SuiResult> { // Note: any future addition to the returned object list needs cautions // to make sure not to mess up object pruning. @@ -2176,7 +2185,7 @@ impl AuthorityState { Committee::clone(self.epoch_store_for_testing().committee()) } - pub async fn get_object(&self, object_id: &ObjectID) -> Result, SuiError> { + pub async fn get_object(&self, object_id: &ObjectID) -> SuiResult> { self.database.get_object(object_id) } @@ -2228,7 +2237,7 @@ impl AuthorityState { Ok(checkpoint) } - pub fn get_object_read(&self, object_id: &ObjectID) -> Result { + pub fn get_object_read(&self, object_id: &ObjectID) -> SuiResult { match self.database.get_object_or_tombstone(*object_id)? { None => Ok(ObjectRead::NotExists(*object_id)), Some(obj_ref) => { @@ -2330,7 +2339,7 @@ impl AuthorityState { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> Result { + ) -> SuiResult { // Firstly we see if the object ever exists by getting its latest data match self.database.get_object_or_tombstone(*object_id)? { None => Ok(PastObjectRead::ObjectNotExists(*object_id)), @@ -2416,7 +2425,7 @@ impl AuthorityState { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> Result { + ) -> SuiResult { self.database .get_object_by_key(object_id, version)? .ok_or_else(|| { @@ -2551,64 +2560,61 @@ impl AuthorityState { } } - pub fn get_total_transaction_blocks(&self) -> Result { + pub fn get_total_transaction_blocks(&self) -> SuiResult { Ok(self.get_indexes()?.next_sequence_number()) } pub async fn get_executed_transaction_and_effects( &self, digest: TransactionDigest, - ) -> Result<(VerifiedTransaction, TransactionEffects), anyhow::Error> { + ) -> SuiResult<(VerifiedTransaction, TransactionEffects)> { let transaction = self.database.get_transaction_block(&digest)?; let effects = self.database.get_executed_effects(&digest)?; match (transaction, effects) { (Some(transaction), Some(effects)) => Ok((transaction, effects)), - _ => Err(anyhow!(SuiError::TransactionNotFound { digest })), + _ => Err(SuiError::TransactionNotFound { digest }), } } pub async fn get_transaction_block( &self, digest: TransactionDigest, - ) -> Result { + ) -> SuiResult { let transaction = self.database.get_transaction_block(&digest)?; - transaction.ok_or_else(|| anyhow!(SuiError::TransactionNotFound { digest })) + transaction.ok_or(SuiError::TransactionNotFound { digest }) } - pub fn get_executed_effects( - &self, - digest: TransactionDigest, - ) -> Result { + pub fn get_executed_effects(&self, digest: TransactionDigest) -> SuiResult { let effects = self.database.get_executed_effects(&digest)?; - effects.ok_or_else(|| anyhow!(SuiError::TransactionNotFound { digest })) + effects.ok_or(SuiError::TransactionNotFound { digest }) } pub fn multi_get_executed_transactions( &self, digests: &[TransactionDigest], - ) -> Result>, anyhow::Error> { - Ok(self.database.multi_get_transaction_blocks(digests)?) + ) -> SuiResult>> { + self.database.multi_get_transaction_blocks(digests) } pub fn multi_get_executed_effects( &self, digests: &[TransactionDigest], - ) -> Result>, anyhow::Error> { - Ok(self.database.multi_get_executed_effects(digests)?) + ) -> SuiResult>> { + self.database.multi_get_executed_effects(digests) } pub fn multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> Result>, anyhow::Error> { - Ok(self.database.multi_get_transaction_checkpoint(digests)?) + ) -> SuiResult>> { + self.database.multi_get_transaction_checkpoint(digests) } pub fn multi_get_events( &self, digests: &[TransactionEventsDigest], - ) -> Result>, anyhow::Error> { - Ok(self.database.multi_get_events(digests)?) + ) -> SuiResult>> { + self.database.multi_get_events(digests) } pub fn multi_get_checkpoint_by_sequence_number( @@ -2653,7 +2659,7 @@ impl AuthorityState { cursor: Option, limit: Option, reverse: bool, - ) -> Result, anyhow::Error> { + ) -> SuiResult> { if let Some(TransactionFilter::Checkpoint(sequence_number)) = filter { let checkpoint_contents = self.get_checkpoint_contents_by_sequence_number(sequence_number)?; @@ -2679,50 +2685,45 @@ impl AuthorityState { self.checkpoint_store.clone() } - pub fn get_latest_checkpoint_sequence_number( - &self, - ) -> Result { + pub fn get_latest_checkpoint_sequence_number(&self) -> SuiResult { self.get_checkpoint_store() .get_highest_executed_checkpoint_seq_number()? - .ok_or_else(|| anyhow!("Latest checkpoint sequence number not found")) + .ok_or(SuiError::UserInputError { + error: UserInputError::LatestCheckpointSequenceNumberNotFound, + }) } pub fn get_checkpoint_summary_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> Result { + ) -> SuiResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_sequence_number(sequence_number)?; match verified_checkpoint { Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()), - None => Err(anyhow!( - "Verified checkpoint not found for sequence number {}", - sequence_number - )), + None => Err(SuiError::UserInputError { + error: UserInputError::VerifiedCheckpointNotFound(sequence_number), + }), } } pub fn get_checkpoint_summary_by_digest( &self, digest: CheckpointDigest, - ) -> Result { + ) -> SuiResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_digest(&digest)?; match verified_checkpoint { Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()), - None => Err(anyhow!( - "Verified checkpoint not found for digest: {}", - Base58::encode(digest) - )), + None => Err(SuiError::UserInputError { + error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)), + }), } } - pub fn find_publish_txn_digest( - &self, - package_id: ObjectID, - ) -> Result { + pub fn find_publish_txn_digest(&self, package_id: ObjectID) -> SuiResult { if is_system_package(package_id) { return self.find_genesis_txn_digest(); } @@ -2732,14 +2733,16 @@ impl AuthorityState { .previous_transaction) } - pub fn find_genesis_txn_digest(&self) -> Result { + pub fn find_genesis_txn_digest(&self) -> SuiResult { let summary = self .get_verified_checkpoint_by_sequence_number(0)? .into_message(); let content = self.get_checkpoint_contents(summary.content_digest)?; let genesis_transaction = content.enumerate_transactions(&summary).next(); Ok(genesis_transaction - .ok_or(anyhow!("No transactions found in checkpoint content"))? + .ok_or(SuiError::UserInputError { + error: UserInputError::GenesisTransactionNotFound, + })? .1 .transaction) } @@ -2747,48 +2750,48 @@ impl AuthorityState { pub fn get_verified_checkpoint_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> Result { + ) -> SuiResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_sequence_number(sequence_number)?; match verified_checkpoint { Some(verified_checkpoint) => Ok(verified_checkpoint), - None => Err(anyhow!( - "Verified checkpoint not found for sequence number {}", - sequence_number - )), + None => Err(SuiError::UserInputError { + error: UserInputError::VerifiedCheckpointNotFound(sequence_number), + }), } } pub fn get_verified_checkpoint_summary_by_digest( &self, digest: CheckpointDigest, - ) -> Result { + ) -> SuiResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_digest(&digest)?; match verified_checkpoint { Some(verified_checkpoint) => Ok(verified_checkpoint), - None => Err(anyhow!( - "Verified checkpoint not found for digest: {}", - Base58::encode(digest) - )), + None => Err(SuiError::UserInputError { + error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)), + }), } } pub fn get_checkpoint_contents( &self, digest: CheckpointContentsDigest, - ) -> Result { + ) -> SuiResult { self.get_checkpoint_store() .get_checkpoint_contents(&digest)? - .ok_or_else(|| anyhow!("Checkpoint contents not found for digest: {:?}", digest)) + .ok_or(SuiError::UserInputError { + error: UserInputError::CheckpointContentsNotFound(digest), + }) } pub fn get_checkpoint_contents_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> Result { + ) -> SuiResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_sequence_number(sequence_number)?; @@ -2797,10 +2800,9 @@ impl AuthorityState { let content_digest = verified_checkpoint.into_inner().content_digest; self.get_checkpoint_contents(content_digest) } - None => Err(anyhow!( - "Verified checkpoint not found for sequence number {}", - sequence_number - )), + None => Err(SuiError::UserInputError { + error: UserInputError::VerifiedCheckpointNotFound(sequence_number), + }), } } @@ -2810,7 +2812,7 @@ impl AuthorityState { cursor: Option, limit: u64, descending_order: bool, - ) -> Result, anyhow::Error> { + ) -> SuiResult> { let max_checkpoint = self.get_latest_checkpoint_sequence_number()?; let checkpoint_numbers = calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); @@ -2859,11 +2861,8 @@ impl AuthorityState { Ok(checkpoints) } - pub async fn get_timestamp_ms( - &self, - digest: &TransactionDigest, - ) -> Result, anyhow::Error> { - Ok(self.get_indexes()?.get_timestamp_ms(digest)?) + pub async fn get_timestamp_ms(&self, digest: &TransactionDigest) -> SuiResult> { + self.get_indexes()?.get_timestamp_ms(digest) } pub fn query_events( @@ -2873,7 +2872,7 @@ impl AuthorityState { cursor: Option, limit: usize, descending: bool, - ) -> Result, anyhow::Error> { + ) -> SuiResult> { let index_store = self.get_indexes()?; //Get the tx_num from tx_digest @@ -2896,9 +2895,12 @@ impl AuthorityState { if filters.is_empty() { index_store.all_events(tx_num, event_num, limit, descending)? } else { - return Err(anyhow!( - "This query type does not currently support filter combinations." - )); + return Err(SuiError::UserInputError { + error: UserInputError::Unsupported( + "This query type does not currently support filter combinations" + .to_string(), + ), + }); } } EventFilter::Transaction(digest) => { @@ -2925,9 +2927,11 @@ impl AuthorityState { } => index_store .event_iterator(start_time, end_time, tx_num, event_num, limit, descending)?, _ => { - return Err(anyhow!( - "This query type is not supported by the full node." - )) + return Err(SuiError::UserInputError { + error: UserInputError::Unsupported( + "This query type is not supported by the full node.".to_string(), + ), + }) } }; @@ -2987,7 +2991,7 @@ impl AuthorityState { &self, tx_digest: &TransactionDigest, epoch_store: &Arc, - ) -> Result, SuiError> { + ) -> SuiResult> { let Some(cert_sig) = epoch_store.get_transaction_cert_sig(tx_digest)? else { return Ok(None); }; @@ -3008,7 +3012,7 @@ impl AuthorityState { &self, transaction_digest: &TransactionDigest, epoch_store: &Arc, - ) -> Result, SuiError> { + ) -> SuiResult> { // TODO: In the case of read path, we should not have to re-sign the effects. if let Some(effects) = self.get_signed_effects_and_maybe_resign(transaction_digest, epoch_store)? @@ -3059,7 +3063,7 @@ impl AuthorityState { &self, effects: TransactionEffects, epoch_store: &Arc, - ) -> Result { + ) -> SuiResult { let tx_digest = *effects.transaction_digest(); let signed_effects = match epoch_store.get_effects_signature(&tx_digest)? { Some(sig) if sig.epoch == epoch_store.epoch() => { @@ -3121,7 +3125,7 @@ impl AuthorityState { mutable_input_objects: &[ObjectRef], signed_transaction: VerifiedSignedTransaction, epoch_store: &Arc, - ) -> Result<(), SuiError> { + ) -> SuiResult { self.lock_and_write_transaction(mutable_input_objects, signed_transaction, epoch_store) .await } @@ -3134,7 +3138,7 @@ impl AuthorityState { owned_input_objects: &[ObjectRef], transaction: VerifiedSignedTransaction, epoch_store: &Arc, - ) -> Result<(), SuiError> { + ) -> SuiResult { let tx_digest = *transaction.digest(); // Acquire the lock on input objects @@ -3256,7 +3260,7 @@ impl AuthorityState { &self, object_ref: &ObjectRef, epoch_store: &AuthorityPerEpochStore, - ) -> Result, SuiError> { + ) -> SuiResult> { let lock_info = self .database .get_lock(*object_ref, epoch_store.epoch()) @@ -3298,17 +3302,14 @@ impl AuthorityState { Ok(tx_option) } - pub async fn get_objects( - &self, - _objects: &[ObjectID], - ) -> Result>, SuiError> { + pub async fn get_objects(&self, _objects: &[ObjectID]) -> SuiResult>> { self.database.get_objects(_objects) } pub async fn get_object_or_tombstone( &self, object_id: ObjectID, - ) -> Result, SuiError> { + ) -> SuiResult> { self.database.get_object_or_tombstone(object_id) } diff --git a/crates/sui-core/src/authority/authority_store.rs b/crates/sui-core/src/authority/authority_store.rs index 6d90a4690b792..5508577f94bc9 100644 --- a/crates/sui-core/src/authority/authority_store.rs +++ b/crates/sui-core/src/authority/authority_store.rs @@ -1464,7 +1464,7 @@ impl AuthorityStore { pub fn multi_get_transaction_blocks( &self, tx_digests: &[TransactionDigest], - ) -> Result>, SuiError> { + ) -> SuiResult>> { Ok(self .perpetual_tables .transactions diff --git a/crates/sui-core/src/transaction_input_checker.rs b/crates/sui-core/src/transaction_input_checker.rs index 97544198d2f7b..f3d56b8eada3c 100644 --- a/crates/sui-core/src/transaction_input_checker.rs +++ b/crates/sui-core/src/transaction_input_checker.rs @@ -113,7 +113,7 @@ pub(crate) async fn check_dev_inspect_input( config: &ProtocolConfig, kind: &TransactionKind, gas_object: Object, -) -> Result<(ObjectRef, InputObjects), anyhow::Error> { +) -> SuiResult<(ObjectRef, InputObjects)> { let gas_object_ref = gas_object.compute_object_reference(); kind.validity_check(config)?; match kind { @@ -121,7 +121,7 @@ pub(crate) async fn check_dev_inspect_input( TransactionKind::ChangeEpoch(_) | TransactionKind::Genesis(_) | TransactionKind::ConsensusCommitPrologue(_) => { - anyhow::bail!("Transaction kind {} is not supported in dev-inspect", kind) + return Err(UserInputError::Unsupported(format!("Transaction kind {} is not supported in dev-inspect", kind)).into()) } } let mut input_objects = kind.input_objects()?; diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/sui-core/src/unit_tests/authority_tests.rs index 9194782658730..8d09237228c41 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_tests.rs @@ -4287,7 +4287,7 @@ pub async fn call_dev_inspect( function: &str, type_arguments: Vec, test_args: Vec, -) -> Result { +) -> SuiResult { let mut builder = ProgrammableTransactionBuilder::new(); let mut arguments = Vec::with_capacity(test_args.len()); for a in test_args { diff --git a/crates/sui-json-rpc-types/src/sui_transaction.rs b/crates/sui-json-rpc-types/src/sui_transaction.rs index 3eab16b8f25e2..e7acd64d4b91f 100644 --- a/crates/sui-json-rpc-types/src/sui_transaction.rs +++ b/crates/sui-json-rpc-types/src/sui_transaction.rs @@ -24,7 +24,7 @@ use sui_types::base_types::{ }; use sui_types::digests::{ObjectDigest, TransactionEventsDigest}; use sui_types::effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}; -use sui_types::error::{ExecutionError, SuiError}; +use sui_types::error::{ExecutionError, SuiError, SuiResult}; use sui_types::execution_status::ExecutionStatus; use sui_types::gas::GasCostSummary; use sui_types::messages_checkpoint::CheckpointSequenceNumber; @@ -706,7 +706,7 @@ impl SuiTransactionBlockEvents { tx_digest: TransactionDigest, timestamp_ms: Option, resolver: &impl GetModule, - ) -> Result { + ) -> SuiResult { Ok(Self { data: events .data @@ -761,7 +761,7 @@ impl DevInspectResults { events: TransactionEvents, return_values: Result, ExecutionError>, resolver: &impl GetModule, - ) -> Result { + ) -> SuiResult { let tx_digest = *effects.transaction_digest(); let mut error = None; let mut results = None; diff --git a/crates/sui-json-rpc/src/indexer_api.rs b/crates/sui-json-rpc/src/indexer_api.rs index 1a2140fd0e834..424cca26aa14d 100644 --- a/crates/sui-json-rpc/src/indexer_api.rs +++ b/crates/sui-json-rpc/src/indexer_api.rs @@ -36,6 +36,7 @@ use crate::api::{ cap_page_limit, validate_limit, IndexerApiServer, JsonRpcMetrics, ReadApiServer, QUERY_MAX_RESULT_LIMIT, }; +use crate::error::Error; use crate::with_tracing; use crate::SuiRpcModule; @@ -157,9 +158,10 @@ impl IndexerApiServer for IndexerApi { let opts = query.options.unwrap_or_default(); // Retrieve 1 extra item for next cursor - let mut digests = - self.state - .get_transactions(query.filter, cursor, Some(limit + 1), descending)?; + let mut digests = self + .state + .get_transactions(query.filter, cursor, Some(limit + 1), descending) + .map_err(Error::from)?; // extract next cursor let has_next_page = digests.len() > limit; @@ -206,7 +208,8 @@ impl IndexerApiServer for IndexerApi { // Retrieve 1 extra item for next cursor let mut data = self .state - .query_events(query, cursor.clone(), limit + 1, descending)?; + .query_events(query, cursor.clone(), limit + 1, descending) + .map_err(Error::from)?; let has_next_page = data.len() > limit; data.truncate(limit); let next_cursor = data.last().map_or(cursor, |e| Some(e.id.clone())); diff --git a/crates/sui-json-rpc/src/read_api.rs b/crates/sui-json-rpc/src/read_api.rs index b28cbc66daaf1..c6eee33df6de9 100644 --- a/crates/sui-json-rpc/src/read_api.rs +++ b/crates/sui-json-rpc/src/read_api.rs @@ -590,7 +590,11 @@ impl ReadApiServer for ReadApi { #[instrument(skip(self))] async fn get_total_transaction_blocks(&self) -> RpcResult> { with_tracing!("get_total_transaction_blocks", async move { - Ok(self.state.get_total_transaction_blocks()?.into()) + Ok(self + .state + .get_total_transaction_blocks() + .map_err(Error::from)? + .into()) // converts into BigInt }) } @@ -612,7 +616,8 @@ impl ReadApiServer for ReadApi { ) }) .await - .map_err(|e| anyhow!(e))??; + .map_err(Error::from)? + .map_err(Error::from)?; let input_objects = transaction .data() .inner() @@ -636,7 +641,8 @@ impl ReadApiServer for ReadApi { ) }) .await - .map_err(|e| anyhow!(e))??, + .map_err(Error::from)? + .map_err(Error::from)?, ); } @@ -767,7 +773,7 @@ impl ReadApiServer for ReadApi { let state = self.state.clone(); spawn_monitored_task!(async move{ let store = state.load_epoch_store_one_call_per_task(); - let effect = state.get_executed_effects(transaction_digest)?; + let effect = state.get_executed_effects(transaction_digest).map_err(Error::from)?; let events = if let Some(event_digest) = effect.events_digest() { state .get_transaction_events(event_digest) @@ -837,7 +843,8 @@ impl ReadApiServer for ReadApi { state.get_checkpoints(cursor.map(|s| *s), limit as u64 + 1, descending_order) }) .await - .map_err(|e| anyhow!(e))??; + .map_err(Error::from)? + .map_err(Error::from)?; let has_next_page = data.len() > limit; data.truncate(limit); @@ -981,12 +988,15 @@ fn get_display_object_by_type( object_type: &StructTag, // TODO: add query version support ) -> RpcResult> { - let mut events = fullnode_api.state.query_events( - EventFilter::MoveEventType(DisplayVersionUpdatedEvent::type_(object_type)), - None, - 1, - true, - )?; + let mut events = fullnode_api + .state + .query_events( + EventFilter::MoveEventType(DisplayVersionUpdatedEvent::type_(object_type)), + None, + 1, + true, + ) + .map_err(Error::from)?; // If there's any recent version of Display, give it to the client. // TODO: add support for version query. diff --git a/crates/sui-json-rpc/src/transaction_execution_api.rs b/crates/sui-json-rpc/src/transaction_execution_api.rs index 26fb97dbca859..94b1d326f797e 100644 --- a/crates/sui-json-rpc/src/transaction_execution_api.rs +++ b/crates/sui-json-rpc/src/transaction_execution_api.rs @@ -235,7 +235,8 @@ impl WriteApiServer for TransactionExecutionApi { .state .dev_inspect_transaction_block(sender_address, tx_kind, gas_price.map(|i| *i)) .instrument(error_span!("dev_inspect_transaction_block")) - .await?) + .await + .map_err(Error::from)?) } async fn dry_run_transaction_block( diff --git a/crates/sui-storage/src/indexes.rs b/crates/sui-storage/src/indexes.rs index aafe5f8b8c9fb..887ed28104967 100644 --- a/crates/sui-storage/src/indexes.rs +++ b/crates/sui-storage/src/indexes.rs @@ -10,7 +10,6 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; -use anyhow::anyhow; use itertools::Itertools; use move_core_types::identifier::Identifier; use move_core_types::language_storage::{ModuleId, StructTag, TypeTag}; @@ -621,12 +620,12 @@ impl IndexStore { cursor: Option, limit: Option, reverse: bool, - ) -> Result, anyhow::Error> { + ) -> SuiResult> { // Lookup TransactionDigest sequence number, let cursor = if let Some(cursor) = cursor { Some( self.get_transaction_seq(&cursor)? - .ok_or_else(|| anyhow!("Transaction [{cursor:?}] not found."))?, + .ok_or(SuiError::TransactionNotFound { digest: cursor })?, ) } else { None @@ -653,7 +652,9 @@ impl IndexStore { } // NOTE: filter via checkpoint sequence number is implemented in // `get_transactions` of authority.rs. - Some(_) => Err(anyhow!("Unsupported filter: {:?}", filter)), + Some(_) => Err(SuiError::UserInputError { + error: UserInputError::Unsupported(format!("{:?}", filter)), + }), None => { let iter = self.tables.transaction_order.iter(); diff --git a/crates/sui-types/src/error.rs b/crates/sui-types/src/error.rs index 807fc2de9862f..dad282b1eadd2 100644 --- a/crates/sui-types/src/error.rs +++ b/crates/sui-types/src/error.rs @@ -5,6 +5,8 @@ use crate::{ base_types::*, committee::{Committee, EpochId, StakeUnit}, + digests::CheckpointContentsDigest, + messages_checkpoint::CheckpointSequenceNumber, object::Owner, }; @@ -206,11 +208,29 @@ pub enum UserInputError { #[error("Transaction is denied: {}", error)] TransactionDenied { error: String }, - #[error("Feature is not yet supported: {0}")] + #[error("Feature is not supported: {0}")] Unsupported(String), #[error("Query transactions with move function input error: {0}")] MoveFunctionInputError(String), + + #[error("Verified checkpoint not found for sequence number: {0}")] + VerifiedCheckpointNotFound(CheckpointSequenceNumber), + + #[error("Verified checkpoint not found for digest: {0}")] + VerifiedCheckpointDigestNotFound(String), + + #[error("Latest checkpoint sequence number not found")] + LatestCheckpointSequenceNumberNotFound, + + #[error("Checkpoint contents not found for digest: {0}")] + CheckpointContentsNotFound(CheckpointContentsDigest), + + #[error("Genesis transaction not found")] + GenesisTransactionNotFound, + + #[error("Transaction {0} not found")] + TransactionCursorNotFound(u64), } #[derive(