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::{
17        CheckpointCommitment, CheckpointContents, CheckpointData, CheckpointSummary,
18        CheckpointTransaction, CheckpointTransactionInfo, EndOfEpochData, SignedCheckpointSummary,
19    },
20    crypto::{Bls12381PublicKey, Bls12381Signature, UserSignature},
21    digest::Digest,
22    move_core::{Identifier, StructTag, TypeParseError, TypeTag},
23    object::Object,
24    transaction::SignedTransaction,
25    validator::{ValidatorAggregatedSignature, ValidatorCommittee, ValidatorCommitteeMember},
26};
27use tap::Pipe;
28
29use crate::object::ObjectInner;
30
31#[derive(Debug)]
32pub struct SdkTypeConversionError(pub String);
33
34impl std::fmt::Display for SdkTypeConversionError {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        f.write_str(&self.0)
37    }
38}
39
40impl std::error::Error for SdkTypeConversionError {}
41
42impl From<TypeParseError> for SdkTypeConversionError {
43    fn from(value: TypeParseError) -> Self {
44        Self(value.to_string())
45    }
46}
47
48impl From<anyhow::Error> for SdkTypeConversionError {
49    fn from(value: anyhow::Error) -> Self {
50        Self(value.to_string())
51    }
52}
53
54impl From<bcs::Error> for SdkTypeConversionError {
55    fn from(value: bcs::Error) -> Self {
56        Self(value.to_string())
57    }
58}
59
60impl TryFrom<crate::object::Object> for Object {
61    type Error = SdkTypeConversionError;
62
63    fn try_from(value: crate::object::Object) -> Result<Self, Self::Error> {
64        Self {
65            data: value.data.clone(),
66            owner: value.owner,
67            previous_transaction: value.previous_transaction,
68            storage_rebate: value.storage_rebate,
69        }
70        .pipe(Ok)
71    }
72}
73
74impl TryFrom<Object> for crate::object::Object {
75    type Error = SdkTypeConversionError;
76
77    fn try_from(value: Object) -> Result<Self, Self::Error> {
78        Self::from(ObjectInner {
79            data: value.data,
80            owner: value.owner,
81            previous_transaction: value.previous_transaction,
82            storage_rebate: value.storage_rebate,
83        })
84        .pipe(Ok)
85    }
86}
87
88impl TryFrom<crate::messages_checkpoint::CheckpointContents> for CheckpointContents {
89    type Error = SdkTypeConversionError;
90
91    fn try_from(
92        value: crate::messages_checkpoint::CheckpointContents,
93    ) -> Result<Self, Self::Error> {
94        Self(
95            value
96                .into_iter_with_signatures()
97                .map(|(digests, signatures)| {
98                    let signatures_result = signatures
99                        .into_iter()
100                        .map(TryInto::try_into)
101                        .collect::<Result<Vec<UserSignature>, _>>();
102
103                    match signatures_result {
104                        Ok(signatures) => Ok(CheckpointTransactionInfo {
105                            transaction: digests.transaction,
106                            effects: digests.effects,
107                            signatures,
108                        }),
109                        Err(e) => Err(SdkTypeConversionError::from(e)),
110                    }
111                })
112                .collect::<Result<Vec<_>, _>>()?,
113        )
114        .pipe(Ok)
115    }
116}
117
118impl TryFrom<CheckpointContents> for crate::messages_checkpoint::CheckpointContents {
119    type Error = SdkTypeConversionError;
120
121    fn try_from(value: CheckpointContents) -> Result<Self, Self::Error> {
122        let (transactions, user_signatures) = value.0.into_iter().fold(
123            (Vec::new(), Vec::new()),
124            |(mut transactions, mut user_signatures), info| {
125                transactions.push(crate::base_types::ExecutionDigests {
126                    transaction: info.transaction,
127                    effects: info.effects,
128                });
129                user_signatures.push(
130                    info.signatures
131                        .into_iter()
132                        .map(TryInto::try_into)
133                        .collect::<Result<_, _>>(),
134                );
135                (transactions, user_signatures)
136            },
137        );
138        crate::messages_checkpoint::CheckpointContents::new_with_digests_and_signatures(
139            transactions,
140            user_signatures.into_iter().collect::<Result<Vec<_>, _>>()?,
141        )
142        .pipe(Ok)
143    }
144}
145
146impl TryFrom<crate::full_checkpoint_content::CheckpointData> for CheckpointData {
147    type Error = SdkTypeConversionError;
148
149    fn try_from(
150        value: crate::full_checkpoint_content::CheckpointData,
151    ) -> Result<Self, Self::Error> {
152        Self {
153            checkpoint_summary: value.checkpoint_summary.try_into()?,
154            checkpoint_contents: value.checkpoint_contents.try_into()?,
155            transactions: value
156                .transactions
157                .into_iter()
158                .map(TryInto::try_into)
159                .collect::<Result<_, _>>()?,
160        }
161        .pipe(Ok)
162    }
163}
164
165impl TryFrom<CheckpointData> for crate::full_checkpoint_content::CheckpointData {
166    type Error = SdkTypeConversionError;
167
168    fn try_from(value: CheckpointData) -> Result<Self, Self::Error> {
169        Self {
170            checkpoint_summary: value.checkpoint_summary.try_into()?,
171            checkpoint_contents: value.checkpoint_contents.try_into()?,
172            transactions: value
173                .transactions
174                .into_iter()
175                .map(TryInto::try_into)
176                .collect::<Result<_, _>>()?,
177        }
178        .pipe(Ok)
179    }
180}
181
182impl TryFrom<crate::full_checkpoint_content::CheckpointTransaction> for CheckpointTransaction {
183    type Error = SdkTypeConversionError;
184
185    fn try_from(
186        value: crate::full_checkpoint_content::CheckpointTransaction,
187    ) -> Result<Self, Self::Error> {
188        let input_objects = value
189            .input_objects
190            .into_iter()
191            .map(TryInto::try_into)
192            .collect::<Result<_, _>>();
193        let output_objects = value
194            .output_objects
195            .into_iter()
196            .map(TryInto::try_into)
197            .collect::<Result<_, _>>();
198        match (input_objects, output_objects) {
199            (Ok(input_objects), Ok(output_objects)) => Ok(Self {
200                transaction: value.transaction.try_into()?,
201                effects: value.effects,
202                events: value.events,
203                input_objects,
204                output_objects,
205            }),
206            (Err(e), _) | (_, Err(e)) => Err(e),
207        }
208    }
209}
210
211impl TryFrom<CheckpointTransaction> for crate::full_checkpoint_content::CheckpointTransaction {
212    type Error = SdkTypeConversionError;
213
214    fn try_from(value: CheckpointTransaction) -> Result<Self, Self::Error> {
215        let input_objects = value
216            .input_objects
217            .into_iter()
218            .map(TryInto::try_into)
219            .collect::<Result<_, _>>();
220        let output_objects = value
221            .output_objects
222            .into_iter()
223            .map(TryInto::try_into)
224            .collect::<Result<_, _>>();
225
226        match (input_objects, output_objects) {
227            (Ok(input_objects), Ok(output_objects)) => Ok(Self {
228                transaction: value.transaction.try_into()?,
229                effects: value.effects,
230                events: value.events,
231                input_objects,
232                output_objects,
233            }),
234            (Err(e), _) | (_, Err(e)) => Err(e),
235        }
236    }
237}
238
239impl TryFrom<crate::signature::GenericSignature> for UserSignature {
240    type Error = bcs::Error;
241
242    fn try_from(value: crate::signature::GenericSignature) -> Result<Self, Self::Error> {
243        bcs::from_bytes(&bcs::to_bytes(&value)?)
244    }
245}
246
247impl TryFrom<UserSignature> for crate::signature::GenericSignature {
248    type Error = bcs::Error;
249
250    fn try_from(value: UserSignature) -> Result<Self, Self::Error> {
251        bcs::from_bytes(&bcs::to_bytes(&value)?)
252    }
253}
254
255impl From<crate::messages_checkpoint::EndOfEpochData> for EndOfEpochData {
256    fn from(value: crate::messages_checkpoint::EndOfEpochData) -> Self {
257        Self {
258            next_epoch_committee: value
259                .next_epoch_committee
260                .into_iter()
261                .map(|(public_key, stake)| ValidatorCommitteeMember {
262                    public_key: Bls12381PublicKey::new(public_key.0),
263                    stake,
264                })
265                .collect(),
266            next_epoch_protocol_version: value.next_epoch_protocol_version.as_u64(),
267            epoch_commitments: value
268                .epoch_commitments
269                .into_iter()
270                .map(Into::into)
271                .collect(),
272            epoch_supply_change: value.epoch_supply_change,
273        }
274    }
275}
276
277impl From<EndOfEpochData> for crate::messages_checkpoint::EndOfEpochData {
278    fn from(value: EndOfEpochData) -> Self {
279        Self {
280            next_epoch_committee: value
281                .next_epoch_committee
282                .into_iter()
283                .map(|v| (v.public_key.into(), v.stake))
284                .collect(),
285            next_epoch_protocol_version: value.next_epoch_protocol_version.into(),
286            epoch_commitments: value
287                .epoch_commitments
288                .into_iter()
289                .map(Into::into)
290                .collect(),
291            epoch_supply_change: value.epoch_supply_change,
292        }
293    }
294}
295
296impl From<crate::messages_checkpoint::CheckpointCommitment> for CheckpointCommitment {
297    fn from(value: crate::messages_checkpoint::CheckpointCommitment) -> Self {
298        let crate::messages_checkpoint::CheckpointCommitment::ECMHLiveObjectSetDigest(digest) =
299            value;
300        Self::EcmhLiveObjectSet {
301            digest: Digest::new(digest.digest.into_inner()),
302        }
303    }
304}
305
306impl From<CheckpointCommitment> for crate::messages_checkpoint::CheckpointCommitment {
307    fn from(value: CheckpointCommitment) -> Self {
308        match value {
309            CheckpointCommitment::EcmhLiveObjectSet { digest } => {
310                Self::ECMHLiveObjectSetDigest(crate::messages_checkpoint::ECMHLiveObjectSetDigest {
311                    digest: crate::digests::Digest::new(digest.into_inner()),
312                })
313            }
314            _ => unimplemented!(
315                "a new CheckpointCommitment enum variant was added and needs to be handled"
316            ),
317        }
318    }
319}
320
321impl TryFrom<crate::messages_checkpoint::CheckpointSummary> for CheckpointSummary {
322    type Error = SdkTypeConversionError;
323
324    fn try_from(value: crate::messages_checkpoint::CheckpointSummary) -> Result<Self, Self::Error> {
325        Self {
326            epoch: value.epoch,
327            sequence_number: value.sequence_number,
328            network_total_transactions: value.network_total_transactions,
329            content_digest: value.content_digest,
330            previous_digest: value.previous_digest,
331            epoch_rolling_gas_cost_summary: value.epoch_rolling_gas_cost_summary,
332            timestamp_ms: value.timestamp_ms,
333            checkpoint_commitments: value
334                .checkpoint_commitments
335                .into_iter()
336                .map(Into::into)
337                .collect(),
338            end_of_epoch_data: value.end_of_epoch_data.map(Into::into),
339            version_specific_data: value.version_specific_data,
340        }
341        .pipe(Ok)
342    }
343}
344
345impl TryFrom<CheckpointSummary> for crate::messages_checkpoint::CheckpointSummary {
346    type Error = SdkTypeConversionError;
347
348    fn try_from(value: CheckpointSummary) -> Result<Self, Self::Error> {
349        Self {
350            epoch: value.epoch,
351            sequence_number: value.sequence_number,
352            network_total_transactions: value.network_total_transactions,
353            content_digest: value.content_digest,
354            previous_digest: value.previous_digest,
355            epoch_rolling_gas_cost_summary: value.epoch_rolling_gas_cost_summary,
356            timestamp_ms: value.timestamp_ms,
357            checkpoint_commitments: value
358                .checkpoint_commitments
359                .into_iter()
360                .map(Into::into)
361                .collect(),
362            end_of_epoch_data: value.end_of_epoch_data.map(Into::into),
363            version_specific_data: value.version_specific_data,
364        }
365        .pipe(Ok)
366    }
367}
368
369impl TryFrom<crate::messages_checkpoint::CertifiedCheckpointSummary> for SignedCheckpointSummary {
370    type Error = SdkTypeConversionError;
371
372    fn try_from(
373        value: crate::messages_checkpoint::CertifiedCheckpointSummary,
374    ) -> Result<Self, Self::Error> {
375        let (data, sig) = value.into_data_and_sig();
376        Self {
377            checkpoint: data.try_into()?,
378            signature: sig.into(),
379        }
380        .pipe(Ok)
381    }
382}
383
384impl TryFrom<SignedCheckpointSummary> for crate::messages_checkpoint::CertifiedCheckpointSummary {
385    type Error = SdkTypeConversionError;
386
387    fn try_from(value: SignedCheckpointSummary) -> Result<Self, Self::Error> {
388        Self::new_from_data_and_sig(
389            crate::messages_checkpoint::CheckpointSummary::try_from(value.checkpoint)?,
390            crate::crypto::AuthorityQuorumSignInfo::<true>::from(value.signature),
391        )
392        .pipe(Ok)
393    }
394}
395
396impl<const T: bool> From<crate::crypto::AuthorityQuorumSignInfo<T>>
397    for ValidatorAggregatedSignature
398{
399    fn from(value: crate::crypto::AuthorityQuorumSignInfo<T>) -> Self {
400        let crate::crypto::AuthorityQuorumSignInfo {
401            epoch,
402            signature,
403            signers_map,
404        } = value;
405
406        Self {
407            epoch,
408            signature: Bls12381Signature::from_bytes(signature.as_ref()).unwrap(),
409            bitmap: signers_map,
410        }
411    }
412}
413
414impl<const T: bool> From<ValidatorAggregatedSignature>
415    for crate::crypto::AuthorityQuorumSignInfo<T>
416{
417    fn from(value: ValidatorAggregatedSignature) -> Self {
418        let ValidatorAggregatedSignature {
419            epoch,
420            signature,
421            bitmap,
422        } = value;
423
424        Self {
425            epoch,
426            signature: crate::crypto::AggregateAuthoritySignature::from_bytes(signature.as_bytes())
427                .unwrap(),
428            signers_map: bitmap,
429        }
430    }
431}
432
433impl TryFrom<crate::transaction::SenderSignedData> for SignedTransaction {
434    type Error = SdkTypeConversionError;
435
436    fn try_from(value: crate::transaction::SenderSignedData) -> Result<Self, Self::Error> {
437        let crate::transaction::SenderSignedTransaction {
438            intent_message,
439            tx_signatures,
440        } = value.into_inner();
441
442        Self {
443            transaction: intent_message.value,
444            signatures: tx_signatures
445                .into_iter()
446                .map(TryInto::try_into)
447                .collect::<Result<_, _>>()?,
448        }
449        .pipe(Ok)
450    }
451}
452
453impl TryFrom<SignedTransaction> for crate::transaction::SenderSignedData {
454    type Error = SdkTypeConversionError;
455
456    fn try_from(value: SignedTransaction) -> Result<Self, Self::Error> {
457        let SignedTransaction {
458            transaction,
459            signatures,
460        } = value;
461
462        Self::new(
463            transaction,
464            signatures
465                .into_iter()
466                .map(TryInto::try_into)
467                .collect::<Result<_, _>>()?,
468        )
469        .pipe(Ok)
470    }
471}
472
473impl TryFrom<crate::transaction::Transaction> for SignedTransaction {
474    type Error = SdkTypeConversionError;
475
476    fn try_from(value: crate::transaction::Transaction) -> Result<Self, Self::Error> {
477        value.into_data().try_into()
478    }
479}
480
481impl TryFrom<SignedTransaction> for crate::transaction::Transaction {
482    type Error = SdkTypeConversionError;
483
484    fn try_from(value: SignedTransaction) -> Result<Self, Self::Error> {
485        Ok(Self::new(value.try_into()?))
486    }
487}
488
489pub fn type_tag_core_to_sdk(value: &move_core_types::language_storage::TypeTag) -> TypeTag {
490    match value {
491        move_core_types::language_storage::TypeTag::Bool => TypeTag::Bool,
492        move_core_types::language_storage::TypeTag::U8 => TypeTag::U8,
493        move_core_types::language_storage::TypeTag::U64 => TypeTag::U64,
494        move_core_types::language_storage::TypeTag::U128 => TypeTag::U128,
495        move_core_types::language_storage::TypeTag::Address => TypeTag::Address,
496        move_core_types::language_storage::TypeTag::Signer => TypeTag::Signer,
497        move_core_types::language_storage::TypeTag::Vector(type_tag) => {
498            TypeTag::Vector(Box::new(type_tag_core_to_sdk(type_tag)))
499        }
500        move_core_types::language_storage::TypeTag::Struct(struct_tag) => {
501            TypeTag::Struct(Box::new(struct_tag_core_to_sdk(struct_tag)))
502        }
503        move_core_types::language_storage::TypeTag::U16 => TypeTag::U16,
504        move_core_types::language_storage::TypeTag::U32 => TypeTag::U32,
505        move_core_types::language_storage::TypeTag::U256 => TypeTag::U256,
506    }
507}
508
509pub fn type_tag_sdk_to_core(value: &TypeTag) -> move_core_types::language_storage::TypeTag {
510    match value {
511        TypeTag::Bool => move_core_types::language_storage::TypeTag::Bool,
512        TypeTag::U8 => move_core_types::language_storage::TypeTag::U8,
513        TypeTag::U64 => move_core_types::language_storage::TypeTag::U64,
514        TypeTag::U128 => move_core_types::language_storage::TypeTag::U128,
515        TypeTag::Address => move_core_types::language_storage::TypeTag::Address,
516        TypeTag::Signer => move_core_types::language_storage::TypeTag::Signer,
517        TypeTag::Vector(type_tag) => move_core_types::language_storage::TypeTag::Vector(Box::new(
518            type_tag_sdk_to_core(type_tag),
519        )),
520        TypeTag::Struct(struct_tag) => move_core_types::language_storage::TypeTag::Struct(
521            Box::new(struct_tag_sdk_to_core(struct_tag)),
522        ),
523        TypeTag::U16 => move_core_types::language_storage::TypeTag::U16,
524        TypeTag::U32 => move_core_types::language_storage::TypeTag::U32,
525        TypeTag::U256 => move_core_types::language_storage::TypeTag::U256,
526    }
527}
528
529pub fn struct_tag_core_to_sdk(value: &move_core_types::language_storage::StructTag) -> StructTag {
530    let move_core_types::language_storage::StructTag {
531        address,
532        module,
533        name,
534        type_params,
535    } = value;
536
537    let address = Address::new(address.into_bytes());
538    let module = Identifier::new_unchecked(module.as_str());
539    let name = Identifier::new_unchecked(name.as_str());
540    let type_params = type_params.iter().map(type_tag_core_to_sdk).collect();
541    StructTag::new(address, module, name, type_params)
542}
543
544pub fn struct_tag_sdk_to_core(value: &StructTag) -> move_core_types::language_storage::StructTag {
545    let address =
546        move_core_types::account_address::AccountAddress::new(value.address().into_bytes());
547    let module = move_core_types::identifier::Identifier::new(value.module().as_str()).unwrap();
548    let name = move_core_types::identifier::Identifier::new(value.name().as_str()).unwrap();
549    let type_params = value
550        .type_params()
551        .iter()
552        .map(type_tag_sdk_to_core)
553        .collect();
554    move_core_types::language_storage::StructTag {
555        address,
556        module,
557        name,
558        type_params,
559    }
560}
561
562impl From<crate::committee::Committee> for ValidatorCommittee {
563    fn from(value: crate::committee::Committee) -> Self {
564        Self {
565            epoch: value.epoch(),
566            members: value
567                .voting_rights
568                .into_iter()
569                .map(|(name, stake)| ValidatorCommitteeMember {
570                    public_key: name.into(),
571                    stake,
572                })
573                .collect(),
574        }
575    }
576}
577
578impl From<ValidatorCommittee> for crate::committee::Committee {
579    fn from(value: ValidatorCommittee) -> Self {
580        let ValidatorCommittee { epoch, members } = value;
581
582        Self::new(
583            epoch,
584            members
585                .into_iter()
586                .map(|member| (member.public_key.into(), member.stake))
587                .collect(),
588        )
589    }
590}
591
592impl From<crate::crypto::AuthorityPublicKeyBytes> for Bls12381PublicKey {
593    fn from(value: crate::crypto::AuthorityPublicKeyBytes) -> Self {
594        Self::new(value.0)
595    }
596}
597
598impl From<Bls12381PublicKey> for crate::crypto::AuthorityPublicKeyBytes {
599    fn from(value: Bls12381PublicKey) -> Self {
600        Self::new(value.into_inner())
601    }
602}