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