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