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