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