iota_types/
base_types.rs

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