diff --git a/crates/sui-rest-api/src/accounts.rs b/crates/sui-rest-api/src/accounts.rs index 8bf9af6e328ae..25f121d65ed48 100644 --- a/crates/sui-rest-api/src/accounts.rs +++ b/crates/sui-rest-api/src/accounts.rs @@ -55,13 +55,13 @@ async fn list_account_objects( let mut object_info = state .inner() .account_owned_objects_info_iter(address.into(), start)? + .take(limit + 1) .map(|info| AccountOwnedObjectInfo { owner: info.owner.into(), object_id: info.object_id.into(), version: info.version.into(), - type_: struct_tag_core_to_sdk(info.type_.into()), + type_: struct_tag_core_to_sdk(info.type_.into()).expect("object types must be valid"), }) - .take(limit + 1) .collect::>(); let cursor = if object_info.len() > limit { diff --git a/crates/sui-rest-api/src/checkpoints.rs b/crates/sui-rest-api/src/checkpoints.rs index 334e1b4cebbe0..2c813af3f55f7 100644 --- a/crates/sui-rest-api/src/checkpoints.rs +++ b/crates/sui-rest-api/src/checkpoints.rs @@ -151,7 +151,7 @@ async fn get_checkpoint( }? .ok_or(CheckpointNotFoundError(checkpoint_id))? .into_inner() - .into(); + .try_into()?; match accept { AcceptFormat::Json => ResponseContent::Json(summary), @@ -277,11 +277,15 @@ async fn list_checkpoints( let checkpoints = state .checkpoint_iter(direction, start) + .take(limit) .map(|result| { - result.map(|(checkpoint, _contents)| SignedCheckpointSummary::from(checkpoint)) + result + .map_err(Into::into) + .and_then(|(checkpoint, _contents)| { + SignedCheckpointSummary::try_from(checkpoint).map_err(Into::into) + }) }) - .take(limit) - .collect::, _>>()?; + .collect::>>()?; let cursor = checkpoints.last().and_then(|checkpoint| match direction { Direction::Ascending => checkpoint.checkpoint.sequence_number.checked_add(1), diff --git a/crates/sui-rest-api/src/client/mod.rs b/crates/sui-rest-api/src/client/mod.rs index 915563b0798bc..9619747510f73 100644 --- a/crates/sui-rest-api/src/client/mod.rs +++ b/crates/sui-rest-api/src/client/mod.rs @@ -35,7 +35,7 @@ impl Client { .get_latest_checkpoint() .await .map(Response::into_inner) - .map(Into::into) + .and_then(|checkpoint| checkpoint.try_into().map_err(Into::into)) } pub async fn get_full_checkpoint( @@ -66,7 +66,7 @@ impl Client { .get_checkpoint(checkpoint_sequence_number) .await .map(Response::into_inner) - .map(Into::into) + .and_then(|checkpoint| checkpoint.try_into().map_err(Into::into)) } pub async fn get_object(&self, object_id: ObjectID) -> Result { @@ -74,7 +74,7 @@ impl Client { .get_object(object_id.into()) .await .map(Response::into_inner) - .map(Into::into) + .and_then(|object| object.try_into().map_err(Into::into)) } pub async fn get_object_with_version( @@ -86,7 +86,7 @@ impl Client { .get_object_with_version(object_id.into(), version.into()) .await .map(Response::into_inner) - .map(Into::into) + .and_then(|object| object.try_into().map_err(Into::into)) } pub async fn execute_transaction( diff --git a/crates/sui-rest-api/src/client/sdk.rs b/crates/sui-rest-api/src/client/sdk.rs index 892c0d2c4835e..cbd83889ebefa 100644 --- a/crates/sui-rest-api/src/client/sdk.rs +++ b/crates/sui-rest-api/src/client/sdk.rs @@ -666,3 +666,9 @@ impl From for Error { Self::from_error(error) } } + +impl From for Error { + fn from(value: sui_types::sui_sdk2_conversions::SdkTypeConversionError) -> Self { + Self::from_error(value) + } +} diff --git a/crates/sui-rest-api/src/coins.rs b/crates/sui-rest-api/src/coins.rs index 6d2661f10ab43..b17069b2f3c6e 100644 --- a/crates/sui-rest-api/src/coins.rs +++ b/crates/sui-rest-api/src/coins.rs @@ -50,7 +50,7 @@ async fn get_coin_info( Path(coin_type): Path, State(state): State, ) -> Result> { - let core_coin_type = struct_tag_sdk_to_core(coin_type.clone()); + let core_coin_type = struct_tag_sdk_to_core(coin_type.clone())?; let sui_types::storage::CoinInfo { coin_metadata_object_id, diff --git a/crates/sui-rest-api/src/error.rs b/crates/sui-rest-api/src/error.rs index 51432315d0d37..2d0042c27d0cb 100644 --- a/crates/sui-rest-api/src/error.rs +++ b/crates/sui-rest-api/src/error.rs @@ -47,6 +47,24 @@ impl From for RestError { } } +impl From for RestError { + fn from(value: sui_types::sui_sdk2_conversions::SdkTypeConversionError) -> Self { + Self { + status: StatusCode::INTERNAL_SERVER_ERROR, + message: Some(value.to_string()), + } + } +} + +impl From for RestError { + fn from(value: bcs::Error) -> Self { + Self { + status: StatusCode::INTERNAL_SERVER_ERROR, + message: Some(value.to_string()), + } + } +} + impl From for RestError { fn from(error: sui_types::quorum_driver_types::QuorumDriverError) -> Self { use itertools::Itertools; diff --git a/crates/sui-rest-api/src/objects.rs b/crates/sui-rest-api/src/objects.rs index be10e0e38f58c..97608ecc3259f 100644 --- a/crates/sui-rest-api/src/objects.rs +++ b/crates/sui-rest-api/src/objects.rs @@ -285,7 +285,7 @@ impl From<(DynamicFieldKey, DynamicFieldIndexInfo)> for DynamicFieldInfo { parent: parent.into(), field_id: field_id.into(), dynamic_field_type: dynamic_field_type.into(), - name_type: type_tag_core_to_sdk(name_type), + name_type: type_tag_core_to_sdk(name_type).expect("object types must be valid"), name_value, dynamic_object_id: dynamic_object_id.map(Into::into), } diff --git a/crates/sui-rest-api/src/reader.rs b/crates/sui-rest-api/src/reader.rs index 30b2f8c2271b7..810b2c8aa8827 100644 --- a/crates/sui-rest-api/src/reader.rs +++ b/crates/sui-rest-api/src/reader.rs @@ -26,20 +26,22 @@ impl StateReader { &self.inner } - pub fn get_object(&self, object_id: ObjectId) -> Result> { + pub fn get_object(&self, object_id: ObjectId) -> crate::Result> { self.inner .get_object(&object_id.into()) - .map(|maybe| maybe.map(Into::into)) + .map_err(Into::into) + .and_then(|maybe| maybe.map(TryInto::try_into).transpose().map_err(Into::into)) } pub fn get_object_with_version( &self, object_id: ObjectId, version: Version, - ) -> Result> { + ) -> crate::Result> { self.inner .get_object_by_key(&object_id.into(), version.into()) - .map(|maybe| maybe.map(Into::into)) + .map_err(Into::into) + .and_then(|maybe| maybe.map(TryInto::try_into).transpose().map_err(Into::into)) } pub fn get_committee(&self, epoch: EpochId) -> Result> { @@ -90,7 +92,11 @@ impl StateReader { None }; - Ok((transaction.into(), effects.into(), events.map(Into::into))) + Ok(( + transaction.try_into()?, + effects.try_into()?, + events.map(TryInto::try_into).transpose()?, + )) } pub fn get_transaction_response( diff --git a/crates/sui-rest-api/src/transactions/execution.rs b/crates/sui-rest-api/src/transactions/execution.rs index 9611b82c4bf15..2711c4ff6f898 100644 --- a/crates/sui-rest-api/src/transactions/execution.rs +++ b/crates/sui-rest-api/src/transactions/execution.rs @@ -74,7 +74,7 @@ async fn execute_transaction( ) -> Result> { let executor = state.ok_or_else(|| anyhow::anyhow!("No Transaction Executor"))?; let request = sui_types::quorum_driver_types::ExecuteTransactionRequestV3 { - transaction: transaction.into(), + transaction: transaction.try_into()?, include_events: parameters.events, include_input_objects: parameters.input_objects || parameters.balance_changes, include_output_objects: parameters.output_objects || parameters.balance_changes, @@ -108,19 +108,31 @@ async fn execute_transaction( ) => EffectsFinality::Checkpointed { checkpoint }, }; - (effects.into(), finality) + (effects.try_into()?, finality) }; let events = if parameters.events { - events.map(Into::into) + events.map(TryInto::try_into).transpose()? } else { None }; - let input_objects = - input_objects.map(|objects| objects.into_iter().map(Into::into).collect::>()); - let output_objects = - output_objects.map(|objects| objects.into_iter().map(Into::into).collect::>()); + let input_objects = input_objects + .map(|objects| { + objects + .into_iter() + .map(TryInto::try_into) + .collect::, _>>() + }) + .transpose()?; + let output_objects = output_objects + .map(|objects| { + objects + .into_iter() + .map(TryInto::try_into) + .collect::, _>>() + }) + .transpose()?; let balance_changes = match (parameters.balance_changes, &input_objects, &output_objects) { (true, Some(input_objects), Some(output_objects)) => Some(derive_balance_changes( diff --git a/crates/sui-types/src/sui_sdk2_conversions.rs b/crates/sui-types/src/sui_sdk2_conversions.rs index 88a73019cd19d..e7a03d77a94a9 100644 --- a/crates/sui-types/src/sui_sdk2_conversions.rs +++ b/crates/sui-types/src/sui_sdk2_conversions.rs @@ -10,20 +10,68 @@ use fastcrypto::traits::ToFromBytes; use sui_sdk2::types::*; +use tap::Pipe; + +#[derive(Debug)] +pub struct SdkTypeConversionError(String); + +impl std::fmt::Display for SdkTypeConversionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0) + } +} + +impl std::error::Error for SdkTypeConversionError {} + +impl From for SdkTypeConversionError { + fn from(value: TypeParseError) -> Self { + Self(value.to_string()) + } +} + +impl From for SdkTypeConversionError { + fn from(value: anyhow::Error) -> Self { + Self(value.to_string()) + } +} + +impl From for SdkTypeConversionError { + fn from(value: bcs::Error) -> Self { + Self(value.to_string()) + } +} macro_rules! bcs_convert_impl { ($core:ty, $external:ty) => { - impl From<$core> for $external { - fn from(value: $core) -> Self { - let bytes = bcs::to_bytes(&value).unwrap(); - bcs::from_bytes(&bytes).unwrap() + // impl From<$core> for $external { + // fn from(value: $core) -> Self { + // let bytes = bcs::to_bytes(&value).unwrap(); + // bcs::from_bytes(&bytes).unwrap() + // } + // } + + // impl From<$external> for $core { + // fn from(value: $external) -> Self { + // let bytes = bcs::to_bytes(&value).unwrap(); + // bcs::from_bytes(&bytes).unwrap() + // } + // } + + impl TryFrom<$core> for $external { + type Error = bcs::Error; + + fn try_from(value: $core) -> Result { + let bytes = bcs::to_bytes(&value)?; + bcs::from_bytes(&bytes) } } - impl From<$external> for $core { - fn from(value: $external) -> Self { - let bytes = bcs::to_bytes(&value).unwrap(); - bcs::from_bytes(&bytes).unwrap() + impl TryFrom<$external> for $core { + type Error = bcs::Error; + + fn try_from(value: $external) -> Result { + let bytes = bcs::to_bytes(&value)?; + bcs::from_bytes(&bytes) } } }; @@ -151,47 +199,65 @@ impl From for crate::base_types::SuiAddress { } } -impl From for SignedTransaction { - fn from(value: crate::transaction::SenderSignedData) -> Self { +impl TryFrom for SignedTransaction { + type Error = SdkTypeConversionError; + + fn try_from(value: crate::transaction::SenderSignedData) -> Result { let crate::transaction::SenderSignedTransaction { intent_message, tx_signatures, } = value.into_inner(); Self { - transaction: intent_message.value.into(), - signatures: tx_signatures.into_iter().map(Into::into).collect(), + transaction: intent_message.value.try_into()?, + signatures: tx_signatures + .into_iter() + .map(TryInto::try_into) + .collect::>()?, } + .pipe(Ok) } } -impl From for crate::transaction::SenderSignedData { - fn from(value: SignedTransaction) -> Self { +impl TryFrom for crate::transaction::SenderSignedData { + type Error = SdkTypeConversionError; + + fn try_from(value: SignedTransaction) -> Result { let SignedTransaction { transaction, signatures, } = value; Self::new( - transaction.into(), - signatures.into_iter().map(Into::into).collect(), + transaction.try_into()?, + signatures + .into_iter() + .map(TryInto::try_into) + .collect::>()?, ) + .pipe(Ok) } } -impl From for SignedTransaction { - fn from(value: crate::transaction::Transaction) -> Self { - value.into_data().into() +impl TryFrom for SignedTransaction { + type Error = SdkTypeConversionError; + + fn try_from(value: crate::transaction::Transaction) -> Result { + value.into_data().try_into() } } -impl From for crate::transaction::Transaction { - fn from(value: SignedTransaction) -> Self { - Self::new(value.into()) +impl TryFrom for crate::transaction::Transaction { + type Error = SdkTypeConversionError; + + fn try_from(value: SignedTransaction) -> Result { + Ok(Self::new(value.try_into()?)) } } -pub fn type_tag_core_to_sdk(value: move_core_types::language_storage::TypeTag) -> TypeTag { +pub fn type_tag_core_to_sdk( + value: move_core_types::language_storage::TypeTag, +) -> Result { match value { move_core_types::language_storage::TypeTag::Bool => TypeTag::Bool, move_core_types::language_storage::TypeTag::U8 => TypeTag::U8, @@ -200,18 +266,21 @@ pub fn type_tag_core_to_sdk(value: move_core_types::language_storage::TypeTag) - move_core_types::language_storage::TypeTag::Address => TypeTag::Address, move_core_types::language_storage::TypeTag::Signer => TypeTag::Signer, move_core_types::language_storage::TypeTag::Vector(type_tag) => { - TypeTag::Vector(Box::new(type_tag_core_to_sdk(*type_tag))) + TypeTag::Vector(Box::new(type_tag_core_to_sdk(*type_tag)?)) } move_core_types::language_storage::TypeTag::Struct(struct_tag) => { - TypeTag::Struct(Box::new(struct_tag_core_to_sdk(*struct_tag))) + TypeTag::Struct(Box::new(struct_tag_core_to_sdk(*struct_tag)?)) } move_core_types::language_storage::TypeTag::U16 => TypeTag::U16, move_core_types::language_storage::TypeTag::U32 => TypeTag::U32, move_core_types::language_storage::TypeTag::U256 => TypeTag::U256, } + .pipe(Ok) } -pub fn struct_tag_core_to_sdk(value: move_core_types::language_storage::StructTag) -> StructTag { +pub fn struct_tag_core_to_sdk( + value: move_core_types::language_storage::StructTag, +) -> Result { let move_core_types::language_storage::StructTag { address, module, @@ -220,18 +289,24 @@ pub fn struct_tag_core_to_sdk(value: move_core_types::language_storage::StructTa } = value; let address = Address::new(address.into_bytes()); - let module = Identifier::new(module.as_str()).unwrap(); - let name = Identifier::new(name.as_str()).unwrap(); - let type_params = type_params.into_iter().map(type_tag_core_to_sdk).collect(); + let module = Identifier::new(module.as_str())?; + let name = Identifier::new(name.as_str())?; + let type_params = type_params + .into_iter() + .map(type_tag_core_to_sdk) + .collect::>()?; StructTag { address, module, name, type_params, } + .pipe(Ok) } -pub fn type_tag_sdk_to_core(value: TypeTag) -> move_core_types::language_storage::TypeTag { +pub fn type_tag_sdk_to_core( + value: TypeTag, +) -> Result { match value { TypeTag::Bool => move_core_types::language_storage::TypeTag::Bool, TypeTag::U8 => move_core_types::language_storage::TypeTag::U8, @@ -240,18 +315,21 @@ pub fn type_tag_sdk_to_core(value: TypeTag) -> move_core_types::language_storage TypeTag::Address => move_core_types::language_storage::TypeTag::Address, TypeTag::Signer => move_core_types::language_storage::TypeTag::Signer, TypeTag::Vector(type_tag) => move_core_types::language_storage::TypeTag::Vector(Box::new( - type_tag_sdk_to_core(*type_tag), + type_tag_sdk_to_core(*type_tag)?, )), TypeTag::Struct(struct_tag) => move_core_types::language_storage::TypeTag::Struct( - Box::new(struct_tag_sdk_to_core(*struct_tag)), + Box::new(struct_tag_sdk_to_core(*struct_tag)?), ), TypeTag::U16 => move_core_types::language_storage::TypeTag::U16, TypeTag::U32 => move_core_types::language_storage::TypeTag::U32, TypeTag::U256 => move_core_types::language_storage::TypeTag::U256, } + .pipe(Ok) } -pub fn struct_tag_sdk_to_core(value: StructTag) -> move_core_types::language_storage::StructTag { +pub fn struct_tag_sdk_to_core( + value: StructTag, +) -> Result { let StructTag { address, module, @@ -260,15 +338,19 @@ pub fn struct_tag_sdk_to_core(value: StructTag) -> move_core_types::language_sto } = value; let address = move_core_types::account_address::AccountAddress::new(address.into_inner()); - let module = move_core_types::identifier::Identifier::new(module.into_inner()).unwrap(); - let name = move_core_types::identifier::Identifier::new(name.into_inner()).unwrap(); - let type_params = type_params.into_iter().map(type_tag_sdk_to_core).collect(); + let module = move_core_types::identifier::Identifier::new(module.into_inner())?; + let name = move_core_types::identifier::Identifier::new(name.into_inner())?; + let type_params = type_params + .into_iter() + .map(type_tag_sdk_to_core) + .collect::>()?; move_core_types::language_storage::StructTag { address, module, name, type_params, } + .pipe(Ok) } impl From for CheckpointDigest {