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