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