iota_types/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5#![warn(
6    future_incompatible,
7    nonstandard_style,
8    rust_2018_idioms,
9    rust_2021_compatibility
10)]
11
12use base_types::{IotaAddress, ObjectID, SequenceNumber};
13pub use iota_network_stack::multiaddr;
14use move_binary_format::{
15    CompiledModule,
16    file_format::{AbilitySet, SignatureToken},
17};
18use move_bytecode_utils::resolve_struct;
19use move_core_types::{
20    account_address::AccountAddress,
21    language_storage::{ModuleId, StructTag},
22};
23pub use move_core_types::{identifier::Identifier, language_storage::TypeTag};
24use object::OBJECT_START_VERSION;
25
26use crate::{
27    base_types::{RESOLVED_ASCII_STR, RESOLVED_STD_OPTION, RESOLVED_UTF8_STR},
28    id::RESOLVED_IOTA_ID,
29};
30
31#[macro_use]
32pub mod error;
33
34pub mod account_abstraction;
35pub mod accumulator;
36pub mod auth_context;
37pub mod authenticator_state;
38pub mod balance;
39pub mod base_types;
40pub mod clock;
41pub mod coin;
42pub mod coin_manager;
43pub mod collection_types;
44pub mod committee;
45pub mod config;
46pub mod crypto;
47pub mod deny_list_v1;
48pub mod derived_object;
49pub mod digests;
50pub mod display;
51pub mod dynamic_field;
52pub mod effects;
53pub mod epoch_data;
54pub mod event;
55pub mod executable_transaction;
56pub mod execution;
57pub mod execution_config_utils;
58pub mod execution_status;
59pub mod full_checkpoint_content;
60pub mod gas;
61pub mod gas_coin;
62pub mod gas_model;
63pub mod governance;
64pub mod id;
65pub mod in_memory_storage;
66pub mod inner_temporary_store;
67pub mod iota_sdk_types_conversions;
68pub mod iota_serde;
69pub mod iota_system_state;
70pub mod layout_resolver;
71pub mod message_envelope;
72pub mod messages_checkpoint;
73pub mod messages_consensus;
74pub mod messages_grpc;
75pub mod messages_safe_client;
76pub mod metrics;
77pub mod mock_checkpoint_builder;
78pub mod move_authenticator;
79pub mod move_package;
80pub mod multisig;
81pub mod object;
82pub mod passkey_authenticator;
83pub mod programmable_transaction_builder;
84pub mod proto_value;
85pub mod quorum_driver_types;
86pub mod randomness_state;
87pub mod scoring_metrics;
88pub mod signature;
89pub mod signature_verification;
90pub mod stardust;
91pub mod storage;
92pub mod supported_protocol_versions;
93pub mod system_admin_cap;
94pub mod test_checkpoint_data_builder;
95pub mod timelock;
96pub mod traffic_control;
97pub mod transaction;
98pub mod transaction_executor;
99pub mod transfer;
100pub mod type_input;
101pub mod versioned;
102pub mod zk_login_authenticator;
103pub mod zk_login_util;
104
105#[path = "./unit_tests/utils.rs"]
106pub mod utils;
107
108macro_rules! built_in_ids {
109    ($($addr:ident / $id:ident = $init:expr);* $(;)?) => {
110        $(
111            pub const $addr: AccountAddress = builtin_address($init);
112            pub const $id: ObjectID = ObjectID::from_address($addr);
113        )*
114    }
115}
116
117macro_rules! built_in_pkgs {
118    ($($addr:ident / $id:ident = $init:expr);* $(;)?) => {
119        built_in_ids! { $($addr / $id = $init;)* }
120        pub const SYSTEM_PACKAGE_ADDRESSES: &[AccountAddress] = &[$($addr),*];
121        pub fn is_system_package(addr: impl Into<AccountAddress>) -> bool {
122            matches!(addr.into(), $($addr)|*)
123        }
124    }
125}
126
127built_in_pkgs! {
128    MOVE_STDLIB_ADDRESS / MOVE_STDLIB_PACKAGE_ID = 0x1;
129    IOTA_FRAMEWORK_ADDRESS / IOTA_FRAMEWORK_PACKAGE_ID = 0x2;
130    IOTA_SYSTEM_ADDRESS / IOTA_SYSTEM_PACKAGE_ID = 0x3;
131    GENESIS_BRIDGE_ADDRESS / GENESIS_BRIDGE_PACKAGE_ID = 0xb;
132    STARDUST_ADDRESS / STARDUST_PACKAGE_ID = 0x107a;
133}
134
135built_in_ids! {
136    IOTA_SYSTEM_STATE_ADDRESS / IOTA_SYSTEM_STATE_OBJECT_ID = 0x5;
137    IOTA_CLOCK_ADDRESS / IOTA_CLOCK_OBJECT_ID = 0x6;
138    IOTA_AUTHENTICATOR_STATE_ADDRESS / IOTA_AUTHENTICATOR_STATE_OBJECT_ID = 0x7;
139    IOTA_RANDOMNESS_STATE_ADDRESS / IOTA_RANDOMNESS_STATE_OBJECT_ID = 0x8;
140    GENESIS_IOTA_BRIDGE_ADDRESS / GENESIS_IOTA_BRIDGE_OBJECT_ID = 0x9;
141    IOTA_DENY_LIST_ADDRESS / IOTA_DENY_LIST_OBJECT_ID = 0x403;
142}
143
144pub const IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
145pub const IOTA_CLOCK_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
146pub const IOTA_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
147
148const fn builtin_address(suffix: u16) -> AccountAddress {
149    let mut addr = [0u8; AccountAddress::LENGTH];
150    let [hi, lo] = suffix.to_be_bytes();
151    addr[AccountAddress::LENGTH - 2] = hi;
152    addr[AccountAddress::LENGTH - 1] = lo;
153    AccountAddress::new(addr)
154}
155
156pub fn iota_framework_address_concat_string(suffix: &str) -> String {
157    format!("{}{suffix}", IOTA_FRAMEWORK_ADDRESS.to_hex_literal())
158}
159
160/// Parses `s` as an address. Valid formats for addresses are:
161///
162/// - A 256bit number, encoded in decimal, or hexadecimal with a leading "0x"
163///   prefix.
164/// - One of a number of pre-defined named addresses: std, iota, iota_system,
165///   stardust.
166///
167/// Parsing succeeds if and only if `s` matches one of these formats exactly,
168/// with no remaining suffix. This function is intended for use within the
169/// authority codebases.
170pub fn parse_iota_address(s: &str) -> anyhow::Result<IotaAddress> {
171    use move_core_types::parsing::address::ParsedAddress;
172    Ok(ParsedAddress::parse(s)?
173        .into_account_address(&resolve_address)?
174        .into())
175}
176
177/// Parse `s` as a Module ID: An address (see `parse_iota_address`), followed by
178/// `::`, and then a module name (an identifier). Parsing succeeds if and only
179/// if `s` matches this format exactly, with no remaining input. This function
180/// is intended for use within the authority codebases.
181pub fn parse_iota_module_id(s: &str) -> anyhow::Result<ModuleId> {
182    use move_core_types::parsing::types::ParsedModuleId;
183    ParsedModuleId::parse(s)?.into_module_id(&resolve_address)
184}
185
186/// Parse `s` as a fully-qualified name: A Module ID (see
187/// `parse_iota_module_id`), followed by `::`, and then an identifier (for the
188/// module member). Parsing succeeds if and only if `s` matches this
189/// format exactly, with no remaining input. This function is intended for use
190/// within the authority codebases.
191pub fn parse_iota_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> {
192    use move_core_types::parsing::types::ParsedFqName;
193    ParsedFqName::parse(s)?.into_fq_name(&resolve_address)
194}
195
196/// Parse `s` as a struct type: A fully-qualified name, optionally followed by a
197/// list of type parameters (types -- see `parse_iota_type_tag`, separated by
198/// commas, surrounded by angle brackets). Parsing succeeds if and only if `s`
199/// matches this format exactly, with no remaining input. This function is
200/// intended for use within the authority codebase.
201pub fn parse_iota_struct_tag(s: &str) -> anyhow::Result<StructTag> {
202    use move_core_types::parsing::types::ParsedStructType;
203    ParsedStructType::parse(s)?.into_struct_tag(&resolve_address)
204}
205
206/// Parse `s` as a type: Either a struct type (see `parse_iota_struct_tag`), a
207/// primitive type, or a vector with a type parameter. Parsing succeeds if and
208/// only if `s` matches this format exactly, with no remaining input. This
209/// function is intended for use within the authority codebase.
210pub fn parse_iota_type_tag(s: &str) -> anyhow::Result<TypeTag> {
211    use move_core_types::parsing::types::ParsedType;
212    ParsedType::parse(s)?.into_type_tag(&resolve_address)
213}
214
215/// Resolve well-known named addresses into numeric addresses.
216pub fn resolve_address(addr: &str) -> Option<AccountAddress> {
217    match addr {
218        "std" => Some(MOVE_STDLIB_ADDRESS),
219        "iota" => Some(IOTA_FRAMEWORK_ADDRESS),
220        "iota_system" => Some(IOTA_SYSTEM_ADDRESS),
221        "stardust" => Some(STARDUST_ADDRESS),
222        _ => None,
223    }
224}
225
226pub trait MoveTypeTagTrait {
227    fn get_type_tag() -> TypeTag;
228}
229
230impl MoveTypeTagTrait for u8 {
231    fn get_type_tag() -> TypeTag {
232        TypeTag::U8
233    }
234}
235
236impl MoveTypeTagTrait for u64 {
237    fn get_type_tag() -> TypeTag {
238        TypeTag::U64
239    }
240}
241
242impl MoveTypeTagTrait for ObjectID {
243    fn get_type_tag() -> TypeTag {
244        TypeTag::Address
245    }
246}
247
248impl MoveTypeTagTrait for IotaAddress {
249    fn get_type_tag() -> TypeTag {
250        TypeTag::Address
251    }
252}
253
254impl<T: MoveTypeTagTrait> MoveTypeTagTrait for Vec<T> {
255    fn get_type_tag() -> TypeTag {
256        TypeTag::Vector(Box::new(T::get_type_tag()))
257    }
258}
259
260/// Check if a type is a primitive type in optimistic mode. It invokes the inner
261/// function with is_strict = false.
262pub fn is_primitive(
263    view: &CompiledModule,
264    function_type_args: &[AbilitySet],
265    s: &SignatureToken,
266) -> bool {
267    is_primitive_inner(view, function_type_args, s, false)
268}
269
270/// Check if a type is a primitive type in strict mode. It invokes the inner
271/// function with is_strict = true.
272pub fn is_primitive_strict(
273    view: &CompiledModule,
274    function_type_args: &[AbilitySet],
275    s: &SignatureToken,
276) -> bool {
277    is_primitive_inner(view, function_type_args, s, true)
278}
279
280/// Check if a type is a primitive type.
281/// In optimistic mode (is_strict = false), a type parameter is considered
282/// primitive if it has no key ability. In strict mode (is_strict = true), a
283/// type parameter is considered primitive if it has at least copy or drop
284/// ability.
285pub fn is_primitive_inner(
286    view: &CompiledModule,
287    function_type_args: &[AbilitySet],
288    s: &SignatureToken,
289    is_strict: bool,
290) -> bool {
291    use SignatureToken as S;
292    match s {
293        S::Bool | S::U8 | S::U16 | S::U32 | S::U64 | S::U128 | S::U256 | S::Address => true,
294        S::Signer => false,
295        // optimistic -> no primitive has key
296        // strict -> all primitives have at least copy or drop
297        S::TypeParameter(idx) => {
298            if !is_strict {
299                // optimistic: has no key
300                !function_type_args[*idx as usize].has_key()
301            } else {
302                // strict: has at least one of: copy or drop (or store and one of the others).
303                // copy or drop abilities always imply having no key, but here we double check
304                let abilities = function_type_args[*idx as usize];
305                !abilities.has_key() && (abilities.has_copy() || abilities.has_drop())
306            }
307        }
308
309        S::Datatype(idx) => [RESOLVED_IOTA_ID, RESOLVED_ASCII_STR, RESOLVED_UTF8_STR]
310            .contains(&resolve_struct(view, *idx)),
311
312        S::DatatypeInstantiation(inst) => {
313            let (idx, targs) = &**inst;
314            let resolved_struct = resolve_struct(view, *idx);
315            // option is a primitive
316            resolved_struct == RESOLVED_STD_OPTION
317                && targs.len() == 1
318                && is_primitive_inner(view, function_type_args, &targs[0], is_strict)
319        }
320
321        S::Vector(inner) => is_primitive_inner(view, function_type_args, inner, is_strict),
322        S::Reference(_) | S::MutableReference(_) => false,
323    }
324}
325
326pub fn is_object(
327    view: &CompiledModule,
328    function_type_args: &[AbilitySet],
329    t: &SignatureToken,
330) -> Result<bool, String> {
331    use SignatureToken as S;
332    match t {
333        S::Reference(inner) | S::MutableReference(inner) => {
334            is_object(view, function_type_args, inner)
335        }
336        _ => is_object_struct(view, function_type_args, t),
337    }
338}
339
340pub fn is_object_vector(
341    view: &CompiledModule,
342    function_type_args: &[AbilitySet],
343    t: &SignatureToken,
344) -> Result<bool, String> {
345    use SignatureToken as S;
346    match t {
347        S::Vector(inner) => is_object_struct(view, function_type_args, inner),
348        _ => is_object_struct(view, function_type_args, t),
349    }
350}
351
352pub fn is_object_struct(
353    view: &CompiledModule,
354    function_type_args: &[AbilitySet],
355    s: &SignatureToken,
356) -> Result<bool, String> {
357    use SignatureToken as S;
358    match s {
359        S::Bool
360        | S::U8
361        | S::U16
362        | S::U32
363        | S::U64
364        | S::U128
365        | S::U256
366        | S::Address
367        | S::Signer
368        | S::Vector(_)
369        | S::Reference(_)
370        | S::MutableReference(_) => Ok(false),
371        S::TypeParameter(idx) => Ok(function_type_args
372            .get(*idx as usize)
373            .map(|abs| abs.has_key())
374            .unwrap_or(false)),
375        S::Datatype(_) | S::DatatypeInstantiation(_) => {
376            let abilities = view
377                .abilities(s, function_type_args)
378                .map_err(|vm_err| vm_err.to_string())?;
379            Ok(abilities.has_key())
380        }
381    }
382}
383
384#[cfg(test)]
385mod tests {
386    use expect_test::expect;
387
388    use super::*;
389
390    #[test]
391    fn test_parse_iota_numeric_address() {
392        let result = parse_iota_address("0x2").expect("should not error");
393
394        let expected =
395            expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
396        expected.assert_eq(&result.to_string());
397    }
398
399    #[test]
400    fn test_parse_iota_named_address() {
401        let result = parse_iota_address("iota").expect("should not error");
402
403        let expected =
404            expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
405        expected.assert_eq(&result.to_string());
406    }
407
408    #[test]
409    fn test_parse_iota_module_id() {
410        let result = parse_iota_module_id("0x2::iota").expect("should not error");
411        let expected =
412            expect!["0x0000000000000000000000000000000000000000000000000000000000000002::iota"];
413        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
414    }
415
416    #[test]
417    fn test_parse_iota_fq_name() {
418        let (module, name) = parse_iota_fq_name("0x2::object::new").expect("should not error");
419        let expected = expect![
420            "0x0000000000000000000000000000000000000000000000000000000000000002::object::new"
421        ];
422        expected.assert_eq(&format!(
423            "{}::{name}",
424            module.to_canonical_display(/* with_prefix */ true)
425        ));
426    }
427
428    #[test]
429    fn test_parse_iota_struct_tag_short_account_addr() {
430        let result = parse_iota_struct_tag("0x2::iota::IOTA").expect("should not error");
431
432        let expected = expect!["0x2::iota::IOTA"];
433        expected.assert_eq(&result.to_string());
434
435        let expected = expect![
436            "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA"
437        ];
438        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
439    }
440
441    #[test]
442    fn test_parse_iota_struct_tag_long_account_addr() {
443        let result = parse_iota_struct_tag(
444            "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA",
445        )
446        .expect("should not error");
447
448        let expected = expect!["0x2::iota::IOTA"];
449        expected.assert_eq(&result.to_string());
450
451        let expected = expect![
452            "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA"
453        ];
454        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
455    }
456
457    #[test]
458    fn test_parse_iota_struct_with_type_param_short_addr() {
459        let result =
460            parse_iota_struct_tag("0x2::coin::COIN<0x2::iota::IOTA>").expect("should not error");
461
462        let expected = expect!["0x2::coin::COIN<0x2::iota::IOTA>"];
463        expected.assert_eq(&result.to_string());
464
465        let expected = expect![
466            "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>"
467        ];
468        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
469    }
470
471    #[test]
472    fn test_parse_iota_struct_with_type_param_long_addr() {
473        let result = parse_iota_struct_tag("0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>")
474            .expect("should not error");
475
476        let expected = expect!["0x2::coin::COIN<0x2::iota::IOTA>"];
477        expected.assert_eq(&result.to_string());
478
479        let expected = expect![
480            "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>"
481        ];
482        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
483    }
484
485    #[test]
486    fn test_complex_struct_tag_with_short_addr() {
487        let result = parse_iota_struct_tag(
488            "0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>",
489        )
490        .expect("should not error");
491
492        let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>"];
493        expected.assert_eq(&result.to_string());
494
495        let expected = expect![
496            "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>"
497        ];
498        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
499    }
500
501    #[test]
502    fn test_complex_struct_tag_with_long_addr() {
503        let result = parse_iota_struct_tag("0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>")
504            .expect("should not error");
505
506        let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>"];
507        expected.assert_eq(&result.to_string());
508
509        let expected = expect![
510            "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>"
511        ];
512        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
513    }
514
515    #[test]
516    fn test_dynamic_field_short_addr() {
517        let result = parse_iota_struct_tag(
518            "0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>",
519        )
520        .expect("should not error");
521
522        let expected =
523            expect!["0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>"];
524        expected.assert_eq(&result.to_string());
525
526        let expected = expect![
527            "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
528        ];
529        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
530    }
531
532    #[test]
533    fn test_dynamic_field_long_addr() {
534        let result = parse_iota_struct_tag(
535            "0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>",
536        )
537        .expect("should not error");
538
539        let expected =
540            expect!["0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>"];
541        expected.assert_eq(&result.to_string());
542
543        let expected = expect![
544            "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
545        ];
546        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
547    }
548}