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