sui_types/
object.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::collections::BTreeMap;
5use std::convert::TryFrom;
6use std::fmt::{Debug, Display, Formatter};
7use std::sync::Arc;
8
9use move_binary_format::CompiledModule;
10use move_bytecode_utils::layout::TypeLayoutBuilder;
11use move_bytecode_utils::module_cache::GetModule;
12use move_core_types::annotated_value::{MoveStruct, MoveStructLayout, MoveTypeLayout, MoveValue};
13use move_core_types::language_storage::StructTag;
14use move_core_types::language_storage::TypeTag;
15use mysten_common::debug_fatal;
16use once_cell::sync::Lazy;
17use schemars::JsonSchema;
18use serde::{Deserialize, Serialize};
19use serde_with::Bytes;
20use serde_with::serde_as;
21
22use crate::accumulator_root::AccumulatorValue;
23use crate::base_types::{FullObjectID, FullObjectRef, MoveObjectType, ObjectIDParseError};
24use crate::coin::{Coin, CoinMetadata, TreasuryCap};
25use crate::crypto::{default_hash, deterministic_random_account_key};
26use crate::error::{
27    ExecutionError, SuiError, SuiErrorKind, SuiResult, UserInputError, UserInputResult,
28};
29use crate::execution_status::ExecutionErrorKind;
30use crate::gas_coin::GAS;
31use crate::is_system_package;
32use crate::layout_resolver::LayoutResolver;
33use crate::move_package::MovePackage;
34use crate::{
35    base_types::{
36        ObjectDigest, ObjectID, ObjectRef, SequenceNumber, SuiAddress, TransactionDigest,
37    },
38    gas_coin::GasCoin,
39};
40use sui_protocol_config::ProtocolConfig;
41
42use self::balance_traversal::BalanceTraversal;
43use self::bounded_visitor::BoundedVisitor;
44
45mod balance_traversal;
46pub mod bounded_visitor;
47pub mod option_visitor;
48pub mod rpc_visitor;
49
50pub const GAS_VALUE_FOR_TESTING: u64 = 300_000_000_000_000;
51pub const OBJECT_START_VERSION: SequenceNumber = SequenceNumber::from_u64(1);
52
53#[serde_as]
54#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)]
55pub struct MoveObject {
56    /// The type of this object. Immutable
57    type_: MoveObjectType,
58    /// DEPRECATED this field is no longer used to determine whether a tx can transfer this
59    /// object. Instead, it is always calculated from the objects type when loaded in execution
60    has_public_transfer: bool,
61    /// Number that increases each time a tx takes this object as a mutable input
62    /// This is a lamport timestamp, not a sequentially increasing version
63    version: SequenceNumber,
64    /// BCS bytes of a Move struct value
65    #[serde_as(as = "Bytes")]
66    contents: Vec<u8>,
67}
68
69/// Index marking the end of the object's ID + the beginning of its version
70pub const ID_END_INDEX: usize = ObjectID::LENGTH;
71
72impl MoveObject {
73    /// Creates a new Move object of type `type_` with BCS encoded bytes in `contents`
74    /// `has_public_transfer` is determined by the abilities of the `type_`, but resolving
75    /// the abilities requires the compiled modules of the `type_: StructTag`.
76    /// In other words, `has_public_transfer` will be the same for all objects of the same `type_`.
77    ///
78    /// # Safety
79    ///
80    /// This function should ONLY be called if has_public_transfer has been determined by the type_.
81    /// Yes, this is a bit of an abuse of the `unsafe` marker, but bad things will happen if this
82    /// is inconsistent
83    pub unsafe fn new_from_execution(
84        type_: MoveObjectType,
85        has_public_transfer: bool,
86        version: SequenceNumber,
87        contents: Vec<u8>,
88        protocol_config: &ProtocolConfig,
89        system_mutation: bool,
90    ) -> Result<Self, ExecutionError> {
91        let bound = if protocol_config.allow_unbounded_system_objects() && system_mutation {
92            if contents.len() as u64 > protocol_config.max_move_object_size() {
93                debug_fatal!(
94                    "System created object (ID = {:?}) of type {:?} and size {} exceeds normal max size {}",
95                    MoveObject::id_opt(&contents).ok(),
96                    type_,
97                    contents.len(),
98                    protocol_config.max_move_object_size()
99                );
100            }
101            u64::MAX
102        } else {
103            protocol_config.max_move_object_size()
104        };
105        unsafe {
106            Self::new_from_execution_with_limit(
107                type_,
108                has_public_transfer,
109                version,
110                contents,
111                bound,
112            )
113        }
114    }
115
116    /// # Safety
117    /// This function should ONLY be called if has_public_transfer has been determined by the type_
118    pub unsafe fn new_from_execution_with_limit(
119        type_: MoveObjectType,
120        has_public_transfer: bool,
121        version: SequenceNumber,
122        contents: Vec<u8>,
123        max_move_object_size: u64,
124    ) -> Result<Self, ExecutionError> {
125        // coins should always have public transfer, as they always should have store.
126        // Thus, type_ == GasCoin::type_() ==> has_public_transfer
127        // TODO: think this can be generalized to is_coin
128        debug_assert!(!type_.is_gas_coin() || has_public_transfer);
129        if contents.len() as u64 > max_move_object_size {
130            return Err(ExecutionError::from_kind(
131                ExecutionErrorKind::MoveObjectTooBig {
132                    object_size: contents.len() as u64,
133                    max_object_size: max_move_object_size,
134                },
135            ));
136        }
137        Ok(Self {
138            type_,
139            has_public_transfer,
140            version,
141            contents,
142        })
143    }
144
145    pub fn new_gas_coin(version: SequenceNumber, id: ObjectID, value: u64) -> Self {
146        // unwrap safe because coins are always smaller than the max object size
147        unsafe {
148            Self::new_from_execution_with_limit(
149                GasCoin::type_().into(),
150                true,
151                version,
152                GasCoin::new(id, value).to_bcs_bytes(),
153                256,
154            )
155            .unwrap()
156        }
157    }
158
159    pub fn new_coin(coin_type: TypeTag, version: SequenceNumber, id: ObjectID, value: u64) -> Self {
160        // unwrap safe because coins are always smaller than the max object size
161        unsafe {
162            Self::new_from_execution_with_limit(
163                MoveObjectType::coin(coin_type),
164                true,
165                version,
166                Coin::new(id, value).to_bcs_bytes(),
167                256,
168            )
169            .unwrap()
170        }
171    }
172
173    pub fn type_(&self) -> &MoveObjectType {
174        &self.type_
175    }
176
177    pub fn is_type(&self, s: &StructTag) -> bool {
178        self.type_.is(s)
179    }
180
181    pub fn has_public_transfer(&self) -> bool {
182        self.has_public_transfer
183    }
184
185    pub fn id(&self) -> ObjectID {
186        Self::id_opt(&self.contents).unwrap()
187    }
188
189    pub fn id_opt(contents: &[u8]) -> Result<ObjectID, ObjectIDParseError> {
190        if ID_END_INDEX > contents.len() {
191            return Err(ObjectIDParseError::TryFromSliceError);
192        }
193        ObjectID::try_from(&contents[0..ID_END_INDEX])
194    }
195
196    /// Return the `value: u64` field of a `Coin<T>` type.
197    /// Useful for reading the coin without deserializing the object into a Move value
198    /// It is the caller's responsibility to check that `self` is a coin--this function
199    /// may panic or do something unexpected otherwise.
200    pub fn get_coin_value_unsafe(&self) -> u64 {
201        debug_assert!(self.type_.is_coin());
202        // 32 bytes for object ID, 8 for balance
203        debug_assert!(self.contents.len() == 40);
204
205        // unwrap safe because we checked that it is a coin
206        u64::from_le_bytes(<[u8; 8]>::try_from(&self.contents[ID_END_INDEX..]).unwrap())
207    }
208
209    /// Update the `value: u64` field of a `Coin<T>` type.
210    /// Useful for updating the coin without deserializing the object into a Move value
211    /// It is the caller's responsibility to check that `self` is a coin--this function
212    /// may panic or do something unexpected otherwise.
213    pub fn set_coin_value_unsafe(&mut self, value: u64) {
214        debug_assert!(self.type_.is_coin());
215        // 32 bytes for object ID, 8 for balance
216        debug_assert!(self.contents.len() == 40);
217
218        self.contents.splice(ID_END_INDEX.., value.to_le_bytes());
219    }
220
221    /// Update the `timestamp_ms: u64` field of the `Clock` type.
222    ///
223    /// Panics if the object isn't a `Clock`.
224    pub fn set_clock_timestamp_ms_unsafe(&mut self, timestamp_ms: u64) {
225        assert!(self.is_clock());
226        // 32 bytes for object ID, 8 for timestamp
227        assert!(self.contents.len() == 40);
228
229        self.contents
230            .splice(ID_END_INDEX.., timestamp_ms.to_le_bytes());
231    }
232
233    pub fn set_contents_unsafe(&mut self, contents: Vec<u8>) {
234        self.contents = contents;
235    }
236
237    pub fn is_coin(&self) -> bool {
238        self.type_.is_coin()
239    }
240
241    pub fn is_staked_sui(&self) -> bool {
242        self.type_.is_staked_sui()
243    }
244
245    pub fn is_clock(&self) -> bool {
246        self.type_.is(&crate::clock::Clock::type_())
247    }
248
249    pub fn version(&self) -> SequenceNumber {
250        self.version
251    }
252
253    pub fn contents_and_type_equal(&self, other: &Self) -> bool {
254        self.contents == other.contents && self.type_ == other.type_
255    }
256
257    /// Contents of the object that are specific to its type--i.e., not its ID and version, which all objects have
258    /// For example if the object was declared as `struct S has key { id: ID, f1: u64, f2: bool },
259    /// this returns the slice containing `f1` and `f2`.
260    #[cfg(test)]
261    pub fn type_specific_contents(&self) -> &[u8] {
262        &self.contents[ID_END_INDEX..]
263    }
264
265    /// Update the contents of this object but does not increment its version
266    /// This should only be used for safe mode epoch advancement.
267    pub(crate) fn update_contents_advance_epoch_safe_mode(
268        &mut self,
269        new_contents: Vec<u8>,
270        protocol_config: &ProtocolConfig,
271    ) -> Result<(), ExecutionError> {
272        if new_contents.len() as u64 > protocol_config.max_move_object_size() {
273            if protocol_config.allow_unbounded_system_objects() {
274                debug_fatal!(
275                    "Safe mode object update (ID = {}) of size {} exceeds normal max size {}",
276                    self.id(),
277                    new_contents.len(),
278                    protocol_config.max_move_object_size()
279                )
280            } else {
281                return Err(ExecutionError::from_kind(
282                    ExecutionErrorKind::MoveObjectTooBig {
283                        object_size: new_contents.len() as u64,
284                        max_object_size: protocol_config.max_move_object_size(),
285                    },
286                ));
287            }
288        }
289
290        #[cfg(debug_assertions)]
291        let old_id = self.id();
292        self.contents = new_contents;
293
294        // Update should not modify ID
295        #[cfg(debug_assertions)]
296        debug_assert_eq!(self.id(), old_id);
297
298        Ok(())
299    }
300
301    /// Sets the version of this object to a new value which is assumed to be higher (and checked to
302    /// be higher in debug).
303    pub fn increment_version_to(&mut self, next: SequenceNumber) {
304        self.version.increment_to(next);
305    }
306
307    pub fn decrement_version_to(&mut self, prev: SequenceNumber) {
308        self.version.decrement_to(prev);
309    }
310
311    pub fn contents(&self) -> &[u8] {
312        &self.contents
313    }
314
315    pub fn into_contents(self) -> Vec<u8> {
316        self.contents
317    }
318
319    pub fn into_type(self) -> MoveObjectType {
320        self.type_
321    }
322
323    pub fn into_inner(self) -> (MoveObjectType, Vec<u8>) {
324        (self.type_, self.contents)
325    }
326
327    /// Get a `MoveStructLayout` for `self`.
328    /// The `resolver` value must contain the module that declares `self.type_` and the (transitive)
329    /// dependencies of `self.type_` in order for this to succeed. Failure will result in an `ObjectSerializationError`
330    pub fn get_layout(&self, resolver: &impl GetModule) -> Result<MoveStructLayout, SuiError> {
331        Self::get_struct_layout_from_struct_tag(self.type_().clone().into(), resolver)
332    }
333
334    pub fn get_struct_layout_from_struct_tag(
335        struct_tag: StructTag,
336        resolver: &impl GetModule,
337    ) -> Result<MoveStructLayout, SuiError> {
338        let type_ = TypeTag::Struct(Box::new(struct_tag));
339        let layout = TypeLayoutBuilder::build_with_types(&type_, resolver).map_err(|e| {
340            SuiErrorKind::ObjectSerializationError {
341                error: e.to_string(),
342            }
343        })?;
344        match layout {
345            MoveTypeLayout::Struct(l) => Ok(*l),
346            _ => unreachable!(
347                "We called build_with_types on Struct type, should get a struct layout"
348            ),
349        }
350    }
351
352    /// Convert `self` to the JSON representation dictated by `layout`.
353    pub fn to_move_struct(&self, layout: &MoveStructLayout) -> Result<MoveStruct, SuiError> {
354        BoundedVisitor::deserialize_struct(&self.contents, layout).map_err(|e| {
355            SuiErrorKind::ObjectSerializationError {
356                error: e.to_string(),
357            }
358            .into()
359        })
360    }
361
362    /// Convert `self` to the JSON representation dictated by `layout`.
363    pub fn to_move_struct_with_resolver(
364        &self,
365        resolver: &impl GetModule,
366    ) -> Result<MoveStruct, SuiError> {
367        self.to_move_struct(&self.get_layout(resolver)?)
368    }
369
370    pub fn to_rust<'de, T: Deserialize<'de>>(&'de self) -> Option<T> {
371        bcs::from_bytes(self.contents()).ok()
372    }
373
374    /// Approximate size of the object in bytes. This is used for gas metering.
375    /// For the type tag field, we serialize it on the spot to get the accurate size.
376    /// This should not be very expensive since the type tag is usually simple, and
377    /// we only do this once per object being mutated.
378    pub fn object_size_for_gas_metering(&self) -> usize {
379        let serialized_type_tag_size =
380            bcs::serialized_size(&self.type_).expect("Serializing type tag should not fail");
381        // + 1 for 'has_public_transfer'
382        // + 8 for `version`
383        self.contents.len() + serialized_type_tag_size + 1 + 8
384    }
385
386    /// Get the total amount of SUI embedded in `self`. Intended for testing purposes
387    pub fn get_total_sui(&self, layout_resolver: &mut dyn LayoutResolver) -> Result<u64, SuiError> {
388        if self.type_.is_gas_coin() {
389            let balance = self.get_coin_value_unsafe();
390            Ok(balance)
391        } else if self.type_.coin_type_maybe().is_some() {
392            // It's a coin, but its not SUI
393            Ok(0)
394        } else if self.type_.is_sui_balance_accumulator_field() {
395            let value = AccumulatorValue::try_from(self)?;
396            let AccumulatorValue::U128(v) = value;
397            // Well behaved balance types can never have more than their total supply
398            // anywhere, which is 10B for SUI.
399            assert!(
400                v.value <= u64::MAX as u128,
401                "SUI balance cannot exceed u64::MAX"
402            );
403            Ok(v.value as u64)
404        } else {
405            let layout = layout_resolver.get_annotated_layout(&self.type_().clone().into())?;
406
407            let mut traversal = BalanceTraversal::default();
408            MoveValue::visit_deserialize(&self.contents, &layout.into_layout(), &mut traversal)
409                .map_err(|e| SuiErrorKind::ObjectSerializationError {
410                    error: e.to_string(),
411                })?;
412
413            Ok(traversal
414                .finish()
415                .get(&GAS::type_tag())
416                .copied()
417                .unwrap_or(0))
418        }
419    }
420}
421
422#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)]
423#[allow(clippy::large_enum_variant)]
424pub enum Data {
425    /// An object whose governing logic lives in a published Move module
426    Move(MoveObject),
427    /// Map from each module name to raw serialized Move module bytes
428    Package(MovePackage),
429    // ... Sui "native" types go here
430}
431
432impl Data {
433    pub fn try_as_move(&self) -> Option<&MoveObject> {
434        use Data::*;
435        match self {
436            Move(m) => Some(m),
437            Package(_) => None,
438        }
439    }
440
441    pub fn try_as_move_mut(&mut self) -> Option<&mut MoveObject> {
442        use Data::*;
443        match self {
444            Move(m) => Some(m),
445            Package(_) => None,
446        }
447    }
448
449    pub fn try_as_package(&self) -> Option<&MovePackage> {
450        use Data::*;
451        match self {
452            Move(_) => None,
453            Package(p) => Some(p),
454        }
455    }
456
457    pub fn try_as_package_mut(&mut self) -> Option<&mut MovePackage> {
458        use Data::*;
459        match self {
460            Move(_) => None,
461            Package(p) => Some(p),
462        }
463    }
464
465    pub fn try_into_package(self) -> Option<MovePackage> {
466        use Data::*;
467        match self {
468            Move(_) => None,
469            Package(p) => Some(p),
470        }
471    }
472
473    pub fn type_(&self) -> Option<&MoveObjectType> {
474        use Data::*;
475        match self {
476            Move(m) => Some(m.type_()),
477            Package(_) => None,
478        }
479    }
480
481    pub fn struct_tag(&self) -> Option<StructTag> {
482        use Data::*;
483        match self {
484            Move(m) => Some(m.type_().clone().into()),
485            Package(_) => None,
486        }
487    }
488
489    pub fn id(&self) -> ObjectID {
490        match self {
491            Self::Move(v) => v.id(),
492            Self::Package(m) => m.id(),
493        }
494    }
495}
496
497/// A single permission that can be granted on a party-owned object.
498///
499/// Bit layout (u8):
500///
501/// ```text
502///  7  6  5  4  3  2  1  0
503///  _  W  P  T  D  M  U  I
504/// ```
505///
506/// - `I` Bit 0: [`Self::ImmutableUsage`] is required for immutable usage at signing
507/// - `U` Bit 1: [`Self::MutableUsage`] is required for mutable usage at signing
508///   - It is also required for any additional permissions below
509/// - `M` Bit 2: [`Self::Write`] allows for the value of the object to be changed
510/// - `D` Bit 3: [`Self::Delete`] allows for the object to be deleted
511/// - `T` Bit 4: [`Self::InternalTransfer`] allows for usage of the internal transfer functions
512/// - `P` Bit 5: [`Self::PublicTransfer`] allows for usage of public transfer functions
513/// - `W` Bit 6: [`Self::Wrap`] allows for the object to be wrapped
514#[repr(u8)]
515#[derive(Debug, Clone, Eq, Copy, Hash, Ord, PartialEq, PartialOrd)]
516pub enum ObjectPermission {
517    ImmutableUsage = 1 << 0,
518    MutableUsage = 1 << 1,
519    Write = 1 << 2,
520    Delete = 1 << 3,
521    InternalTransfer = 1 << 4,
522    PublicTransfer = 1 << 5,
523    Wrap = 1 << 6,
524}
525
526impl ObjectPermission {
527    pub fn from_u64(bits: u64) -> Option<Self> {
528        match bits {
529            b if b == Self::Write as u64 => Some(Self::Write),
530            b if b == Self::Delete as u64 => Some(Self::Delete),
531            b if b == Self::InternalTransfer as u64 => Some(Self::InternalTransfer),
532            b if b == Self::PublicTransfer as u64 => Some(Self::PublicTransfer),
533            b if b == Self::Wrap as u64 => Some(Self::Wrap),
534            b if b == Self::MutableUsage as u64 => Some(Self::MutableUsage),
535            b if b == Self::ImmutableUsage as u64 => Some(Self::ImmutableUsage),
536            _ => {
537                debug_assert!(false, "Invalid ObjectPermission bit pattern: {bits}.");
538                None
539            }
540        }
541    }
542}
543
544impl Display for ObjectPermission {
545    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
546        match self {
547            Self::Write => write!(f, "Write"),
548            Self::Delete => write!(f, "Delete"),
549            Self::InternalTransfer => write!(f, "InternalTransfer"),
550            Self::PublicTransfer => write!(f, "PublicTransfer"),
551            Self::Wrap => write!(f, "Wrap"),
552            Self::MutableUsage => write!(f, "MutableUsage"),
553            Self::ImmutableUsage => write!(f, "ImmutableUsage"),
554        }
555    }
556}
557
558/// A bitflag set of `ObjectPermission`s.
559#[derive(
560    Eq, PartialEq, Debug, Clone, Copy, Deserialize, Serialize, Hash, JsonSchema, Ord, PartialOrd,
561)]
562#[serde(try_from = "u64", into = "u64")]
563pub struct ObjectPermissions(u64);
564
565#[cfg(feature = "fuzzing")]
566impl proptest::arbitrary::Arbitrary for ObjectPermissions {
567    type Parameters = ();
568    type Strategy = proptest::strategy::BoxedStrategy<Self>;
569    fn arbitrary_with(_: ()) -> Self::Strategy {
570        use proptest::prelude::*;
571        any::<u8>()
572            .prop_map(|bits| {
573                let mut bits = bits as u64 & Self::ALL_BITS;
574                if bits & Self::MUTABLE_PERMISSION_BITS != 0 {
575                    bits |= ObjectPermission::MutableUsage as u64;
576                }
577                Self(bits)
578            })
579            .boxed()
580    }
581}
582
583impl ObjectPermissions {
584    /// Bitmask of the individual mutable permissions.
585    /// Each requires [`ObjectPermission::MutableUsage`] to also be set.
586    const MUTABLE_PERMISSION_BITS: u64 = (ObjectPermission::Write as u64)
587        | (ObjectPermission::Delete as u64)
588        | (ObjectPermission::InternalTransfer as u64)
589        | (ObjectPermission::PublicTransfer as u64)
590        | (ObjectPermission::Wrap as u64);
591
592    /// Bitmask of all known bits.
593    const ALL_BITS: u64 = Self::MUTABLE_PERMISSION_BITS
594        | (ObjectPermission::MutableUsage as u64)
595        | (ObjectPermission::ImmutableUsage as u64);
596
597    pub const NONE: Self = Self(0);
598    pub const IMMUTABLE_USAGE: Self = Self::from_bits(ObjectPermission::ImmutableUsage as u64);
599    pub const MUTABLE_USAGE: Self = Self::from_bits(ObjectPermission::MutableUsage as u64);
600    pub const WRITE: Self =
601        Self::from_bits(ObjectPermission::Write as u64 | ObjectPermission::MutableUsage as u64);
602    pub const DELETE: Self =
603        Self::from_bits(ObjectPermission::Delete as u64 | ObjectPermission::MutableUsage as u64);
604    pub const INTERNAL_TRANSFER: Self = Self::from_bits(
605        ObjectPermission::InternalTransfer as u64 | ObjectPermission::MutableUsage as u64,
606    );
607    pub const PUBLIC_TRANSFER: Self = Self::from_bits(
608        ObjectPermission::PublicTransfer as u64 | ObjectPermission::MutableUsage as u64,
609    );
610    pub const WRAP: Self =
611        Self::from_bits(ObjectPermission::Wrap as u64 | ObjectPermission::MutableUsage as u64);
612    pub const ALL: Self = Self::from_bits(Self::ALL_BITS);
613
614    pub const LEGACY_SHARED_OBJECT: Self = Self::from_bits(
615        (ObjectPermission::Write as u64)
616            | (ObjectPermission::Delete as u64)
617            | (ObjectPermission::MutableUsage as u64)
618            | (ObjectPermission::ImmutableUsage as u64),
619    );
620
621    /// Private const constructor. Asserts that:
622    /// - no unknown bits are set
623    /// - if any individual mutable permission is set, `MutableUsage` is also set
624    const fn from_bits(bits: u64) -> Self {
625        assert!(bits & !Self::ALL_BITS == 0, "unknown permission bit");
626        let has_mutable_perm = bits & Self::MUTABLE_PERMISSION_BITS != 0;
627        let has_mutable_usage = bits & (ObjectPermission::MutableUsage as u64) != 0;
628        assert!(
629            !has_mutable_perm || has_mutable_usage,
630            "a mutable permission requires MutableUsage"
631        );
632        Self(bits)
633    }
634
635    /// Construct from raw bits. Returns `None` if any unknown bit is set, or
636    /// if any individual mutable permission is set without `MutableUsage`.
637    pub const fn new(bits: u64) -> Option<Self> {
638        if bits & !Self::ALL_BITS != 0 {
639            return None;
640        }
641        let has_mutable_perm = bits & Self::MUTABLE_PERMISSION_BITS != 0;
642        let has_mutable_usage = bits & (ObjectPermission::MutableUsage as u64) != 0;
643        if has_mutable_perm && !has_mutable_usage {
644            return None;
645        }
646        Some(Self(bits))
647    }
648
649    pub fn can(&self, permission: ObjectPermission) -> bool {
650        let p = permission as u64;
651        (self.0 & p) == p
652    }
653
654    /// Can it change the Move value of the object?
655    pub fn can_write(&self) -> bool {
656        self.can(ObjectPermission::Write)
657    }
658
659    /// Can the object's UID be deleted?
660    // TODO(Party WIP) this might also gate derived object UID release
661    pub fn can_delete(&self) -> bool {
662        self.can(ObjectPermission::Delete)
663    }
664
665    /// Can the object be transferred using the internal transfer functions?
666    pub fn can_internal_transfer(&self) -> bool {
667        self.can(ObjectPermission::InternalTransfer)
668    }
669
670    /// Can the object be transferred using the public transfer functions?
671    pub fn can_public_transfer(&self) -> bool {
672        self.can(ObjectPermission::PublicTransfer)
673    }
674
675    /// Can the object be wrapped?
676    // TODO(Party WIP) this might _not_ gate derived object UID release even though it will be a
677    // wrap
678    pub fn can_wrap(&self) -> bool {
679        self.can(ObjectPermission::Wrap)
680    }
681
682    /// Can the object be used as a mutable input in a transaction?
683    /// Note that this is required for all mutable permissions
684    pub fn can_use_mutably(&self) -> bool {
685        self.can(ObjectPermission::MutableUsage)
686    }
687
688    /// Can the object be used as an immutable input in a transaction?
689    pub fn can_use_immutably(&self) -> bool {
690        self.can(ObjectPermission::ImmutableUsage)
691    }
692
693    #[inline(always)]
694    const fn is_subset_bits(sub: u64, sup: u64) -> bool {
695        (sub & sup) == sub
696    }
697
698    pub const fn is_subset(&self, other: Self) -> bool {
699        Self::is_subset_bits(self.0, other.0)
700    }
701}
702
703impl std::ops::BitOr<ObjectPermissions> for ObjectPermissions {
704    type Output = Self;
705    fn bitor(self, rhs: Self) -> Self {
706        // Two valid sets union into a valid set: any mutable permission in
707        // either input was already paired with MutableUsage there.
708        Self(self.0 | rhs.0)
709    }
710}
711
712impl TryFrom<u64> for ObjectPermissions {
713    type Error = &'static str;
714    fn try_from(bits: u64) -> Result<Self, Self::Error> {
715        Self::new(bits).ok_or("invalid ObjectPermissions bits")
716    }
717}
718
719impl From<ObjectPermissions> for u64 {
720    fn from(p: ObjectPermissions) -> u64 {
721        p.0
722    }
723}
724
725pub struct ObjectPermissionsIterator {
726    set: ObjectPermissions,
727    idx: usize,
728    #[cfg(debug_assertions)]
729    emitted: u64,
730}
731
732impl ObjectPermissionsIterator {
733    const ORDER: &'static [ObjectPermission] = &[
734        ObjectPermission::ImmutableUsage,
735        ObjectPermission::MutableUsage,
736        ObjectPermission::Write,
737        ObjectPermission::Delete,
738        ObjectPermission::InternalTransfer,
739        ObjectPermission::PublicTransfer,
740        ObjectPermission::Wrap,
741    ];
742}
743
744impl Iterator for ObjectPermissionsIterator {
745    type Item = ObjectPermission;
746
747    fn next(&mut self) -> Option<Self::Item> {
748        while self.idx < Self::ORDER.len() {
749            let p = Self::ORDER[self.idx];
750            self.idx += 1;
751            if self.set.can(p) {
752                #[cfg(debug_assertions)]
753                {
754                    self.emitted |= p as u64;
755                }
756                return Some(p);
757            }
758        }
759        #[cfg(debug_assertions)]
760        debug_assert_eq!(
761            self.emitted, self.set.0,
762            "ObjectPermissionsIterator did not iterate over every permission in the set",
763        );
764        None
765    }
766}
767
768impl IntoIterator for ObjectPermissions {
769    type Item = ObjectPermission;
770    type IntoIter = ObjectPermissionsIterator;
771    fn into_iter(self) -> Self::IntoIter {
772        debug_assert_eq!(
773            ObjectPermissionsIterator::ORDER
774                .iter()
775                .copied()
776                .fold(0u64, |a, p| {
777                    let bit = p as u64;
778                    debug_assert_eq!(
779                        a & bit,
780                        0,
781                        "duplicate ObjectPermission in ObjectPermissionsIterator::ORDER: {p:?}",
782                    );
783                    a | bit
784                }),
785            ObjectPermissions::ALL.0,
786            "ObjectPermissionsIterator::ORDER must contain every ObjectPermission",
787        );
788        ObjectPermissionsIterator {
789            idx: 0,
790            set: self,
791            #[cfg(debug_assertions)]
792            emitted: 0,
793        }
794    }
795}
796
797impl Display for ObjectPermissions {
798    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
799        write!(f, "{{")?;
800        let mut first = true;
801        for permission in *self {
802            if !first {
803                write!(f, ",")?;
804            }
805            write!(f, "{}", permission)?;
806            first = false;
807        }
808        write!(f, "}}")
809    }
810}
811
812/// Per-address permission map for a party-owned object.
813/// Addresses not in `members` receive `default_permissions`.
814#[derive(
815    Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash, JsonSchema, Ord, PartialOrd,
816)]
817#[serde(try_from = "RawPartySerde", into = "RawPartySerde")]
818pub struct Party {
819    /// The default permissions, used for any party member not explicitly listed in `members`.
820    default_permissions: ObjectPermissions,
821    /// The permissions for each party member.
822    members: BTreeMap<SuiAddress, ObjectPermissions>,
823}
824
825impl Party {
826    /// Returns `None` if it could be represented as a single `ConsensusAddressOwner`
827    pub fn new(
828        default_permissions: ObjectPermissions,
829        members: BTreeMap<SuiAddress, ObjectPermissions>,
830    ) -> Option<Self> {
831        if Self::is_consensus_address_owner(default_permissions, &members) {
832            return None;
833        }
834        Some(Self {
835            default_permissions,
836            members,
837        })
838    }
839
840    pub fn is_consensus_address_owner(
841        default_permissions: ObjectPermissions,
842        members: &BTreeMap<SuiAddress, ObjectPermissions>,
843    ) -> bool {
844        default_permissions == ObjectPermissions::NONE
845            && members.len() == 1
846            && members.values().next() == Some(&ObjectPermissions::ALL)
847    }
848
849    pub fn permissions_for(&self, address: &SuiAddress) -> ObjectPermissions {
850        self.members
851            .get(address)
852            .copied()
853            .unwrap_or(self.default_permissions)
854    }
855}
856
857impl Display for Party {
858    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
859        write!(
860            f,
861            "Party {{ default_permissions: {}, members: {{",
862            self.default_permissions.0
863        )?;
864        let mut first = true;
865        for (address, permissions) in &self.members {
866            if !first {
867                write!(f, ", ")?;
868            }
869            write!(f, "{} => {}", address, permissions.0)?;
870            first = false;
871        }
872        write!(f, "}} }}")
873    }
874}
875
876#[derive(Deserialize, Serialize)]
877struct RawPartySerde {
878    default_permissions: ObjectPermissions,
879    members: Vec<(SuiAddress, ObjectPermissions)>,
880}
881
882impl TryFrom<RawPartySerde> for Party {
883    type Error = &'static str;
884    fn try_from(raw: RawPartySerde) -> Result<Self, Self::Error> {
885        for window in raw.members.windows(2) {
886            match window[0].0.cmp(&window[1].0) {
887                std::cmp::Ordering::Less => continue,
888                std::cmp::Ordering::Equal => return Err("duplicate Party member address"),
889                std::cmp::Ordering::Greater => return Err("Party members must be sorted"),
890            }
891        }
892        let members: BTreeMap<SuiAddress, ObjectPermissions> = raw.members.into_iter().collect();
893        // A Party cannot be equivalent to a ConsensusAddressOwner.
894        // The error message here is left generic for any additional restrictions that may be
895        // added in the future.
896        Self::new(raw.default_permissions, members)
897            .ok_or("invalid Party: violates canonical representation")
898    }
899}
900
901impl From<Party> for RawPartySerde {
902    fn from(p: Party) -> Self {
903        Self {
904            default_permissions: p.default_permissions,
905            members: p.members.into_iter().collect(),
906        }
907    }
908}
909
910#[cfg(feature = "fuzzing")]
911impl proptest::arbitrary::Arbitrary for Party {
912    type Parameters = ();
913    type Strategy = proptest::strategy::BoxedStrategy<Self>;
914    fn arbitrary_with(_: ()) -> Self::Strategy {
915        use proptest::prelude::*;
916        (
917            any::<ObjectPermissions>(),
918            any::<BTreeMap<SuiAddress, ObjectPermissions>>(),
919        )
920            .prop_filter_map(
921                "Party representable as ConsensusAddressOwner",
922                |(default_permissions, members)| Self::new(default_permissions, members),
923            )
924            .boxed()
925    }
926}
927
928#[derive(
929    Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash, JsonSchema, Ord, PartialOrd,
930)]
931#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))]
932pub enum Owner {
933    /// Object is exclusively owned by a single address, and is mutable.
934    AddressOwner(SuiAddress),
935    /// Object is exclusively owned by a single object, and is mutable.
936    /// The object ID is converted to SuiAddress as SuiAddress is universal.
937    ObjectOwner(SuiAddress),
938    /// Object is shared, can be used by any address, and is mutable.
939    Shared {
940        /// The version at which the object became shared
941        initial_shared_version: SequenceNumber,
942    },
943    /// Object is immutable, and hence ownership doesn't matter.
944    Immutable,
945    /// Object is exclusively owned by a single address and sequenced via consensus.
946    ConsensusAddressOwner {
947        /// The version at which the object most recently became a consensus object.
948        /// This serves the same function as `initial_shared_version`, except it may change
949        /// if the object's Owner type changes.
950        start_version: SequenceNumber,
951        // The owner of the object.
952        owner: SuiAddress,
953    },
954    /// Object is sequenced via consensus with per-address permissions.
955    /// Each address can be granted a subset of [`ObjectPermission`] flags.
956    /// Addresses not explicitly listed fall back to the default permissions.
957    Party {
958        /// The version at which the object most recently became a party object.
959        /// Serves the same function as `initial_shared_version`, except it may change
960        /// if the object's Owner type changes.
961        start_version: SequenceNumber,
962        /// The permission map for this object.
963        permissions: Party,
964    },
965}
966
967impl Owner {
968    // NOTE: only return address of AddressOwner, otherwise return error,
969    // ObjectOwner's address is converted from object id, thus we will skip it.
970    pub fn get_address_owner_address(&self) -> SuiResult<SuiAddress> {
971        match self {
972            Self::AddressOwner(address) => Ok(*address),
973            Self::Shared { .. }
974            | Self::Immutable
975            | Self::ObjectOwner(_)
976            | Self::ConsensusAddressOwner { .. }
977            | Self::Party { .. } => Err(SuiErrorKind::UnexpectedOwnerType.into()),
978        }
979    }
980
981    // NOTE: this function will return address of AddressOwner, ConsensusAddressOwner, and
982    // ObjectOwner. The address of ObjectOwner is converted from object ID, even though the
983    // type is SuiAddress.
984    pub fn get_owner_address(&self) -> SuiResult<SuiAddress> {
985        match self {
986            Self::AddressOwner(address)
987            | Self::ObjectOwner(address)
988            | Self::ConsensusAddressOwner { owner: address, .. } => Ok(*address),
989            Self::Shared { .. } | Self::Immutable | Self::Party { .. } => {
990                Err(SuiErrorKind::UnexpectedOwnerType.into())
991            }
992        }
993    }
994
995    // Returns initial_shared_version for Shared objects, and start_version
996    // for ConsensusAddressOwner and Party objects.
997    pub fn start_version(&self) -> Option<SequenceNumber> {
998        match self {
999            Self::Shared {
1000                initial_shared_version,
1001            } => Some(*initial_shared_version),
1002            Self::ConsensusAddressOwner { start_version, .. }
1003            | Self::Party { start_version, .. } => Some(*start_version),
1004            Self::Immutable | Self::AddressOwner(_) | Self::ObjectOwner(_) => None,
1005        }
1006    }
1007
1008    pub fn is_immutable(&self) -> bool {
1009        matches!(self, Owner::Immutable)
1010    }
1011
1012    pub fn is_address_owned(&self) -> bool {
1013        matches!(self, Owner::AddressOwner(_))
1014    }
1015
1016    pub fn is_child_object(&self) -> bool {
1017        matches!(self, Owner::ObjectOwner(_))
1018    }
1019
1020    pub fn is_shared(&self) -> bool {
1021        matches!(self, Owner::Shared { .. })
1022    }
1023
1024    pub fn is_consensus(&self) -> bool {
1025        matches!(
1026            self,
1027            Owner::Shared { .. } | Owner::ConsensusAddressOwner { .. } | Owner::Party { .. }
1028        )
1029    }
1030}
1031
1032impl PartialEq<ObjectID> for Owner {
1033    fn eq(&self, other: &ObjectID) -> bool {
1034        let other_id: SuiAddress = (*other).into();
1035        match self {
1036            Self::ObjectOwner(id) => id == &other_id,
1037            Self::AddressOwner(_)
1038            | Self::Shared { .. }
1039            | Self::Immutable
1040            | Self::ConsensusAddressOwner { .. }
1041            | Self::Party { .. } => false,
1042        }
1043    }
1044}
1045
1046impl Display for Owner {
1047    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1048        match self {
1049            Self::AddressOwner(address) => {
1050                write!(f, "Account Address ( {} )", address)
1051            }
1052            Self::ObjectOwner(address) => {
1053                write!(f, "Object ID: ( {} )", address)
1054            }
1055            Self::Immutable => {
1056                write!(f, "Immutable")
1057            }
1058            Self::Shared {
1059                initial_shared_version,
1060            } => {
1061                write!(f, "Shared( {} )", initial_shared_version.value())
1062            }
1063            Self::ConsensusAddressOwner {
1064                start_version,
1065                owner,
1066            } => {
1067                write!(
1068                    f,
1069                    "ConsensusAddressOwner( {}, {} )",
1070                    start_version.value(),
1071                    owner
1072                )
1073            }
1074            Self::Party {
1075                start_version,
1076                permissions,
1077            } => {
1078                write!(f, "Party( {}, {} )", start_version.value(), permissions)
1079            }
1080        }
1081    }
1082}
1083
1084#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)]
1085#[serde(rename = "Object")]
1086pub struct ObjectInner {
1087    /// The meat of the object
1088    pub data: Data,
1089    /// The owner that unlocks this object
1090    pub owner: Owner,
1091    /// The digest of the transaction that created or last mutated this object
1092    pub previous_transaction: TransactionDigest,
1093    /// The amount of SUI we would rebate if this object gets deleted.
1094    /// This number is re-calculated each time the object is mutated based on
1095    /// the present storage gas price.
1096    pub storage_rebate: u64,
1097}
1098
1099#[derive(Eq, PartialEq, Clone, Deserialize, Serialize, Hash)]
1100#[serde(from = "ObjectInner")]
1101pub struct Object(Arc<ObjectInner>);
1102
1103fn is_object_debug_verbose() -> bool {
1104    static SUI_OBJECT_DEBUG_VERBOSE: Lazy<bool> =
1105        Lazy::new(|| std::env::var("SUI_OBJECT_DEBUG_VERBOSE").is_ok());
1106    *SUI_OBJECT_DEBUG_VERBOSE
1107}
1108
1109impl std::fmt::Debug for Object {
1110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1111        if is_object_debug_verbose() {
1112            // Just call debug on ObjectInner for verbose debugging.
1113            (*self.0).fmt(f)
1114        } else {
1115            f.debug_struct("Object")
1116                .field("id", &self.id())
1117                .field("version", &self.version())
1118                .field("owner", &self.owner())
1119                .finish()
1120        }
1121    }
1122}
1123
1124impl From<ObjectInner> for Object {
1125    fn from(inner: ObjectInner) -> Self {
1126        Self(Arc::new(inner))
1127    }
1128}
1129
1130impl Object {
1131    pub fn into_inner(self) -> ObjectInner {
1132        match Arc::try_unwrap(self.0) {
1133            Ok(inner) => inner,
1134            Err(inner_arc) => (*inner_arc).clone(),
1135        }
1136    }
1137
1138    pub fn as_inner(&self) -> &ObjectInner {
1139        &self.0
1140    }
1141
1142    pub fn owner(&self) -> &Owner {
1143        &self.0.owner
1144    }
1145
1146    pub fn new_from_genesis(
1147        data: Data,
1148        owner: Owner,
1149        previous_transaction: TransactionDigest,
1150    ) -> Self {
1151        ObjectInner {
1152            data,
1153            owner,
1154            previous_transaction,
1155            storage_rebate: 0,
1156        }
1157        .into()
1158    }
1159
1160    /// Create a new Move object
1161    pub fn new_move(o: MoveObject, owner: Owner, previous_transaction: TransactionDigest) -> Self {
1162        ObjectInner {
1163            data: Data::Move(o),
1164            owner,
1165            previous_transaction,
1166            storage_rebate: 0,
1167        }
1168        .into()
1169    }
1170
1171    pub fn new_package_from_data(data: Data, previous_transaction: TransactionDigest) -> Self {
1172        ObjectInner {
1173            data,
1174            owner: Owner::Immutable,
1175            previous_transaction,
1176            storage_rebate: 0,
1177        }
1178        .into()
1179    }
1180
1181    // Note: this will panic if `modules` is empty
1182    pub fn new_from_package(package: MovePackage, previous_transaction: TransactionDigest) -> Self {
1183        Self::new_package_from_data(Data::Package(package), previous_transaction)
1184    }
1185
1186    pub fn new_package<'p>(
1187        modules: &[CompiledModule],
1188        previous_transaction: TransactionDigest,
1189        protocol_config: &ProtocolConfig,
1190        dependencies: impl IntoIterator<Item = &'p MovePackage>,
1191    ) -> Result<Self, ExecutionError> {
1192        Ok(Self::new_package_from_data(
1193            Data::Package(MovePackage::new_initial(
1194                modules,
1195                protocol_config,
1196                dependencies,
1197            )?),
1198            previous_transaction,
1199        ))
1200    }
1201
1202    pub fn new_upgraded_package<'p>(
1203        previous_package: &MovePackage,
1204        new_package_id: ObjectID,
1205        modules: &[CompiledModule],
1206        previous_transaction: TransactionDigest,
1207        protocol_config: &ProtocolConfig,
1208        dependencies: impl IntoIterator<Item = &'p MovePackage>,
1209    ) -> Result<Self, ExecutionError> {
1210        Ok(Self::new_package_from_data(
1211            Data::Package(previous_package.new_upgraded(
1212                new_package_id,
1213                modules,
1214                protocol_config,
1215                dependencies,
1216            )?),
1217            previous_transaction,
1218        ))
1219    }
1220
1221    pub fn new_package_for_testing(
1222        modules: &[CompiledModule],
1223        previous_transaction: TransactionDigest,
1224        dependencies: impl IntoIterator<Item = MovePackage>,
1225    ) -> Result<Self, ExecutionError> {
1226        let dependencies: Vec<_> = dependencies.into_iter().collect();
1227        let config = ProtocolConfig::get_for_max_version_UNSAFE();
1228        Self::new_package(modules, previous_transaction, &config, &dependencies)
1229    }
1230
1231    /// Create a system package which is not subject to size limits. Panics if the object ID is not
1232    /// a known system package.
1233    pub fn new_system_package(
1234        modules: &[CompiledModule],
1235        version: SequenceNumber,
1236        dependencies: Vec<ObjectID>,
1237        previous_transaction: TransactionDigest,
1238    ) -> Self {
1239        let ret = Self::new_package_from_data(
1240            Data::Package(MovePackage::new_system(version, modules, dependencies)),
1241            previous_transaction,
1242        );
1243
1244        #[cfg(not(msim))]
1245        assert!(ret.is_system_package());
1246
1247        ret
1248    }
1249}
1250
1251impl std::ops::Deref for Object {
1252    type Target = ObjectInner;
1253    fn deref(&self) -> &Self::Target {
1254        &self.0
1255    }
1256}
1257
1258impl std::ops::DerefMut for Object {
1259    fn deref_mut(&mut self) -> &mut Self::Target {
1260        Arc::make_mut(&mut self.0)
1261    }
1262}
1263
1264impl ObjectInner {
1265    /// Returns true if the object is a system package.
1266    pub fn is_system_package(&self) -> bool {
1267        self.is_package() && is_system_package(self.id())
1268    }
1269
1270    pub fn is_immutable(&self) -> bool {
1271        self.owner.is_immutable()
1272    }
1273
1274    pub fn is_address_owned(&self) -> bool {
1275        self.owner.is_address_owned()
1276    }
1277
1278    pub fn is_child_object(&self) -> bool {
1279        self.owner.is_child_object()
1280    }
1281
1282    pub fn is_shared(&self) -> bool {
1283        self.owner.is_shared()
1284    }
1285
1286    pub fn is_consensus(&self) -> bool {
1287        self.owner.is_consensus()
1288    }
1289
1290    pub fn get_single_owner(&self) -> Option<SuiAddress> {
1291        self.owner.get_owner_address().ok()
1292    }
1293
1294    // It's a common pattern to retrieve both the owner and object ID
1295    // together, if it's owned by a singler owner.
1296    pub fn get_owner_and_id(&self) -> Option<(Owner, ObjectID)> {
1297        Some((self.owner.clone(), self.id()))
1298    }
1299
1300    /// Return true if this object is a Move package, false if it is a Move value
1301    pub fn is_package(&self) -> bool {
1302        matches!(&self.data, Data::Package(_))
1303    }
1304
1305    pub fn compute_object_reference(&self) -> ObjectRef {
1306        (self.id(), self.version(), self.digest())
1307    }
1308
1309    pub fn compute_full_object_reference(&self) -> FullObjectRef {
1310        FullObjectRef(self.full_id(), self.version(), self.digest())
1311    }
1312
1313    pub fn digest(&self) -> ObjectDigest {
1314        ObjectDigest::new(default_hash(self))
1315    }
1316
1317    pub fn id(&self) -> ObjectID {
1318        use Data::*;
1319
1320        match &self.data {
1321            Move(v) => v.id(),
1322            Package(m) => m.id(),
1323        }
1324    }
1325
1326    pub fn full_id(&self) -> FullObjectID {
1327        let id = self.id();
1328        if let Some(start_version) = self.owner.start_version() {
1329            FullObjectID::Consensus((id, start_version))
1330        } else {
1331            FullObjectID::Fastpath(id)
1332        }
1333    }
1334
1335    pub fn version(&self) -> SequenceNumber {
1336        use Data::*;
1337
1338        match &self.data {
1339            Move(o) => o.version(),
1340            Package(p) => p.version(),
1341        }
1342    }
1343
1344    pub fn type_(&self) -> Option<&MoveObjectType> {
1345        self.data.type_()
1346    }
1347
1348    pub fn struct_tag(&self) -> Option<StructTag> {
1349        self.data.struct_tag()
1350    }
1351
1352    pub fn is_coin(&self) -> bool {
1353        if let Some(move_object) = self.data.try_as_move() {
1354            move_object.type_().is_coin()
1355        } else {
1356            false
1357        }
1358    }
1359
1360    pub fn is_gas_coin(&self) -> bool {
1361        if let Some(move_object) = self.data.try_as_move() {
1362            move_object.type_().is_gas_coin()
1363        } else {
1364            false
1365        }
1366    }
1367
1368    // TODO: use `MoveObj::get_balance_unsafe` instead.
1369    // context: https://github.com/MystenLabs/sui/pull/10679#discussion_r1165877816
1370    pub fn as_coin_maybe(&self) -> Option<Coin> {
1371        if let Some(move_object) = self.data.try_as_move() {
1372            if move_object.type_().is_coin() {
1373                let coin: Coin = bcs::from_bytes(move_object.contents()).ok()?;
1374                Some(coin)
1375            } else {
1376                None
1377            }
1378        } else {
1379            None
1380        }
1381    }
1382
1383    pub fn coin_type_maybe(&self) -> Option<TypeTag> {
1384        if let Some(move_object) = self.data.try_as_move() {
1385            move_object.type_().coin_type_maybe()
1386        } else {
1387            None
1388        }
1389    }
1390
1391    /// Return the `value: u64` field of a `Coin<T>` type.
1392    /// Useful for reading the coin without deserializing the object into a Move value
1393    /// It is the caller's responsibility to check that `self` is a coin--this function
1394    /// may panic or do something unexpected otherwise.
1395    pub fn get_coin_value_unsafe(&self) -> u64 {
1396        self.data.try_as_move().unwrap().get_coin_value_unsafe()
1397    }
1398
1399    /// Approximate size of the object in bytes. This is used for gas metering.
1400    /// This will be slightly different from the serialized size, but
1401    /// we also don't want to serialize the object just to get the size.
1402    /// This approximation should be good enough for gas metering.
1403    pub fn object_size_for_gas_metering(&self) -> usize {
1404        const DEFAULT_OWNER_SIZE: usize = 40;
1405        const TRANSACTION_DIGEST_SIZE: usize = 32;
1406        const STORAGE_REBATE_SIZE: usize = 8;
1407
1408        let meta_data_size = DEFAULT_OWNER_SIZE + TRANSACTION_DIGEST_SIZE + STORAGE_REBATE_SIZE;
1409        let data_size = match &self.data {
1410            Data::Move(m) => m.object_size_for_gas_metering(),
1411            Data::Package(p) => p.object_size_for_gas_metering(),
1412        };
1413        meta_data_size + data_size
1414    }
1415
1416    /// Change the owner of `self` to `new_owner`.
1417    pub fn transfer(&mut self, new_owner: SuiAddress) {
1418        self.owner = Owner::AddressOwner(new_owner);
1419    }
1420
1421    /// Get a `MoveStructLayout` for `self`.
1422    /// The `resolver` value must contain the module that declares `self.type_` and the (transitive)
1423    /// dependencies of `self.type_` in order for this to succeed. Failure will result in an `ObjectSerializationError`
1424    pub fn get_layout(
1425        &self,
1426        resolver: &impl GetModule,
1427    ) -> Result<Option<MoveStructLayout>, SuiError> {
1428        match &self.data {
1429            Data::Move(m) => Ok(Some(m.get_layout(resolver)?)),
1430            Data::Package(_) => Ok(None),
1431        }
1432    }
1433
1434    /// Treat the object type as a Move struct with one type parameter,
1435    /// like this: `S<T>`.
1436    /// Returns the inner parameter type `T`.
1437    pub fn get_move_template_type(&self) -> SuiResult<TypeTag> {
1438        let move_struct = self
1439            .data
1440            .struct_tag()
1441            .ok_or_else(|| SuiErrorKind::TypeError {
1442                error: "Object must be a Move object".to_owned(),
1443            })?;
1444        fp_ensure!(
1445            move_struct.type_params.len() == 1,
1446            SuiErrorKind::TypeError {
1447                error: "Move object struct must have one type parameter".to_owned()
1448            }
1449            .into()
1450        );
1451        // Index access safe due to checks above.
1452        let type_tag = move_struct.type_params[0].clone();
1453        Ok(type_tag)
1454    }
1455
1456    pub fn to_rust<'de, T: Deserialize<'de>>(&'de self) -> Option<T> {
1457        self.data.try_as_move().and_then(|data| data.to_rust())
1458    }
1459}
1460
1461// Testing-related APIs.
1462impl Object {
1463    /// Get the total amount of SUI embedded in `self`, including both Move objects and the storage rebate
1464    pub fn get_total_sui(&self, layout_resolver: &mut dyn LayoutResolver) -> Result<u64, SuiError> {
1465        Ok(self.storage_rebate
1466            + match &self.data {
1467                Data::Move(m) => m.get_total_sui(layout_resolver)?,
1468                Data::Package(_) => 0,
1469            })
1470    }
1471
1472    pub fn immutable_with_id_for_testing(id: ObjectID) -> Self {
1473        let data = Data::Move(MoveObject {
1474            type_: GasCoin::type_().into(),
1475            has_public_transfer: true,
1476            version: OBJECT_START_VERSION,
1477            contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(),
1478        });
1479        ObjectInner {
1480            owner: Owner::Immutable,
1481            data,
1482            previous_transaction: TransactionDigest::genesis_marker(),
1483            storage_rebate: 0,
1484        }
1485        .into()
1486    }
1487
1488    pub fn immutable_for_testing() -> Self {
1489        thread_local! {
1490            static IMMUTABLE_OBJECT_ID: ObjectID = ObjectID::random();
1491        }
1492
1493        Self::immutable_with_id_for_testing(IMMUTABLE_OBJECT_ID.with(|id| *id))
1494    }
1495
1496    /// Make a new random test shared object.
1497    pub fn shared_for_testing() -> Object {
1498        let id = ObjectID::random();
1499        let obj = MoveObject::new_gas_coin(OBJECT_START_VERSION, id, 10);
1500        let owner = Owner::Shared {
1501            initial_shared_version: obj.version(),
1502        };
1503        Object::new_move(obj, owner, TransactionDigest::genesis_marker())
1504    }
1505
1506    pub fn with_id_owner_gas_for_testing(id: ObjectID, owner: SuiAddress, gas: u64) -> Self {
1507        let data = Data::Move(MoveObject {
1508            type_: GasCoin::type_().into(),
1509            has_public_transfer: true,
1510            version: OBJECT_START_VERSION,
1511            contents: GasCoin::new(id, gas).to_bcs_bytes(),
1512        });
1513        ObjectInner {
1514            owner: Owner::AddressOwner(owner),
1515            data,
1516            previous_transaction: TransactionDigest::genesis_marker(),
1517            storage_rebate: 0,
1518        }
1519        .into()
1520    }
1521
1522    pub fn treasury_cap_for_testing(struct_tag: StructTag, treasury_cap: TreasuryCap) -> Self {
1523        let data = Data::Move(MoveObject {
1524            type_: TreasuryCap::type_(struct_tag).into(),
1525            has_public_transfer: true,
1526            version: OBJECT_START_VERSION,
1527            contents: bcs::to_bytes(&treasury_cap).expect("Failed to serialize"),
1528        });
1529        ObjectInner {
1530            owner: Owner::Immutable,
1531            data,
1532            previous_transaction: TransactionDigest::genesis_marker(),
1533            storage_rebate: 0,
1534        }
1535        .into()
1536    }
1537
1538    pub fn coin_metadata_for_testing(struct_tag: StructTag, metadata: CoinMetadata) -> Self {
1539        let data = Data::Move(MoveObject {
1540            type_: CoinMetadata::type_(struct_tag).into(),
1541            has_public_transfer: true,
1542            version: OBJECT_START_VERSION,
1543            contents: bcs::to_bytes(&metadata).expect("Failed to serialize"),
1544        });
1545        ObjectInner {
1546            owner: Owner::Immutable,
1547            data,
1548            previous_transaction: TransactionDigest::genesis_marker(),
1549            storage_rebate: 0,
1550        }
1551        .into()
1552    }
1553
1554    pub fn with_object_owner_for_testing(id: ObjectID, owner: ObjectID) -> Self {
1555        let data = Data::Move(MoveObject {
1556            type_: GasCoin::type_().into(),
1557            has_public_transfer: true,
1558            version: OBJECT_START_VERSION,
1559            contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(),
1560        });
1561        ObjectInner {
1562            owner: Owner::ObjectOwner(owner.into()),
1563            data,
1564            previous_transaction: TransactionDigest::genesis_marker(),
1565            storage_rebate: 0,
1566        }
1567        .into()
1568    }
1569
1570    pub fn with_id_owner_for_testing(id: ObjectID, owner: SuiAddress) -> Self {
1571        // For testing, we provide sufficient gas by default.
1572        Self::with_id_owner_gas_for_testing(id, owner, GAS_VALUE_FOR_TESTING)
1573    }
1574
1575    pub fn with_id_owner_version_for_testing(
1576        id: ObjectID,
1577        version: SequenceNumber,
1578        owner: Owner,
1579    ) -> Self {
1580        let data = Data::Move(MoveObject {
1581            type_: GasCoin::type_().into(),
1582            has_public_transfer: true,
1583            version,
1584            contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(),
1585        });
1586        ObjectInner {
1587            owner,
1588            data,
1589            previous_transaction: TransactionDigest::genesis_marker(),
1590            storage_rebate: 0,
1591        }
1592        .into()
1593    }
1594
1595    pub fn with_owner_for_testing(owner: SuiAddress) -> Self {
1596        Self::with_id_owner_for_testing(ObjectID::random(), owner)
1597    }
1598
1599    /// Generate a new gas coin worth `value` with a random object ID and owner
1600    /// For testing purposes only
1601    pub fn new_gas_with_balance_and_owner_for_testing(value: u64, owner: SuiAddress) -> Self {
1602        let obj = MoveObject::new_gas_coin(OBJECT_START_VERSION, ObjectID::random(), value);
1603        Object::new_move(
1604            obj,
1605            Owner::AddressOwner(owner),
1606            TransactionDigest::genesis_marker(),
1607        )
1608    }
1609
1610    /// Generate a new gas coin object with default balance and random owner.
1611    pub fn new_gas_for_testing() -> Self {
1612        let gas_object_id = ObjectID::random();
1613        let (owner, _) = deterministic_random_account_key();
1614        Object::with_id_owner_for_testing(gas_object_id, owner)
1615    }
1616}
1617
1618/// Make a few test gas objects (all with the same random owner).
1619pub fn generate_test_gas_objects() -> Vec<Object> {
1620    thread_local! {
1621        static GAS_OBJECTS: Vec<Object> = (0..50)
1622            .map(|_| {
1623                let gas_object_id = ObjectID::random();
1624                let (owner, _) = deterministic_random_account_key();
1625                Object::with_id_owner_for_testing(gas_object_id, owner)
1626            })
1627            .collect();
1628    }
1629
1630    GAS_OBJECTS.with(|v| v.clone())
1631}
1632
1633#[allow(clippy::large_enum_variant)]
1634#[derive(Serialize, Deserialize, Debug)]
1635#[serde(tag = "status", content = "details")]
1636pub enum ObjectRead {
1637    NotExists(ObjectID),
1638    Exists(ObjectRef, Object, Option<MoveStructLayout>),
1639    Deleted(ObjectRef),
1640}
1641
1642impl ObjectRead {
1643    /// Returns the object value if there is any, otherwise an Err if
1644    /// the object does not exist or is deleted.
1645    pub fn into_object(self) -> UserInputResult<Object> {
1646        match self {
1647            Self::Deleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: oref }),
1648            Self::NotExists(id) => Err(UserInputError::ObjectNotFound {
1649                object_id: id,
1650                version: None,
1651            }),
1652            Self::Exists(_, o, _) => Ok(o),
1653        }
1654    }
1655
1656    pub fn object(&self) -> UserInputResult<&Object> {
1657        match self {
1658            Self::Deleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: *oref }),
1659            Self::NotExists(id) => Err(UserInputError::ObjectNotFound {
1660                object_id: *id,
1661                version: None,
1662            }),
1663            Self::Exists(_, o, _) => Ok(o),
1664        }
1665    }
1666
1667    pub fn object_id(&self) -> ObjectID {
1668        match self {
1669            Self::Deleted(oref) => oref.0,
1670            Self::NotExists(id) => *id,
1671            Self::Exists(oref, _, _) => oref.0,
1672        }
1673    }
1674}
1675
1676impl Display for ObjectRead {
1677    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1678        match self {
1679            Self::Deleted(oref) => {
1680                write!(f, "ObjectRead::Deleted ({:?})", oref)
1681            }
1682            Self::NotExists(id) => {
1683                write!(f, "ObjectRead::NotExists ({:?})", id)
1684            }
1685            Self::Exists(oref, _, _) => {
1686                write!(f, "ObjectRead::Exists ({:?})", oref)
1687            }
1688        }
1689    }
1690}
1691
1692#[allow(clippy::large_enum_variant)]
1693#[derive(Serialize, Deserialize, Debug)]
1694#[serde(tag = "status", content = "details")]
1695pub enum PastObjectRead {
1696    /// The object does not exist
1697    ObjectNotExists(ObjectID),
1698    /// The object is found to be deleted with this version
1699    ObjectDeleted(ObjectRef),
1700    /// The object exists and is found with this version
1701    VersionFound(ObjectRef, Object, Option<MoveStructLayout>),
1702    /// The object exists but not found with this version
1703    VersionNotFound(ObjectID, SequenceNumber),
1704    /// The asked object version is higher than the latest
1705    VersionTooHigh {
1706        object_id: ObjectID,
1707        asked_version: SequenceNumber,
1708        latest_version: SequenceNumber,
1709    },
1710}
1711
1712impl PastObjectRead {
1713    /// Returns the object value if there is any, otherwise an Err
1714    pub fn into_object(self) -> UserInputResult<Object> {
1715        match self {
1716            Self::ObjectDeleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: oref }),
1717            Self::ObjectNotExists(id) => Err(UserInputError::ObjectNotFound {
1718                object_id: id,
1719                version: None,
1720            }),
1721            Self::VersionFound(_, o, _) => Ok(o),
1722            Self::VersionNotFound(object_id, version) => Err(UserInputError::ObjectNotFound {
1723                object_id,
1724                version: Some(version),
1725            }),
1726            Self::VersionTooHigh {
1727                object_id,
1728                asked_version,
1729                latest_version,
1730            } => Err(UserInputError::ObjectSequenceNumberTooHigh {
1731                object_id,
1732                asked_version,
1733                latest_version,
1734            }),
1735        }
1736    }
1737}
1738
1739impl Display for PastObjectRead {
1740    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1741        match self {
1742            Self::ObjectDeleted(oref) => {
1743                write!(f, "PastObjectRead::ObjectDeleted ({:?})", oref)
1744            }
1745            Self::ObjectNotExists(id) => {
1746                write!(f, "PastObjectRead::ObjectNotExists ({:?})", id)
1747            }
1748            Self::VersionFound(oref, _, _) => {
1749                write!(f, "PastObjectRead::VersionFound ({:?})", oref)
1750            }
1751            Self::VersionNotFound(object_id, version) => {
1752                write!(
1753                    f,
1754                    "PastObjectRead::VersionNotFound ({:?}, asked sequence number {:?})",
1755                    object_id, version
1756                )
1757            }
1758            Self::VersionTooHigh {
1759                object_id,
1760                asked_version,
1761                latest_version,
1762            } => {
1763                write!(
1764                    f,
1765                    "PastObjectRead::VersionTooHigh ({:?}, asked sequence number {:?}, latest sequence number {:?})",
1766                    object_id, asked_version, latest_version
1767                )
1768            }
1769        }
1770    }
1771}
1772
1773#[cfg(test)]
1774mod tests {
1775    use crate::object::{OBJECT_START_VERSION, Object, Owner};
1776    use crate::{
1777        base_types::{ObjectID, SuiAddress, TransactionDigest},
1778        gas_coin::GasCoin,
1779    };
1780
1781    // Ensure that object digest computation and bcs serialized format are not inadvertently changed.
1782    #[test]
1783    fn test_object_digest_and_serialized_format() {
1784        let g =
1785            GasCoin::new_for_testing_with_id(ObjectID::ZERO, 123).to_object(OBJECT_START_VERSION);
1786        let o = Object::new_move(
1787            g,
1788            Owner::AddressOwner(SuiAddress::ZERO),
1789            TransactionDigest::ZERO,
1790        );
1791        let bytes = bcs::to_bytes(&o).unwrap();
1792
1793        assert_eq!(
1794            bytes,
1795            [
1796                0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1797                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1798                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1799                0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1800                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1801            ]
1802        );
1803
1804        let objref = format!("{:?}", o.compute_object_reference());
1805        assert_eq!(
1806            objref,
1807            "(0x0000000000000000000000000000000000000000000000000000000000000000, SequenceNumber(1), o#59tZq65HVqZjUyNtD7BCGLTD87N5cpayYwEFrtwR4aMz)"
1808        );
1809    }
1810
1811    #[test]
1812    fn test_get_coin_value_unsafe() {
1813        fn test_for_value(v: u64) {
1814            let g = GasCoin::new_for_testing(v).to_object(OBJECT_START_VERSION);
1815            assert_eq!(g.get_coin_value_unsafe(), v);
1816            assert_eq!(GasCoin::try_from(&g).unwrap().value(), v);
1817        }
1818
1819        test_for_value(0);
1820        test_for_value(1);
1821        test_for_value(8);
1822        test_for_value(9);
1823        test_for_value(u8::MAX as u64);
1824        test_for_value(u8::MAX as u64 + 1);
1825        test_for_value(u16::MAX as u64);
1826        test_for_value(u16::MAX as u64 + 1);
1827        test_for_value(u32::MAX as u64);
1828        test_for_value(u32::MAX as u64 + 1);
1829        test_for_value(u64::MAX);
1830    }
1831
1832    #[test]
1833    fn test_set_coin_value_unsafe() {
1834        fn test_for_value(v: u64) {
1835            let mut g = GasCoin::new_for_testing(u64::MAX).to_object(OBJECT_START_VERSION);
1836            g.set_coin_value_unsafe(v);
1837            assert_eq!(g.get_coin_value_unsafe(), v);
1838            assert_eq!(GasCoin::try_from(&g).unwrap().value(), v);
1839            assert_eq!(g.version(), OBJECT_START_VERSION);
1840            assert_eq!(g.contents().len(), 40);
1841        }
1842
1843        test_for_value(0);
1844        test_for_value(1);
1845        test_for_value(8);
1846        test_for_value(9);
1847        test_for_value(u8::MAX as u64);
1848        test_for_value(u8::MAX as u64 + 1);
1849        test_for_value(u16::MAX as u64);
1850        test_for_value(u16::MAX as u64 + 1);
1851        test_for_value(u32::MAX as u64);
1852        test_for_value(u32::MAX as u64 + 1);
1853        test_for_value(u64::MAX);
1854    }
1855
1856    #[test]
1857    fn test_owner_variant_sizes() {
1858        use super::{Party, SequenceNumber};
1859
1860        // AddressOwner / ObjectOwner
1861        assert_eq!(std::mem::size_of::<SuiAddress>(), 32);
1862        // Shared
1863        assert_eq!(std::mem::size_of::<SequenceNumber>(), 8);
1864        // ConsensusAddressOwner
1865        assert_eq!(std::mem::size_of::<(SequenceNumber, SuiAddress)>(), 40);
1866        // Party
1867        assert_eq!(std::mem::size_of::<(SequenceNumber, Party)>(), 40);
1868
1869        // largest variant (40) + tag and alignment
1870        assert_eq!(std::mem::size_of::<Owner>(), 48);
1871    }
1872}