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