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