Skip to main content

iota_types/
iota_sdk_types_conversions.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5//! Module for conversions between iota-core types and iota-sdk types
6//!
7//! For now this module makes heavy use of the `bcs_convert_impl` macro to
8//! implement the `From` trait for converting between core and external sdk
9//! types, relying on the fact that the BCS format of these types are strictly
10//! identical. As time goes on we'll slowly hand implement these impls
11//! directly to avoid going through the BCS machinery.
12
13use fastcrypto::traits::ToFromBytes;
14use iota_sdk_types::{
15    Address, CheckpointData, CheckpointTransaction, Identifier, Object, SignedCheckpointSummary,
16    SignedTransaction, StructTag, TypeParseError, TypeTag, ValidatorAggregatedSignature,
17    ValidatorCommittee, ValidatorCommitteeMember,
18    crypto::{Bls12381PublicKey, Bls12381Signature},
19};
20use tap::Pipe;
21
22#[derive(Debug)]
23pub struct SdkTypeConversionError(pub String);
24
25impl std::fmt::Display for SdkTypeConversionError {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        f.write_str(&self.0)
28    }
29}
30
31impl std::error::Error for SdkTypeConversionError {}
32
33impl From<TypeParseError> for SdkTypeConversionError {
34    fn from(value: TypeParseError) -> Self {
35        Self(value.to_string())
36    }
37}
38
39impl From<anyhow::Error> for SdkTypeConversionError {
40    fn from(value: anyhow::Error) -> Self {
41        Self(value.to_string())
42    }
43}
44
45impl From<bcs::Error> for SdkTypeConversionError {
46    fn from(value: bcs::Error) -> Self {
47        Self(value.to_string())
48    }
49}
50
51impl TryFrom<crate::object::Object> for Object {
52    type Error = SdkTypeConversionError;
53
54    fn try_from(value: crate::object::Object) -> Result<Self, Self::Error> {
55        Self {
56            data: value.data.clone(),
57            owner: value.owner,
58            previous_transaction: value.previous_transaction,
59            storage_rebate: value.storage_rebate,
60        }
61        .pipe(Ok)
62    }
63}
64
65impl TryFrom<crate::full_checkpoint_content::CheckpointData> for CheckpointData {
66    type Error = SdkTypeConversionError;
67
68    fn try_from(
69        value: crate::full_checkpoint_content::CheckpointData,
70    ) -> Result<Self, Self::Error> {
71        Self {
72            checkpoint_summary: value.checkpoint_summary.try_into()?,
73            checkpoint_contents: value.checkpoint_contents,
74            transactions: value
75                .transactions
76                .into_iter()
77                .map(TryInto::try_into)
78                .collect::<Result<_, _>>()?,
79        }
80        .pipe(Ok)
81    }
82}
83
84impl TryFrom<CheckpointData> for crate::full_checkpoint_content::CheckpointData {
85    type Error = SdkTypeConversionError;
86
87    fn try_from(value: CheckpointData) -> Result<Self, Self::Error> {
88        Self {
89            checkpoint_summary: value.checkpoint_summary.try_into()?,
90            checkpoint_contents: value.checkpoint_contents,
91            transactions: value
92                .transactions
93                .into_iter()
94                .map(TryInto::try_into)
95                .collect::<Result<_, _>>()?,
96        }
97        .pipe(Ok)
98    }
99}
100
101impl TryFrom<crate::full_checkpoint_content::CheckpointTransaction> for CheckpointTransaction {
102    type Error = SdkTypeConversionError;
103
104    fn try_from(
105        value: crate::full_checkpoint_content::CheckpointTransaction,
106    ) -> Result<Self, Self::Error> {
107        let input_objects = value
108            .input_objects
109            .into_iter()
110            .map(TryInto::try_into)
111            .collect::<Result<_, _>>();
112        let output_objects = value
113            .output_objects
114            .into_iter()
115            .map(TryInto::try_into)
116            .collect::<Result<_, _>>();
117        match (input_objects, output_objects) {
118            (Ok(input_objects), Ok(output_objects)) => Ok(Self {
119                transaction: value.transaction.into(),
120                effects: value.effects,
121                events: value.events,
122                input_objects,
123                output_objects,
124            }),
125            (Err(e), _) | (_, Err(e)) => Err(e),
126        }
127    }
128}
129
130impl TryFrom<CheckpointTransaction> for crate::full_checkpoint_content::CheckpointTransaction {
131    type Error = SdkTypeConversionError;
132
133    fn try_from(value: CheckpointTransaction) -> Result<Self, Self::Error> {
134        let input_objects = value
135            .input_objects
136            .into_iter()
137            .map(crate::object::Object::from)
138            .collect();
139        let output_objects = value
140            .output_objects
141            .into_iter()
142            .map(crate::object::Object::from)
143            .collect();
144
145        Ok(Self {
146            transaction: value.transaction.into(),
147            effects: value.effects,
148            events: value.events,
149            input_objects,
150            output_objects,
151        })
152    }
153}
154
155impl TryFrom<crate::messages_checkpoint::CertifiedCheckpointSummary> for SignedCheckpointSummary {
156    type Error = SdkTypeConversionError;
157
158    fn try_from(
159        value: crate::messages_checkpoint::CertifiedCheckpointSummary,
160    ) -> Result<Self, Self::Error> {
161        let (data, sig) = value.into_data_and_sig();
162        Self {
163            checkpoint: data,
164            signature: sig.into(),
165        }
166        .pipe(Ok)
167    }
168}
169
170impl TryFrom<SignedCheckpointSummary> for crate::messages_checkpoint::CertifiedCheckpointSummary {
171    type Error = SdkTypeConversionError;
172
173    fn try_from(value: SignedCheckpointSummary) -> Result<Self, Self::Error> {
174        Self::new_from_data_and_sig(
175            value.checkpoint,
176            crate::crypto::AuthorityQuorumSignInfo::<true>::from(value.signature),
177        )
178        .pipe(Ok)
179    }
180}
181
182impl<const T: bool> From<crate::crypto::AuthorityQuorumSignInfo<T>>
183    for ValidatorAggregatedSignature
184{
185    fn from(value: crate::crypto::AuthorityQuorumSignInfo<T>) -> Self {
186        let crate::crypto::AuthorityQuorumSignInfo {
187            epoch,
188            signature,
189            signers_map,
190        } = value;
191
192        Self::new(
193            epoch,
194            Bls12381Signature::from_bytes(signature.as_ref()).unwrap(),
195            signers_map,
196        )
197    }
198}
199
200impl<const T: bool> From<ValidatorAggregatedSignature>
201    for crate::crypto::AuthorityQuorumSignInfo<T>
202{
203    fn from(value: ValidatorAggregatedSignature) -> Self {
204        let signers_map = value.signer_indices().collect();
205
206        Self {
207            epoch: value.epoch,
208            signature: crate::crypto::AggregateAuthoritySignature::from_bytes(
209                value.signature.bytes(),
210            )
211            .unwrap(),
212            signers_map,
213        }
214    }
215}
216
217impl From<crate::transaction::TransactionEnvelope> for SignedTransaction {
218    fn from(value: crate::transaction::TransactionEnvelope) -> Self {
219        value.into_data().into()
220    }
221}
222
223impl From<SignedTransaction> for crate::transaction::TransactionEnvelope {
224    fn from(value: SignedTransaction) -> Self {
225        Self::new(value.into())
226    }
227}
228
229pub fn type_tag_core_to_sdk(value: &move_core_types::language_storage::TypeTag) -> TypeTag {
230    match value {
231        move_core_types::language_storage::TypeTag::Bool => TypeTag::Bool,
232        move_core_types::language_storage::TypeTag::U8 => TypeTag::U8,
233        move_core_types::language_storage::TypeTag::U64 => TypeTag::U64,
234        move_core_types::language_storage::TypeTag::U128 => TypeTag::U128,
235        move_core_types::language_storage::TypeTag::Address => TypeTag::Address,
236        move_core_types::language_storage::TypeTag::Signer => TypeTag::Signer,
237        move_core_types::language_storage::TypeTag::Vector(type_tag) => {
238            TypeTag::Vector(Box::new(type_tag_core_to_sdk(type_tag)))
239        }
240        move_core_types::language_storage::TypeTag::Struct(struct_tag) => {
241            TypeTag::Struct(Box::new(struct_tag_core_to_sdk(struct_tag)))
242        }
243        move_core_types::language_storage::TypeTag::U16 => TypeTag::U16,
244        move_core_types::language_storage::TypeTag::U32 => TypeTag::U32,
245        move_core_types::language_storage::TypeTag::U256 => TypeTag::U256,
246    }
247}
248
249pub fn type_tag_sdk_to_core(value: &TypeTag) -> move_core_types::language_storage::TypeTag {
250    match value {
251        TypeTag::Bool => move_core_types::language_storage::TypeTag::Bool,
252        TypeTag::U8 => move_core_types::language_storage::TypeTag::U8,
253        TypeTag::U64 => move_core_types::language_storage::TypeTag::U64,
254        TypeTag::U128 => move_core_types::language_storage::TypeTag::U128,
255        TypeTag::Address => move_core_types::language_storage::TypeTag::Address,
256        TypeTag::Signer => move_core_types::language_storage::TypeTag::Signer,
257        TypeTag::Vector(type_tag) => move_core_types::language_storage::TypeTag::Vector(Box::new(
258            type_tag_sdk_to_core(type_tag),
259        )),
260        TypeTag::Struct(struct_tag) => move_core_types::language_storage::TypeTag::Struct(
261            Box::new(struct_tag_sdk_to_core(struct_tag)),
262        ),
263        TypeTag::U16 => move_core_types::language_storage::TypeTag::U16,
264        TypeTag::U32 => move_core_types::language_storage::TypeTag::U32,
265        TypeTag::U256 => move_core_types::language_storage::TypeTag::U256,
266    }
267}
268
269pub fn identifier_core_to_sdk(value: &move_core_types::identifier::IdentStr) -> Identifier {
270    Identifier::new_unchecked(value.as_str())
271}
272
273pub fn identifier_sdk_to_core(value: &Identifier) -> move_core_types::identifier::Identifier {
274    // SAFETY: an SDK `Identifier` is an already-validated Move identifier; preserve
275    // it verbatim without re-validation.
276    unsafe { move_core_types::identifier::Identifier::new_unchecked(value.as_str()) }
277}
278
279pub fn struct_tag_core_to_sdk(value: &move_core_types::language_storage::StructTag) -> StructTag {
280    let move_core_types::language_storage::StructTag {
281        address,
282        module,
283        name,
284        type_params,
285    } = value;
286
287    let address = Address::new(address.into_bytes());
288    let module = identifier_core_to_sdk(module);
289    let name = identifier_core_to_sdk(name);
290    let type_params = type_params.iter().map(type_tag_core_to_sdk).collect();
291    StructTag::new(address, module, name, type_params)
292}
293
294pub fn struct_tag_sdk_to_core(value: &StructTag) -> move_core_types::language_storage::StructTag {
295    let address =
296        move_core_types::account_address::AccountAddress::new(value.address().into_bytes());
297    let module = identifier_sdk_to_core(value.module());
298    let name = identifier_sdk_to_core(value.name());
299    let type_params = value
300        .type_params()
301        .iter()
302        .map(type_tag_sdk_to_core)
303        .collect();
304    move_core_types::language_storage::StructTag {
305        address,
306        module,
307        name,
308        type_params,
309    }
310}
311
312impl From<crate::committee::Committee> for ValidatorCommittee {
313    fn from(value: crate::committee::Committee) -> Self {
314        Self {
315            epoch: value.epoch(),
316            members: value
317                .voting_rights
318                .into_iter()
319                .map(|(name, stake)| ValidatorCommitteeMember {
320                    public_key: name.into(),
321                    stake,
322                })
323                .collect(),
324        }
325    }
326}
327
328impl From<ValidatorCommittee> for crate::committee::Committee {
329    fn from(value: ValidatorCommittee) -> Self {
330        let ValidatorCommittee { epoch, members } = value;
331
332        Self::new(
333            epoch,
334            members
335                .into_iter()
336                .map(|member| (member.public_key.into(), member.stake))
337                .collect(),
338        )
339    }
340}
341
342impl From<crate::crypto::AuthorityPublicKeyBytes> for Bls12381PublicKey {
343    fn from(value: crate::crypto::AuthorityPublicKeyBytes) -> Self {
344        Self::new(value.0)
345    }
346}
347
348impl From<Bls12381PublicKey> for crate::crypto::AuthorityPublicKeyBytes {
349    fn from(value: Bls12381PublicKey) -> Self {
350        Self::new(value.into_bytes())
351    }
352}