iota_types/
base_types.rs

1// Copyright (c) 2021, Facebook, Inc. and its affiliates
2// Copyright (c) Mysten Labs, Inc.
3// Modifications Copyright (c) 2024 IOTA Stiftung
4// SPDX-License-Identifier: Apache-2.0
5
6use std::{
7    cmp::max,
8    convert::{TryFrom, TryInto},
9    fmt,
10    str::FromStr,
11};
12
13use anyhow::anyhow;
14use fastcrypto::{
15    encoding::{Encoding, Hex, decode_bytes_hex},
16    hash::HashFunction,
17    traits::AllowedRng,
18};
19use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs;
20use move_binary_format::{CompiledModule, file_format::SignatureToken};
21use move_bytecode_utils::resolve_struct;
22use move_core_types::{
23    account_address::AccountAddress,
24    annotated_value as A, ident_str,
25    identifier::IdentStr,
26    language_storage::{ModuleId, StructTag, TypeTag},
27};
28use rand::Rng;
29use schemars::JsonSchema;
30use serde::{
31    Deserialize, Serialize, Serializer,
32    ser::{Error, SerializeSeq},
33};
34use serde_with::serde_as;
35use shared_crypto::intent::HashingIntentScope;
36
37use crate::{
38    IOTA_CLOCK_OBJECT_ID, IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS, MOVE_STDLIB_ADDRESS,
39    balance::Balance,
40    coin::{COIN_MODULE_NAME, COIN_STRUCT_NAME, Coin, CoinMetadata, TreasuryCap},
41    coin_manager::CoinManager,
42    crypto::{
43        AuthorityPublicKeyBytes, DefaultHash, IotaPublicKey, IotaSignature, PublicKey,
44        SignatureScheme,
45    },
46    dynamic_field::{DynamicFieldInfo, DynamicFieldType},
47    effects::{TransactionEffects, TransactionEffectsAPI},
48    epoch_data::EpochData,
49    error::{ExecutionError, ExecutionErrorKind, IotaError, IotaResult},
50    gas_coin::{GAS, GasCoin},
51    governance::{STAKED_IOTA_STRUCT_NAME, STAKING_POOL_MODULE_NAME, StakedIota},
52    id::RESOLVED_IOTA_ID,
53    iota_serde::{HexAccountAddress, Readable, to_iota_struct_tag_string},
54    messages_checkpoint::CheckpointTimestamp,
55    multisig::MultiSigPublicKey,
56    object::{Object, Owner},
57    parse_iota_struct_tag,
58    signature::GenericSignature,
59    stardust::output::{AliasOutput, BasicOutput, Nft, NftOutput},
60    timelock::{
61        timelock::{self, TimeLock},
62        timelocked_staked_iota::TimelockedStakedIota,
63    },
64    transaction::{Transaction, VerifiedTransaction},
65    zk_login_authenticator::ZkLoginAuthenticator,
66};
67pub use crate::{
68    committee::EpochId,
69    digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest},
70};
71
72#[cfg(test)]
73#[path = "unit_tests/base_types_tests.rs"]
74mod base_types_tests;
75
76#[derive(
77    Eq,
78    PartialEq,
79    Ord,
80    PartialOrd,
81    Copy,
82    Clone,
83    Hash,
84    Default,
85    Debug,
86    Serialize,
87    Deserialize,
88    JsonSchema,
89)]
90#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))]
91pub struct SequenceNumber(u64);
92
93impl SequenceNumber {
94    pub fn one_before(&self) -> Option<SequenceNumber> {
95        if self.0 == 0 {
96            None
97        } else {
98            Some(SequenceNumber(self.0 - 1))
99        }
100    }
101
102    pub fn next(&self) -> SequenceNumber {
103        SequenceNumber(self.0 + 1)
104    }
105}
106
107pub type TxSequenceNumber = u64;
108
109impl fmt::Display for SequenceNumber {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        write!(f, "{:#x}", self.0)
112    }
113}
114
115pub type VersionNumber = SequenceNumber;
116
117/// The round number.
118pub type CommitRound = u64;
119
120#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Hash, Default, Debug, Serialize, Deserialize)]
121pub struct UserData(pub Option<[u8; 32]>);
122
123pub type AuthorityName = AuthorityPublicKeyBytes;
124
125pub trait ConciseableName<'a> {
126    type ConciseTypeRef: std::fmt::Debug;
127    type ConciseType: std::fmt::Debug;
128
129    fn concise(&'a self) -> Self::ConciseTypeRef;
130    fn concise_owned(&self) -> Self::ConciseType;
131}
132
133#[serde_as]
134#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)]
135pub struct ObjectID(
136    #[schemars(with = "Hex")]
137    #[serde_as(as = "Readable<HexAccountAddress, _>")]
138    AccountAddress,
139);
140
141pub type VersionDigest = (SequenceNumber, ObjectDigest);
142
143pub type ObjectRef = (ObjectID, SequenceNumber, ObjectDigest);
144
145pub fn random_object_ref() -> ObjectRef {
146    (
147        ObjectID::random(),
148        SequenceNumber::new(),
149        ObjectDigest::new([0; 32]),
150    )
151}
152
153pub fn update_object_ref_for_testing(object_ref: ObjectRef) -> ObjectRef {
154    (
155        object_ref.0,
156        object_ref.1.next(),
157        ObjectDigest::new([0; 32]),
158    )
159}
160
161/// Wrapper around StructTag with a space-efficient representation for common
162/// types like coins The StructTag for a gas coin is 84 bytes, so using 1 byte
163/// instead is a win. The inner representation is private to prevent incorrectly
164/// constructing an `Other` instead of one of the specialized variants, e.g.
165/// `Other(GasCoin::type_())` instead of `GasCoin`
166#[derive(Eq, PartialEq, PartialOrd, Ord, Debug, Clone, Deserialize, Serialize, Hash)]
167pub struct MoveObjectType(MoveObjectType_);
168
169/// Even though it is declared public, it is the "private", internal
170/// representation for `MoveObjectType`
171#[derive(Eq, PartialEq, PartialOrd, Ord, Debug, Clone, Deserialize, Serialize, Hash)]
172pub enum MoveObjectType_ {
173    /// A type that is not `0x2::coin::Coin<T>`
174    Other(StructTag),
175    /// An IOTA coin (i.e., `0x2::coin::Coin<0x2::iota::IOTA>`)
176    GasCoin,
177    /// A record of a staked IOTA coin (i.e., `0x3::staking_pool::StakedIota`)
178    StakedIota,
179    /// A non-IOTA coin type (i.e., `0x2::coin::Coin<T> where T !=
180    /// 0x2::iota::IOTA`)
181    Coin(TypeTag),
182    // NOTE: if adding a new type here, and there are existing on-chain objects of that
183    // type with Other(_), that is ok, but you must hand-roll PartialEq/Eq/Ord/maybe Hash
184    // to make sure the new type and Other(_) are interpreted consistently.
185}
186
187impl MoveObjectType {
188    pub fn gas_coin() -> Self {
189        Self(MoveObjectType_::GasCoin)
190    }
191
192    pub fn staked_iota() -> Self {
193        Self(MoveObjectType_::StakedIota)
194    }
195
196    pub fn timelocked_iota_balance() -> Self {
197        Self(MoveObjectType_::Other(TimeLock::<Balance>::type_(
198            Balance::type_(GAS::type_().into()).into(),
199        )))
200    }
201
202    pub fn timelocked_staked_iota() -> Self {
203        Self(MoveObjectType_::Other(TimelockedStakedIota::type_()))
204    }
205
206    pub fn stardust_nft() -> Self {
207        Self(MoveObjectType_::Other(Nft::tag()))
208    }
209
210    pub fn address(&self) -> AccountAddress {
211        match &self.0 {
212            MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => IOTA_FRAMEWORK_ADDRESS,
213            MoveObjectType_::StakedIota => IOTA_SYSTEM_ADDRESS,
214            MoveObjectType_::Other(s) => s.address,
215        }
216    }
217
218    pub fn module(&self) -> &IdentStr {
219        match &self.0 {
220            MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => COIN_MODULE_NAME,
221            MoveObjectType_::StakedIota => STAKING_POOL_MODULE_NAME,
222            MoveObjectType_::Other(s) => &s.module,
223        }
224    }
225
226    pub fn name(&self) -> &IdentStr {
227        match &self.0 {
228            MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => COIN_STRUCT_NAME,
229            MoveObjectType_::StakedIota => STAKED_IOTA_STRUCT_NAME,
230            MoveObjectType_::Other(s) => &s.name,
231        }
232    }
233
234    pub fn type_params(&self) -> Vec<TypeTag> {
235        match &self.0 {
236            MoveObjectType_::GasCoin => vec![GAS::type_tag()],
237            MoveObjectType_::StakedIota => vec![],
238            MoveObjectType_::Coin(inner) => vec![inner.clone()],
239            MoveObjectType_::Other(s) => s.type_params.clone(),
240        }
241    }
242
243    pub fn into_type_params(self) -> Vec<TypeTag> {
244        match self.0 {
245            MoveObjectType_::GasCoin => vec![GAS::type_tag()],
246            MoveObjectType_::StakedIota => vec![],
247            MoveObjectType_::Coin(inner) => vec![inner],
248            MoveObjectType_::Other(s) => s.type_params,
249        }
250    }
251
252    pub fn coin_type_maybe(&self) -> Option<TypeTag> {
253        match &self.0 {
254            MoveObjectType_::GasCoin => Some(GAS::type_tag()),
255            MoveObjectType_::Coin(inner) => Some(inner.clone()),
256            MoveObjectType_::StakedIota => None,
257            MoveObjectType_::Other(_) => None,
258        }
259    }
260
261    pub fn module_id(&self) -> ModuleId {
262        ModuleId::new(self.address(), self.module().to_owned())
263    }
264
265    pub fn size_for_gas_metering(&self) -> usize {
266        // unwraps safe because a `StructTag` cannot fail to serialize
267        match &self.0 {
268            MoveObjectType_::GasCoin => 1,
269            MoveObjectType_::StakedIota => 1,
270            MoveObjectType_::Coin(inner) => bcs::serialized_size(inner).unwrap() + 1,
271            MoveObjectType_::Other(s) => bcs::serialized_size(s).unwrap() + 1,
272        }
273    }
274
275    /// Return true if `self` is `0x2::coin::Coin<T>` for some T (note: T can be
276    /// IOTA)
277    pub fn is_coin(&self) -> bool {
278        match &self.0 {
279            MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => true,
280            MoveObjectType_::StakedIota | MoveObjectType_::Other(_) => false,
281        }
282    }
283
284    /// Return true if `self` is 0x2::coin::Coin<0x2::iota::IOTA>
285    pub fn is_gas_coin(&self) -> bool {
286        match &self.0 {
287            MoveObjectType_::GasCoin => true,
288            MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) | MoveObjectType_::Other(_) => {
289                false
290            }
291        }
292    }
293
294    /// Return true if `self` is `0x2::coin::Coin<t>`
295    pub fn is_coin_t(&self, t: &TypeTag) -> bool {
296        match &self.0 {
297            MoveObjectType_::GasCoin => GAS::is_gas_type(t),
298            MoveObjectType_::Coin(c) => t == c,
299            MoveObjectType_::StakedIota | MoveObjectType_::Other(_) => false,
300        }
301    }
302
303    pub fn is_staked_iota(&self) -> bool {
304        match &self.0 {
305            MoveObjectType_::StakedIota => true,
306            MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) | MoveObjectType_::Other(_) => {
307                false
308            }
309        }
310    }
311
312    pub fn is_coin_metadata(&self) -> bool {
313        match &self.0 {
314            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
315                false
316            }
317            MoveObjectType_::Other(s) => CoinMetadata::is_coin_metadata(s),
318        }
319    }
320
321    pub fn is_coin_manager(&self) -> bool {
322        matches!(&self.0, MoveObjectType_::Other(struct_tag) if CoinManager::is_coin_manager(struct_tag))
323    }
324
325    pub fn is_treasury_cap(&self) -> bool {
326        match &self.0 {
327            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
328                false
329            }
330            MoveObjectType_::Other(s) => TreasuryCap::is_treasury_type(s),
331        }
332    }
333
334    pub fn is_upgrade_cap(&self) -> bool {
335        self.address() == IOTA_FRAMEWORK_ADDRESS
336            && self.module().as_str() == "package"
337            && self.name().as_str() == "UpgradeCap"
338    }
339
340    pub fn is_regulated_coin_metadata(&self) -> bool {
341        self.address() == IOTA_FRAMEWORK_ADDRESS
342            && self.module().as_str() == "coin"
343            && self.name().as_str() == "RegulatedCoinMetadata"
344    }
345
346    pub fn is_coin_deny_cap_v1(&self) -> bool {
347        self.address() == IOTA_FRAMEWORK_ADDRESS
348            && self.module().as_str() == "coin"
349            && self.name().as_str() == "DenyCapV1"
350    }
351
352    pub fn is_dynamic_field(&self) -> bool {
353        match &self.0 {
354            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
355                false
356            }
357            MoveObjectType_::Other(s) => DynamicFieldInfo::is_dynamic_field(s),
358        }
359    }
360
361    pub fn is_timelock(&self) -> bool {
362        match &self.0 {
363            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
364                false
365            }
366            MoveObjectType_::Other(s) => timelock::is_timelock(s),
367        }
368    }
369
370    pub fn is_timelocked_balance(&self) -> bool {
371        match &self.0 {
372            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
373                false
374            }
375            MoveObjectType_::Other(s) => timelock::is_timelocked_balance(s),
376        }
377    }
378
379    pub fn is_timelocked_staked_iota(&self) -> bool {
380        match &self.0 {
381            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
382                false
383            }
384            MoveObjectType_::Other(s) => TimelockedStakedIota::is_timelocked_staked_iota(s),
385        }
386    }
387
388    pub fn is_alias_output(&self) -> bool {
389        match &self.0 {
390            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
391                false
392            }
393            MoveObjectType_::Other(s) => AliasOutput::is_alias_output(s),
394        }
395    }
396
397    pub fn is_basic_output(&self) -> bool {
398        match &self.0 {
399            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
400                false
401            }
402            MoveObjectType_::Other(s) => BasicOutput::is_basic_output(s),
403        }
404    }
405
406    pub fn is_nft_output(&self) -> bool {
407        match &self.0 {
408            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
409                false
410            }
411            MoveObjectType_::Other(s) => NftOutput::is_nft_output(s),
412        }
413    }
414
415    pub fn try_extract_field_name(&self, type_: &DynamicFieldType) -> IotaResult<TypeTag> {
416        match &self.0 {
417            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
418                Err(IotaError::ObjectDeserialization {
419                    error: "Error extracting dynamic object name from Coin object".to_string(),
420                })
421            }
422            MoveObjectType_::Other(s) => DynamicFieldInfo::try_extract_field_name(s, type_),
423        }
424    }
425
426    pub fn try_extract_field_value(&self) -> IotaResult<TypeTag> {
427        match &self.0 {
428            MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => {
429                Err(IotaError::ObjectDeserialization {
430                    error: "Error extracting dynamic object value from Coin object".to_string(),
431                })
432            }
433            MoveObjectType_::Other(s) => DynamicFieldInfo::try_extract_field_value(s),
434        }
435    }
436
437    pub fn is(&self, s: &StructTag) -> bool {
438        match &self.0 {
439            MoveObjectType_::GasCoin => GasCoin::is_gas_coin(s),
440            MoveObjectType_::StakedIota => StakedIota::is_staked_iota(s),
441            MoveObjectType_::Coin(inner) => {
442                Coin::is_coin(s) && s.type_params.len() == 1 && inner == &s.type_params[0]
443            }
444            MoveObjectType_::Other(o) => s == o,
445        }
446    }
447
448    pub fn other(&self) -> Option<&StructTag> {
449        if let MoveObjectType_::Other(s) = &self.0 {
450            Some(s)
451        } else {
452            None
453        }
454    }
455
456    /// Returns the string representation of this object's type using the
457    /// canonical display.
458    pub fn to_canonical_string(&self, with_prefix: bool) -> String {
459        StructTag::from(self.clone()).to_canonical_string(with_prefix)
460    }
461}
462
463impl From<StructTag> for MoveObjectType {
464    fn from(mut s: StructTag) -> Self {
465        Self(if GasCoin::is_gas_coin(&s) {
466            MoveObjectType_::GasCoin
467        } else if Coin::is_coin(&s) {
468            // unwrap safe because a coin has exactly one type parameter
469            MoveObjectType_::Coin(s.type_params.pop().unwrap())
470        } else if StakedIota::is_staked_iota(&s) {
471            MoveObjectType_::StakedIota
472        } else {
473            MoveObjectType_::Other(s)
474        })
475    }
476}
477
478impl From<MoveObjectType> for StructTag {
479    fn from(t: MoveObjectType) -> Self {
480        match t.0 {
481            MoveObjectType_::GasCoin => GasCoin::type_(),
482            MoveObjectType_::StakedIota => StakedIota::type_(),
483            MoveObjectType_::Coin(inner) => Coin::type_(inner),
484            MoveObjectType_::Other(s) => s,
485        }
486    }
487}
488
489impl From<MoveObjectType> for TypeTag {
490    fn from(o: MoveObjectType) -> TypeTag {
491        let s: StructTag = o.into();
492        TypeTag::Struct(Box::new(s))
493    }
494}
495
496/// Whether this type is valid as a primitive (pure) transaction input.
497pub fn is_primitive_type_tag(t: &TypeTag) -> bool {
498    use TypeTag as T;
499
500    match t {
501        T::Bool | T::U8 | T::U16 | T::U32 | T::U64 | T::U128 | T::U256 | T::Address => true,
502        T::Vector(inner) => is_primitive_type_tag(inner),
503        T::Struct(st) => {
504            let StructTag {
505                address,
506                module,
507                name,
508                type_params: type_args,
509            } = &**st;
510            let resolved_struct = (address, module.as_ident_str(), name.as_ident_str());
511            // is id or..
512            if resolved_struct == RESOLVED_IOTA_ID {
513                return true;
514            }
515            // is utf8 string
516            if resolved_struct == RESOLVED_UTF8_STR {
517                return true;
518            }
519            // is ascii string
520            if resolved_struct == RESOLVED_ASCII_STR {
521                return true;
522            }
523            // is option of a primitive
524            resolved_struct == RESOLVED_STD_OPTION
525                && type_args.len() == 1
526                && is_primitive_type_tag(&type_args[0])
527        }
528        T::Signer => false,
529    }
530}
531
532/// Type of an IOTA object
533#[derive(Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Debug)]
534pub enum ObjectType {
535    /// Move package containing one or more bytecode modules
536    Package,
537    /// A Move struct of the given type
538    Struct(MoveObjectType),
539}
540
541impl From<&Object> for ObjectType {
542    fn from(o: &Object) -> Self {
543        o.data
544            .type_()
545            .map(|t| ObjectType::Struct(t.clone()))
546            .unwrap_or(ObjectType::Package)
547    }
548}
549
550impl TryFrom<ObjectType> for StructTag {
551    type Error = anyhow::Error;
552
553    fn try_from(o: ObjectType) -> Result<Self, anyhow::Error> {
554        match o {
555            ObjectType::Package => Err(anyhow!("Cannot create StructTag from Package")),
556            ObjectType::Struct(move_object_type) => Ok(move_object_type.into()),
557        }
558    }
559}
560
561impl FromStr for ObjectType {
562    type Err = anyhow::Error;
563
564    fn from_str(s: &str) -> Result<Self, Self::Err> {
565        if s.to_lowercase() == PACKAGE {
566            Ok(ObjectType::Package)
567        } else {
568            let tag = parse_iota_struct_tag(s)?;
569            Ok(ObjectType::Struct(MoveObjectType::from(tag)))
570        }
571    }
572}
573
574#[derive(Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Debug)]
575pub struct ObjectInfo {
576    pub object_id: ObjectID,
577    pub version: SequenceNumber,
578    pub digest: ObjectDigest,
579    pub type_: ObjectType,
580    pub owner: Owner,
581    pub previous_transaction: TransactionDigest,
582}
583
584impl ObjectInfo {
585    pub fn new(oref: &ObjectRef, o: &Object) -> Self {
586        let (object_id, version, digest) = *oref;
587        Self {
588            object_id,
589            version,
590            digest,
591            type_: o.into(),
592            owner: o.owner,
593            previous_transaction: o.previous_transaction,
594        }
595    }
596
597    pub fn from_object(object: &Object) -> Self {
598        Self {
599            object_id: object.id(),
600            version: object.version(),
601            digest: object.digest(),
602            type_: object.into(),
603            owner: object.owner,
604            previous_transaction: object.previous_transaction,
605        }
606    }
607}
608const PACKAGE: &str = "package";
609impl ObjectType {
610    pub fn is_gas_coin(&self) -> bool {
611        matches!(self, ObjectType::Struct(s) if s.is_gas_coin())
612    }
613
614    pub fn is_coin(&self) -> bool {
615        matches!(self, ObjectType::Struct(s) if s.is_coin())
616    }
617
618    /// Return true if `self` is `0x2::coin::Coin<t>`
619    pub fn is_coin_t(&self, t: &TypeTag) -> bool {
620        matches!(self, ObjectType::Struct(s) if s.is_coin_t(t))
621    }
622
623    pub fn is_package(&self) -> bool {
624        matches!(self, ObjectType::Package)
625    }
626}
627
628impl From<ObjectInfo> for ObjectRef {
629    fn from(info: ObjectInfo) -> Self {
630        (info.object_id, info.version, info.digest)
631    }
632}
633
634impl From<&ObjectInfo> for ObjectRef {
635    fn from(info: &ObjectInfo) -> Self {
636        (info.object_id, info.version, info.digest)
637    }
638}
639
640pub const IOTA_ADDRESS_LENGTH: usize = ObjectID::LENGTH;
641
642#[serde_as]
643#[derive(
644    Eq, Default, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema,
645)]
646#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))]
647pub struct IotaAddress(
648    #[schemars(with = "Hex")]
649    #[serde_as(as = "Readable<Hex, _>")]
650    [u8; IOTA_ADDRESS_LENGTH],
651);
652
653impl IotaAddress {
654    pub const ZERO: Self = Self([0u8; IOTA_ADDRESS_LENGTH]);
655
656    pub fn new(bytes: [u8; IOTA_ADDRESS_LENGTH]) -> Self {
657        Self(bytes)
658    }
659
660    /// Convert the address to a byte buffer.
661    pub fn to_vec(&self) -> Vec<u8> {
662        self.0.to_vec()
663    }
664
665    /// Return a random IotaAddress.
666    pub fn random_for_testing_only() -> Self {
667        AccountAddress::random().into()
668    }
669
670    pub fn generate<R: rand::RngCore + rand::CryptoRng>(mut rng: R) -> Self {
671        let buf: [u8; IOTA_ADDRESS_LENGTH] = rng.gen();
672        Self(buf)
673    }
674
675    /// Serialize an `Option<IotaAddress>` in Hex.
676    pub fn optional_address_as_hex<S>(
677        key: &Option<IotaAddress>,
678        serializer: S,
679    ) -> Result<S::Ok, S::Error>
680    where
681        S: serde::ser::Serializer,
682    {
683        serializer.serialize_str(&key.map(Hex::encode).unwrap_or_default())
684    }
685
686    /// Deserialize into an `Option<IotaAddress>`.
687    pub fn optional_address_from_hex<'de, D>(
688        deserializer: D,
689    ) -> Result<Option<IotaAddress>, D::Error>
690    where
691        D: serde::de::Deserializer<'de>,
692    {
693        let s = String::deserialize(deserializer)?;
694        let value = decode_bytes_hex(&s).map_err(serde::de::Error::custom)?;
695        Ok(Some(value))
696    }
697
698    /// Return the underlying byte array of a IotaAddress.
699    pub fn to_inner(self) -> [u8; IOTA_ADDRESS_LENGTH] {
700        self.0
701    }
702
703    /// Parse a IotaAddress from a byte array or buffer.
704    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, IotaError> {
705        <[u8; IOTA_ADDRESS_LENGTH]>::try_from(bytes.as_ref())
706            .map_err(|_| IotaError::InvalidAddress)
707            .map(IotaAddress)
708    }
709
710    /// This derives a zkLogin address by parsing the iss and address_seed from
711    /// [struct ZkLoginAuthenticator]. Define as iss_bytes_len || iss_bytes
712    /// || padded_32_byte_address_seed. This is to be differentiated with
713    /// try_from_unpadded defined below.
714    pub fn try_from_padded(inputs: &ZkLoginInputs) -> IotaResult<Self> {
715        Ok((&PublicKey::from_zklogin_inputs(inputs)?).into())
716    }
717
718    /// Define as iss_bytes_len || iss_bytes || unpadded_32_byte_address_seed.
719    pub fn try_from_unpadded(inputs: &ZkLoginInputs) -> IotaResult<Self> {
720        let mut hasher = DefaultHash::default();
721        hasher.update([SignatureScheme::ZkLoginAuthenticator.flag()]);
722        let iss_bytes = inputs.get_iss().as_bytes();
723        hasher.update([iss_bytes.len() as u8]);
724        hasher.update(iss_bytes);
725        hasher.update(inputs.get_address_seed().unpadded());
726        Ok(IotaAddress(hasher.finalize().digest))
727    }
728}
729
730impl From<ObjectID> for IotaAddress {
731    fn from(object_id: ObjectID) -> IotaAddress {
732        Self(object_id.into_bytes())
733    }
734}
735
736impl From<AccountAddress> for IotaAddress {
737    fn from(address: AccountAddress) -> IotaAddress {
738        Self(address.into_bytes())
739    }
740}
741
742impl TryFrom<&[u8]> for IotaAddress {
743    type Error = IotaError;
744
745    /// Tries to convert the provided byte array into a IotaAddress.
746    fn try_from(bytes: &[u8]) -> Result<Self, IotaError> {
747        Self::from_bytes(bytes)
748    }
749}
750
751impl TryFrom<Vec<u8>> for IotaAddress {
752    type Error = IotaError;
753
754    /// Tries to convert the provided byte buffer into a IotaAddress.
755    fn try_from(bytes: Vec<u8>) -> Result<Self, IotaError> {
756        Self::from_bytes(bytes)
757    }
758}
759
760impl AsRef<[u8]> for IotaAddress {
761    fn as_ref(&self) -> &[u8] {
762        &self.0[..]
763    }
764}
765
766impl FromStr for IotaAddress {
767    type Err = anyhow::Error;
768    fn from_str(s: &str) -> Result<Self, Self::Err> {
769        decode_bytes_hex(s).map_err(|e| anyhow!(e))
770    }
771}
772
773impl<T: IotaPublicKey> From<&T> for IotaAddress {
774    fn from(pk: &T) -> Self {
775        let mut hasher = DefaultHash::default();
776        T::SIGNATURE_SCHEME.update_hasher_with_flag(&mut hasher);
777        hasher.update(pk);
778        let g_arr = hasher.finalize();
779        IotaAddress(g_arr.digest)
780    }
781}
782
783impl From<&PublicKey> for IotaAddress {
784    fn from(pk: &PublicKey) -> Self {
785        let mut hasher = DefaultHash::default();
786        pk.scheme().update_hasher_with_flag(&mut hasher);
787        hasher.update(pk);
788        let g_arr = hasher.finalize();
789        IotaAddress(g_arr.digest)
790    }
791}
792
793impl From<&MultiSigPublicKey> for IotaAddress {
794    /// Derive a IotaAddress from [struct MultiSigPublicKey]. A MultiSig address
795    /// is defined as the 32-byte Blake2b hash of serializing the flag, the
796    /// threshold, concatenation of all n flag, public keys and
797    /// its weight. `flag_MultiSig || threshold || flag_1 || pk_1 || weight_1
798    /// || ... || flag_n || pk_n || weight_n`.
799    ///
800    /// When flag_i is ZkLogin, pk_i refers to [struct ZkLoginPublicIdentifier]
801    /// derived from padded address seed in bytes and iss.
802    fn from(multisig_pk: &MultiSigPublicKey) -> Self {
803        let mut hasher = DefaultHash::default();
804        hasher.update([SignatureScheme::MultiSig.flag()]);
805        hasher.update(multisig_pk.threshold().to_le_bytes());
806        multisig_pk.pubkeys().iter().for_each(|(pk, w)| {
807            pk.scheme().update_hasher_with_flag(&mut hasher);
808            hasher.update(pk.as_ref());
809            hasher.update(w.to_le_bytes());
810        });
811        IotaAddress(hasher.finalize().digest)
812    }
813}
814
815/// IOTA address for [struct ZkLoginAuthenticator] is defined as the black2b
816/// hash of [zklogin_flag || iss_bytes_length || iss_bytes ||
817/// unpadded_address_seed_in_bytes].
818impl TryFrom<&ZkLoginAuthenticator> for IotaAddress {
819    type Error = IotaError;
820    fn try_from(authenticator: &ZkLoginAuthenticator) -> IotaResult<Self> {
821        IotaAddress::try_from_unpadded(&authenticator.inputs)
822    }
823}
824
825impl TryFrom<&GenericSignature> for IotaAddress {
826    type Error = IotaError;
827    /// Derive a IotaAddress from a serialized signature in IOTA
828    /// [GenericSignature].
829    fn try_from(sig: &GenericSignature) -> IotaResult<Self> {
830        match sig {
831            GenericSignature::Signature(sig) => {
832                let scheme = sig.scheme();
833                let pub_key_bytes = sig.public_key_bytes();
834                let pub_key = PublicKey::try_from_bytes(scheme, pub_key_bytes).map_err(|_| {
835                    IotaError::InvalidSignature {
836                        error: "Cannot parse pubkey".to_string(),
837                    }
838                })?;
839                Ok(IotaAddress::from(&pub_key))
840            }
841            GenericSignature::MultiSig(ms) => Ok(ms.get_pk().into()),
842            GenericSignature::ZkLoginAuthenticator(zklogin) => {
843                IotaAddress::try_from_unpadded(&zklogin.inputs)
844            }
845            GenericSignature::PasskeyAuthenticator(s) => Ok(IotaAddress::from(&s.get_pk()?)),
846        }
847    }
848}
849
850impl fmt::Display for IotaAddress {
851    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
852        write!(f, "0x{}", Hex::encode(self.0))
853    }
854}
855
856impl fmt::Debug for IotaAddress {
857    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
858        write!(f, "0x{}", Hex::encode(self.0))
859    }
860}
861
862/// Generate a fake IotaAddress with repeated one byte.
863pub fn dbg_addr(name: u8) -> IotaAddress {
864    let addr = [name; IOTA_ADDRESS_LENGTH];
865    IotaAddress(addr)
866}
867
868#[derive(
869    Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema, Debug,
870)]
871pub struct ExecutionDigests {
872    pub transaction: TransactionDigest,
873    pub effects: TransactionEffectsDigest,
874}
875
876impl ExecutionDigests {
877    pub fn new(transaction: TransactionDigest, effects: TransactionEffectsDigest) -> Self {
878        Self {
879            transaction,
880            effects,
881        }
882    }
883
884    pub fn random() -> Self {
885        Self {
886            transaction: TransactionDigest::random(),
887            effects: TransactionEffectsDigest::random(),
888        }
889    }
890}
891
892#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
893pub struct ExecutionData {
894    pub transaction: Transaction,
895    pub effects: TransactionEffects,
896}
897
898impl ExecutionData {
899    pub fn new(transaction: Transaction, effects: TransactionEffects) -> ExecutionData {
900        debug_assert_eq!(transaction.digest(), effects.transaction_digest());
901        Self {
902            transaction,
903            effects,
904        }
905    }
906
907    pub fn digests(&self) -> ExecutionDigests {
908        self.effects.execution_digests()
909    }
910}
911
912#[derive(Clone, Eq, PartialEq, Debug)]
913pub struct VerifiedExecutionData {
914    pub transaction: VerifiedTransaction,
915    pub effects: TransactionEffects,
916}
917
918impl VerifiedExecutionData {
919    pub fn new(transaction: VerifiedTransaction, effects: TransactionEffects) -> Self {
920        debug_assert_eq!(transaction.digest(), effects.transaction_digest());
921        Self {
922            transaction,
923            effects,
924        }
925    }
926
927    pub fn new_unchecked(data: ExecutionData) -> Self {
928        Self {
929            transaction: VerifiedTransaction::new_unchecked(data.transaction),
930            effects: data.effects,
931        }
932    }
933
934    pub fn into_inner(self) -> ExecutionData {
935        ExecutionData {
936            transaction: self.transaction.into_inner(),
937            effects: self.effects,
938        }
939    }
940
941    pub fn digests(&self) -> ExecutionDigests {
942        self.effects.execution_digests()
943    }
944}
945
946pub const STD_OPTION_MODULE_NAME: &IdentStr = ident_str!("option");
947pub const STD_OPTION_STRUCT_NAME: &IdentStr = ident_str!("Option");
948pub const RESOLVED_STD_OPTION: (&AccountAddress, &IdentStr, &IdentStr) = (
949    &MOVE_STDLIB_ADDRESS,
950    STD_OPTION_MODULE_NAME,
951    STD_OPTION_STRUCT_NAME,
952);
953
954pub const STD_ASCII_MODULE_NAME: &IdentStr = ident_str!("ascii");
955pub const STD_ASCII_STRUCT_NAME: &IdentStr = ident_str!("String");
956pub const RESOLVED_ASCII_STR: (&AccountAddress, &IdentStr, &IdentStr) = (
957    &MOVE_STDLIB_ADDRESS,
958    STD_ASCII_MODULE_NAME,
959    STD_ASCII_STRUCT_NAME,
960);
961
962pub const STD_UTF8_MODULE_NAME: &IdentStr = ident_str!("string");
963pub const STD_UTF8_STRUCT_NAME: &IdentStr = ident_str!("String");
964pub const RESOLVED_UTF8_STR: (&AccountAddress, &IdentStr, &IdentStr) = (
965    &MOVE_STDLIB_ADDRESS,
966    STD_UTF8_MODULE_NAME,
967    STD_UTF8_STRUCT_NAME,
968);
969
970pub const TX_CONTEXT_MODULE_NAME: &IdentStr = ident_str!("tx_context");
971pub const TX_CONTEXT_STRUCT_NAME: &IdentStr = ident_str!("TxContext");
972
973pub fn move_ascii_str_layout() -> A::MoveStructLayout {
974    A::MoveStructLayout {
975        type_: StructTag {
976            address: MOVE_STDLIB_ADDRESS,
977            module: STD_ASCII_MODULE_NAME.to_owned(),
978            name: STD_ASCII_STRUCT_NAME.to_owned(),
979            type_params: vec![],
980        },
981        fields: vec![A::MoveFieldLayout::new(
982            ident_str!("bytes").into(),
983            A::MoveTypeLayout::Vector(Box::new(A::MoveTypeLayout::U8)),
984        )],
985    }
986}
987
988pub fn move_utf8_str_layout() -> A::MoveStructLayout {
989    A::MoveStructLayout {
990        type_: StructTag {
991            address: MOVE_STDLIB_ADDRESS,
992            module: STD_UTF8_MODULE_NAME.to_owned(),
993            name: STD_UTF8_STRUCT_NAME.to_owned(),
994            type_params: vec![],
995        },
996        fields: vec![A::MoveFieldLayout::new(
997            ident_str!("bytes").into(),
998            A::MoveTypeLayout::Vector(Box::new(A::MoveTypeLayout::U8)),
999        )],
1000    }
1001}
1002
1003#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
1004pub struct TxContext {
1005    /// Signer/sender of the transaction
1006    sender: AccountAddress,
1007    /// Digest of the current transaction
1008    digest: Vec<u8>,
1009    /// The current epoch number
1010    epoch: EpochId,
1011    /// Timestamp that the epoch started at
1012    epoch_timestamp_ms: CheckpointTimestamp,
1013    /// Number of `ObjectID`'s generated during execution of the current
1014    /// transaction
1015    ids_created: u64,
1016}
1017
1018#[derive(PartialEq, Eq, Clone, Copy)]
1019pub enum TxContextKind {
1020    // No TxContext
1021    None,
1022    // &mut TxContext
1023    Mutable,
1024    // &TxContext
1025    Immutable,
1026}
1027
1028impl TxContext {
1029    pub fn new(sender: &IotaAddress, digest: &TransactionDigest, epoch_data: &EpochData) -> Self {
1030        Self::new_from_components(
1031            sender,
1032            digest,
1033            &epoch_data.epoch_id(),
1034            epoch_data.epoch_start_timestamp(),
1035        )
1036    }
1037
1038    pub fn new_from_components(
1039        sender: &IotaAddress,
1040        digest: &TransactionDigest,
1041        epoch_id: &EpochId,
1042        epoch_timestamp_ms: u64,
1043    ) -> Self {
1044        Self {
1045            sender: AccountAddress::new(sender.0),
1046            digest: digest.into_inner().to_vec(),
1047            epoch: *epoch_id,
1048            epoch_timestamp_ms,
1049            ids_created: 0,
1050        }
1051    }
1052
1053    /// Returns whether the type signature is &mut TxContext, &TxContext, or
1054    /// none of the above.
1055    pub fn kind(view: &CompiledModule, s: &SignatureToken) -> TxContextKind {
1056        use SignatureToken as S;
1057        let (kind, s) = match s {
1058            S::MutableReference(s) => (TxContextKind::Mutable, s),
1059            S::Reference(s) => (TxContextKind::Immutable, s),
1060            _ => return TxContextKind::None,
1061        };
1062
1063        let S::Datatype(idx) = &**s else {
1064            return TxContextKind::None;
1065        };
1066
1067        let (module_addr, module_name, struct_name) = resolve_struct(view, *idx);
1068        let is_tx_context_type = module_name == TX_CONTEXT_MODULE_NAME
1069            && module_addr == &IOTA_FRAMEWORK_ADDRESS
1070            && struct_name == TX_CONTEXT_STRUCT_NAME;
1071
1072        if is_tx_context_type {
1073            kind
1074        } else {
1075            TxContextKind::None
1076        }
1077    }
1078
1079    pub fn epoch(&self) -> EpochId {
1080        self.epoch
1081    }
1082
1083    /// Derive a globally unique object ID by hashing self.digest |
1084    /// self.ids_created
1085    pub fn fresh_id(&mut self) -> ObjectID {
1086        let id = ObjectID::derive_id(self.digest(), self.ids_created);
1087
1088        self.ids_created += 1;
1089        id
1090    }
1091
1092    /// Return the transaction digest, to include in new objects
1093    pub fn digest(&self) -> TransactionDigest {
1094        TransactionDigest::new(self.digest.clone().try_into().unwrap())
1095    }
1096
1097    pub fn sender(&self) -> IotaAddress {
1098        IotaAddress::from(ObjectID(self.sender))
1099    }
1100
1101    pub fn to_vec(&self) -> Vec<u8> {
1102        bcs::to_bytes(&self).unwrap()
1103    }
1104
1105    /// Updates state of the context instance. It's intended to use
1106    /// when mutable context is passed over some boundary via
1107    /// serialize/deserialize and this is the reason why this method
1108    /// consumes the other context..
1109    pub fn update_state(&mut self, other: TxContext) -> Result<(), ExecutionError> {
1110        if self.sender != other.sender
1111            || self.digest != other.digest
1112            || other.ids_created < self.ids_created
1113        {
1114            return Err(ExecutionError::new_with_source(
1115                ExecutionErrorKind::InvariantViolation,
1116                "Immutable fields for TxContext changed",
1117            ));
1118        }
1119        self.ids_created = other.ids_created;
1120        Ok(())
1121    }
1122
1123    // Generate a random TxContext for testing.
1124    pub fn random_for_testing_only() -> Self {
1125        Self::new(
1126            &IotaAddress::random_for_testing_only(),
1127            &TransactionDigest::random(),
1128            &EpochData::new_test(),
1129        )
1130    }
1131
1132    /// Generate a TxContext for testing with a specific sender.
1133    pub fn with_sender_for_testing_only(sender: &IotaAddress) -> Self {
1134        Self::new(sender, &TransactionDigest::random(), &EpochData::new_test())
1135    }
1136}
1137
1138// TODO: rename to version
1139impl SequenceNumber {
1140    pub const MIN: SequenceNumber = SequenceNumber(u64::MIN);
1141    pub const MAX: SequenceNumber = SequenceNumber(0x7fff_ffff_ffff_ffff);
1142    pub const CANCELLED_READ: SequenceNumber = SequenceNumber(SequenceNumber::MAX.value() + 1);
1143    pub const CONGESTED: SequenceNumber = SequenceNumber(SequenceNumber::MAX.value() + 2);
1144    pub const RANDOMNESS_UNAVAILABLE: SequenceNumber =
1145        SequenceNumber(SequenceNumber::MAX.value() + 3);
1146
1147    pub const fn new() -> Self {
1148        SequenceNumber(0)
1149    }
1150
1151    pub const fn value(&self) -> u64 {
1152        self.0
1153    }
1154
1155    pub const fn from_u64(u: u64) -> Self {
1156        SequenceNumber(u)
1157    }
1158
1159    pub fn increment(&mut self) {
1160        assert_ne!(self.0, u64::MAX);
1161        self.0 += 1;
1162    }
1163
1164    pub fn increment_to(&mut self, next: SequenceNumber) {
1165        debug_assert!(*self < next, "Not an increment: {} to {}", self, next);
1166        *self = next;
1167    }
1168
1169    pub fn decrement(&mut self) {
1170        assert_ne!(self.0, 0);
1171        self.0 -= 1;
1172    }
1173
1174    pub fn decrement_to(&mut self, prev: SequenceNumber) {
1175        debug_assert!(prev < *self, "Not a decrement: {} to {}", self, prev);
1176        *self = prev;
1177    }
1178
1179    /// Returns a new sequence number that is greater than all `SequenceNumber`s
1180    /// in `inputs`, assuming this operation will not overflow.
1181    #[must_use]
1182    pub fn lamport_increment(inputs: impl IntoIterator<Item = SequenceNumber>) -> SequenceNumber {
1183        let max_input = inputs.into_iter().fold(SequenceNumber::new(), max);
1184
1185        // TODO: Ensure this never overflows.
1186        // Option 1: Freeze the object when sequence number reaches MAX.
1187        // Option 2: Reject tx with MAX sequence number.
1188        // Issue #182.
1189        assert_ne!(max_input.0, u64::MAX);
1190
1191        SequenceNumber(max_input.0 + 1)
1192    }
1193
1194    pub fn is_cancelled(&self) -> bool {
1195        self == &SequenceNumber::CANCELLED_READ
1196            || self == &SequenceNumber::CONGESTED
1197            || self == &SequenceNumber::RANDOMNESS_UNAVAILABLE
1198    }
1199
1200    pub fn is_valid(&self) -> bool {
1201        self < &SequenceNumber::MAX
1202    }
1203}
1204
1205impl From<SequenceNumber> for u64 {
1206    fn from(val: SequenceNumber) -> Self {
1207        val.0
1208    }
1209}
1210
1211impl From<u64> for SequenceNumber {
1212    fn from(value: u64) -> Self {
1213        SequenceNumber(value)
1214    }
1215}
1216
1217impl From<SequenceNumber> for usize {
1218    fn from(value: SequenceNumber) -> Self {
1219        value.0 as usize
1220    }
1221}
1222
1223impl ObjectID {
1224    /// The number of bytes in an address.
1225    pub const LENGTH: usize = AccountAddress::LENGTH;
1226    /// Hex address: 0x0
1227    pub const ZERO: Self = Self::new([0u8; Self::LENGTH]);
1228    pub const MAX: Self = Self::new([0xff; Self::LENGTH]);
1229    /// Create a new ObjectID
1230    pub const fn new(obj_id: [u8; Self::LENGTH]) -> Self {
1231        Self(AccountAddress::new(obj_id))
1232    }
1233
1234    /// Const fn variant of `<ObjectID as From<AccountAddress>>::from`
1235    pub const fn from_address(addr: AccountAddress) -> Self {
1236        Self(addr)
1237    }
1238
1239    /// Return a random ObjectID.
1240    pub fn random() -> Self {
1241        Self::from(AccountAddress::random())
1242    }
1243
1244    /// Return a random ObjectID from a given RNG.
1245    pub fn random_from_rng<R>(rng: &mut R) -> Self
1246    where
1247        R: AllowedRng,
1248    {
1249        let buf: [u8; Self::LENGTH] = rng.gen();
1250        ObjectID::new(buf)
1251    }
1252
1253    /// Return the underlying bytes buffer of the ObjectID.
1254    pub fn to_vec(&self) -> Vec<u8> {
1255        self.0.to_vec()
1256    }
1257
1258    /// Parse the ObjectID from byte array or buffer.
1259    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, ObjectIDParseError> {
1260        <[u8; Self::LENGTH]>::try_from(bytes.as_ref())
1261            .map_err(|_| ObjectIDParseError::TryFromSlice)
1262            .map(ObjectID::new)
1263    }
1264
1265    /// Return the underlying bytes array of the ObjectID.
1266    pub fn into_bytes(self) -> [u8; Self::LENGTH] {
1267        self.0.into_bytes()
1268    }
1269
1270    /// Make an ObjectID with padding 0s before the single byte.
1271    pub const fn from_single_byte(byte: u8) -> ObjectID {
1272        let mut bytes = [0u8; Self::LENGTH];
1273        bytes[Self::LENGTH - 1] = byte;
1274        ObjectID::new(bytes)
1275    }
1276
1277    /// Convert from hex string to ObjectID where the string is prefixed with 0x
1278    /// Padding 0s if the string is too short.
1279    pub fn from_hex_literal(literal: &str) -> Result<Self, ObjectIDParseError> {
1280        if !literal.starts_with("0x") {
1281            return Err(ObjectIDParseError::HexLiteralPrefixMissing);
1282        }
1283
1284        let hex_len = literal.len() - 2;
1285
1286        // If the string is too short, pad it
1287        if hex_len < Self::LENGTH * 2 {
1288            let mut hex_str = String::with_capacity(Self::LENGTH * 2);
1289            for _ in 0..Self::LENGTH * 2 - hex_len {
1290                hex_str.push('0');
1291            }
1292            hex_str.push_str(&literal[2..]);
1293            Self::from_str(&hex_str)
1294        } else {
1295            Self::from_str(&literal[2..])
1296        }
1297    }
1298
1299    /// Create an ObjectID from `TransactionDigest` and `creation_num`.
1300    /// Caller is responsible for ensuring that `creation_num` is fresh
1301    pub fn derive_id(digest: TransactionDigest, creation_num: u64) -> Self {
1302        let mut hasher = DefaultHash::default();
1303        hasher.update([HashingIntentScope::RegularObjectId as u8]);
1304        hasher.update(digest);
1305        hasher.update(creation_num.to_le_bytes());
1306        let hash = hasher.finalize();
1307
1308        // truncate into an ObjectID.
1309        // OK to access slice because digest should never be shorter than
1310        // ObjectID::LENGTH.
1311        ObjectID::try_from(&hash.as_ref()[0..ObjectID::LENGTH]).unwrap()
1312    }
1313
1314    /// Increment the ObjectID by usize IDs, assuming the ObjectID hex is a
1315    /// number represented as an array of bytes
1316    pub fn advance(&self, step: usize) -> Result<ObjectID, anyhow::Error> {
1317        let mut curr_vec = self.to_vec();
1318        let mut step_copy = step;
1319
1320        let mut carry = 0;
1321        for idx in (0..Self::LENGTH).rev() {
1322            if step_copy == 0 {
1323                // Nothing else to do
1324                break;
1325            }
1326            // Extract the relevant part
1327            let g = (step_copy % 0x100) as u16;
1328            // Shift to next group
1329            step_copy >>= 8;
1330            let mut val = curr_vec[idx] as u16;
1331            (carry, val) = ((val + carry + g) / 0x100, (val + carry + g) % 0x100);
1332            curr_vec[idx] = val as u8;
1333        }
1334
1335        if carry > 0 {
1336            return Err(anyhow!("Increment will cause overflow"));
1337        }
1338        ObjectID::try_from(curr_vec).map_err(|w| w.into())
1339    }
1340
1341    /// Increment the ObjectID by one, assuming the ObjectID hex is a number
1342    /// represented as an array of bytes
1343    pub fn next_increment(&self) -> Result<ObjectID, anyhow::Error> {
1344        let mut prev_val = self.to_vec();
1345        let mx = [0xFF; Self::LENGTH];
1346
1347        if prev_val == mx {
1348            return Err(anyhow!("Increment will cause overflow"));
1349        }
1350
1351        // This logic increments the integer representation of an ObjectID u8 array
1352        for idx in (0..Self::LENGTH).rev() {
1353            if prev_val[idx] == 0xFF {
1354                prev_val[idx] = 0;
1355            } else {
1356                prev_val[idx] += 1;
1357                break;
1358            };
1359        }
1360        ObjectID::try_from(prev_val.clone()).map_err(|w| w.into())
1361    }
1362
1363    /// Create `count` object IDs starting with one at `offset`
1364    pub fn in_range(offset: ObjectID, count: u64) -> Result<Vec<ObjectID>, anyhow::Error> {
1365        let mut ret = Vec::new();
1366        let mut prev = offset;
1367        for o in 0..count {
1368            if o != 0 {
1369                prev = prev.next_increment()?;
1370            }
1371            ret.push(prev);
1372        }
1373        Ok(ret)
1374    }
1375
1376    /// Return the full hex string with 0x prefix without removing trailing 0s.
1377    /// Prefer this over [fn to_hex_literal] if the string needs to be fully
1378    /// preserved.
1379    pub fn to_hex_uncompressed(&self) -> String {
1380        format!("{self}")
1381    }
1382
1383    pub fn is_clock(&self) -> bool {
1384        *self == IOTA_CLOCK_OBJECT_ID
1385    }
1386}
1387
1388impl From<IotaAddress> for ObjectID {
1389    fn from(address: IotaAddress) -> ObjectID {
1390        let tmp: AccountAddress = address.into();
1391        tmp.into()
1392    }
1393}
1394
1395impl From<AccountAddress> for ObjectID {
1396    fn from(address: AccountAddress) -> Self {
1397        Self(address)
1398    }
1399}
1400
1401impl fmt::Display for ObjectID {
1402    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1403        write!(f, "0x{}", Hex::encode(self.0))
1404    }
1405}
1406
1407impl fmt::Debug for ObjectID {
1408    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1409        write!(f, "0x{}", Hex::encode(self.0))
1410    }
1411}
1412
1413impl AsRef<[u8]> for ObjectID {
1414    fn as_ref(&self) -> &[u8] {
1415        self.0.as_slice()
1416    }
1417}
1418
1419impl TryFrom<&[u8]> for ObjectID {
1420    type Error = ObjectIDParseError;
1421
1422    /// Tries to convert the provided byte array into ObjectID.
1423    fn try_from(bytes: &[u8]) -> Result<ObjectID, ObjectIDParseError> {
1424        Self::from_bytes(bytes)
1425    }
1426}
1427
1428impl TryFrom<Vec<u8>> for ObjectID {
1429    type Error = ObjectIDParseError;
1430
1431    /// Tries to convert the provided byte buffer into ObjectID.
1432    fn try_from(bytes: Vec<u8>) -> Result<ObjectID, ObjectIDParseError> {
1433        Self::from_bytes(bytes)
1434    }
1435}
1436
1437impl FromStr for ObjectID {
1438    type Err = ObjectIDParseError;
1439
1440    /// Parse ObjectID from hex string with or without 0x prefix, pad with 0s if
1441    /// needed.
1442    fn from_str(s: &str) -> Result<Self, ObjectIDParseError> {
1443        decode_bytes_hex(s).or_else(|_| Self::from_hex_literal(s))
1444    }
1445}
1446
1447impl std::ops::Deref for ObjectID {
1448    type Target = AccountAddress;
1449
1450    fn deref(&self) -> &Self::Target {
1451        &self.0
1452    }
1453}
1454
1455/// Generate a fake ObjectID with repeated one byte.
1456pub fn dbg_object_id(name: u8) -> ObjectID {
1457    ObjectID::new([name; ObjectID::LENGTH])
1458}
1459
1460#[derive(PartialEq, Eq, Clone, Debug, thiserror::Error)]
1461pub enum ObjectIDParseError {
1462    #[error("ObjectID hex literal must start with 0x")]
1463    HexLiteralPrefixMissing,
1464
1465    #[error("Could not convert from bytes slice")]
1466    TryFromSlice,
1467}
1468
1469impl From<ObjectID> for AccountAddress {
1470    fn from(obj_id: ObjectID) -> Self {
1471        obj_id.0
1472    }
1473}
1474
1475impl From<IotaAddress> for AccountAddress {
1476    fn from(address: IotaAddress) -> Self {
1477        Self::new(address.0)
1478    }
1479}
1480
1481impl fmt::Display for MoveObjectType {
1482    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
1483        let s: StructTag = self.clone().into();
1484        write!(
1485            f,
1486            "{}",
1487            to_iota_struct_tag_string(&s).map_err(fmt::Error::custom)?
1488        )
1489    }
1490}
1491
1492impl fmt::Display for ObjectType {
1493    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
1494        match self {
1495            ObjectType::Package => write!(f, "{}", PACKAGE),
1496            ObjectType::Struct(t) => write!(f, "{}", t),
1497        }
1498    }
1499}
1500
1501// SizeOneVec is a wrapper around Vec<T> that enforces the size of the vec to be
1502// 1. This seems pointless, but it allows us to have fields in protocol messages
1503// that are current enforced to be of size 1, but might later allow other sizes,
1504// and to have that constraint enforced in the serialization/deserialization
1505// layer, instead of requiring manual input validation.
1506#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
1507#[serde(try_from = "Vec<T>")]
1508pub struct SizeOneVec<T> {
1509    e: T,
1510}
1511
1512impl<T> SizeOneVec<T> {
1513    pub fn new(e: T) -> Self {
1514        Self { e }
1515    }
1516
1517    pub fn element(&self) -> &T {
1518        &self.e
1519    }
1520
1521    pub fn element_mut(&mut self) -> &mut T {
1522        &mut self.e
1523    }
1524
1525    pub fn into_inner(self) -> T {
1526        self.e
1527    }
1528
1529    pub fn iter(&self) -> std::iter::Once<&T> {
1530        std::iter::once(&self.e)
1531    }
1532}
1533
1534impl<T> Serialize for SizeOneVec<T>
1535where
1536    T: Serialize,
1537{
1538    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1539    where
1540        S: Serializer,
1541    {
1542        let mut seq = serializer.serialize_seq(Some(1))?;
1543        seq.serialize_element(&self.e)?;
1544        seq.end()
1545    }
1546}
1547
1548impl<T> TryFrom<Vec<T>> for SizeOneVec<T> {
1549    type Error = anyhow::Error;
1550
1551    fn try_from(mut v: Vec<T>) -> Result<Self, Self::Error> {
1552        if v.len() != 1 {
1553            Err(anyhow!("Expected a vec of size 1"))
1554        } else {
1555            Ok(SizeOneVec {
1556                e: v.pop().unwrap(),
1557            })
1558        }
1559    }
1560}
1561
1562#[test]
1563fn test_size_one_vec_is_transparent() {
1564    let regular = vec![42u8];
1565    let size_one = SizeOneVec::new(42u8);
1566
1567    // Vec -> SizeOneVec serialization is transparent
1568    let regular_ser = bcs::to_bytes(&regular).unwrap();
1569    let size_one_deser = bcs::from_bytes::<SizeOneVec<u8>>(&regular_ser).unwrap();
1570    assert_eq!(size_one, size_one_deser);
1571
1572    // other direction works too
1573    let size_one_ser = bcs::to_bytes(&SizeOneVec::new(43u8)).unwrap();
1574    let regular_deser = bcs::from_bytes::<Vec<u8>>(&size_one_ser).unwrap();
1575    assert_eq!(regular_deser, vec![43u8]);
1576
1577    // we get a deserialize error when deserializing a vec with size != 1
1578    let empty_ser = bcs::to_bytes(&Vec::<u8>::new()).unwrap();
1579    bcs::from_bytes::<SizeOneVec<u8>>(&empty_ser).unwrap_err();
1580
1581    let size_greater_than_one_ser = bcs::to_bytes(&vec![1u8, 2u8]).unwrap();
1582    bcs::from_bytes::<SizeOneVec<u8>>(&size_greater_than_one_ser).unwrap_err();
1583}