1use 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 type_: MoveObjectType,
58 has_public_transfer: bool,
61 version: SequenceNumber,
64 #[serde_as(as = "Bytes")]
66 contents: Vec<u8>,
67}
68
69pub const ID_END_INDEX: usize = ObjectID::LENGTH;
71
72impl MoveObject {
73 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 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 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 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 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 pub fn get_coin_value_unsafe(&self) -> u64 {
201 debug_assert!(self.type_.is_coin());
202 debug_assert!(self.contents.len() == 40);
204
205 u64::from_le_bytes(<[u8; 8]>::try_from(&self.contents[ID_END_INDEX..]).unwrap())
207 }
208
209 pub fn set_coin_value_unsafe(&mut self, value: u64) {
214 debug_assert!(self.type_.is_coin());
215 debug_assert!(self.contents.len() == 40);
217
218 self.contents.splice(ID_END_INDEX.., value.to_le_bytes());
219 }
220
221 pub fn set_clock_timestamp_ms_unsafe(&mut self, timestamp_ms: u64) {
225 assert!(self.is_clock());
226 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 #[cfg(test)]
261 pub fn type_specific_contents(&self) -> &[u8] {
262 &self.contents[ID_END_INDEX..]
263 }
264
265 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 #[cfg(debug_assertions)]
296 debug_assert_eq!(self.id(), old_id);
297
298 Ok(())
299 }
300
301 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 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 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 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 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 self.contents.len() + serialized_type_tag_size + 1 + 8
384 }
385
386 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 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 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 Move(MoveObject),
427 Package(MovePackage),
429 }
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#[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#[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 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 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 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 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 pub fn can_write(&self) -> bool {
656 self.can(ObjectPermission::Write)
657 }
658
659 pub fn can_delete(&self) -> bool {
662 self.can(ObjectPermission::Delete)
663 }
664
665 pub fn can_internal_transfer(&self) -> bool {
667 self.can(ObjectPermission::InternalTransfer)
668 }
669
670 pub fn can_public_transfer(&self) -> bool {
672 self.can(ObjectPermission::PublicTransfer)
673 }
674
675 pub fn can_wrap(&self) -> bool {
679 self.can(ObjectPermission::Wrap)
680 }
681
682 pub fn can_use_mutably(&self) -> bool {
685 self.can(ObjectPermission::MutableUsage)
686 }
687
688 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 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#[derive(
815 Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash, JsonSchema, Ord, PartialOrd,
816)]
817#[serde(try_from = "RawPartySerde", into = "RawPartySerde")]
818pub struct Party {
819 default_permissions: ObjectPermissions,
821 members: BTreeMap<SuiAddress, ObjectPermissions>,
823}
824
825impl Party {
826 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 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 AddressOwner(SuiAddress),
935 ObjectOwner(SuiAddress),
938 Shared {
940 initial_shared_version: SequenceNumber,
942 },
943 Immutable,
945 ConsensusAddressOwner {
947 start_version: SequenceNumber,
951 owner: SuiAddress,
953 },
954 Party {
958 start_version: SequenceNumber,
962 permissions: Party,
964 },
965}
966
967impl Owner {
968 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 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 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 pub data: Data,
1089 pub owner: Owner,
1091 pub previous_transaction: TransactionDigest,
1093 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 (*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 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 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 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 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 pub fn get_owner_and_id(&self) -> Option<(Owner, ObjectID)> {
1297 Some((self.owner.clone(), self.id()))
1298 }
1299
1300 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 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 pub fn get_coin_value_unsafe(&self) -> u64 {
1396 self.data.try_as_move().unwrap().get_coin_value_unsafe()
1397 }
1398
1399 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 pub fn transfer(&mut self, new_owner: SuiAddress) {
1418 self.owner = Owner::AddressOwner(new_owner);
1419 }
1420
1421 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 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 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
1461impl Object {
1463 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 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 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 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 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
1618pub 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 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 ObjectNotExists(ObjectID),
1698 ObjectDeleted(ObjectRef),
1700 VersionFound(ObjectRef, Object, Option<MoveStructLayout>),
1702 VersionNotFound(ObjectID, SequenceNumber),
1704 VersionTooHigh {
1706 object_id: ObjectID,
1707 asked_version: SequenceNumber,
1708 latest_version: SequenceNumber,
1709 },
1710}
1711
1712impl PastObjectRead {
1713 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 #[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 assert_eq!(std::mem::size_of::<SuiAddress>(), 32);
1862 assert_eq!(std::mem::size_of::<SequenceNumber>(), 8);
1864 assert_eq!(std::mem::size_of::<(SequenceNumber, SuiAddress)>(), 40);
1866 assert_eq!(std::mem::size_of::<(SequenceNumber, Party)>(), 40);
1868
1869 assert_eq!(std::mem::size_of::<Owner>(), 48);
1871 }
1872}