sui_types/storage/
mod.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4pub mod error;
5mod object_store_trait;
6mod read_store;
7mod shared_in_memory_store;
8mod write_store;
9
10use crate::base_types::{
11    ConsensusObjectSequenceKey, FullObjectID, FullObjectRef, SuiAddress, TransactionDigest,
12    VersionNumber,
13};
14use crate::committee::EpochId;
15use crate::effects::{TransactionEffects, TransactionEffectsAPI};
16use crate::error::{ExecutionError, SuiError, SuiErrorKind};
17use crate::execution::{DynamicallyLoadedObjectMetadata, ExecutionResults};
18use crate::full_checkpoint_content::ObjectSet;
19use crate::message_envelope::Message;
20use crate::move_package::MovePackage;
21use crate::storage::error::Error as StorageError;
22use crate::transaction::TransactionData;
23use crate::transaction::{SenderSignedData, TransactionDataAPI};
24use crate::{
25    base_types::{ObjectID, ObjectRef, SequenceNumber},
26    error::SuiResult,
27    object::Object,
28};
29use itertools::Itertools;
30use move_binary_format::CompiledModule;
31use move_core_types::language_storage::{ModuleId, TypeTag};
32use move_core_types::resolver::SerializedPackage;
33pub use object_store_trait::ObjectStore;
34pub use read_store::BalanceInfo;
35pub use read_store::BalanceIterator;
36pub use read_store::CoinInfo;
37pub use read_store::DynamicFieldIndexInfo;
38pub use read_store::DynamicFieldIteratorItem;
39pub use read_store::DynamicFieldKey;
40pub use read_store::EpochInfo;
41pub use read_store::LedgerBitmapBucket;
42pub use read_store::LedgerBitmapBucketIterator;
43pub use read_store::LedgerTxSeqDigest;
44pub use read_store::LedgerTxSeqDigestIterator;
45pub use read_store::OwnedObjectInfo;
46pub use read_store::ReadStore;
47pub use read_store::RpcIndexes;
48pub use read_store::RpcStateReader;
49pub use read_store::TransactionInfo;
50use serde::{Deserialize, Serialize};
51use serde_with::serde_as;
52pub use shared_in_memory_store::SharedInMemoryStore;
53pub use shared_in_memory_store::SingleCheckpointSharedInMemoryStore;
54use std::collections::{BTreeMap, BTreeSet};
55use std::fmt::{Display, Formatter};
56use std::sync::Arc;
57pub use write_store::WriteStore;
58
59/// A potential input to a transaction.
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
61pub enum InputKey {
62    VersionedObject {
63        id: FullObjectID,
64        version: SequenceNumber,
65    },
66    Package {
67        id: ObjectID,
68    },
69}
70
71impl InputKey {
72    pub fn id(&self) -> FullObjectID {
73        match self {
74            InputKey::VersionedObject { id, .. } => *id,
75            InputKey::Package { id } => FullObjectID::Fastpath(*id),
76        }
77    }
78
79    pub fn version(&self) -> Option<SequenceNumber> {
80        match self {
81            InputKey::VersionedObject { version, .. } => Some(*version),
82            InputKey::Package { .. } => None,
83        }
84    }
85
86    pub fn is_cancelled(&self) -> bool {
87        match self {
88            InputKey::VersionedObject { version, .. } => version.is_cancelled(),
89            InputKey::Package { .. } => false,
90        }
91    }
92}
93
94impl From<&Object> for InputKey {
95    fn from(obj: &Object) -> Self {
96        if obj.is_package() {
97            InputKey::Package { id: obj.id() }
98        } else {
99            InputKey::VersionedObject {
100                id: obj.full_id(),
101                version: obj.version(),
102            }
103        }
104    }
105}
106
107#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
108pub enum WriteKind {
109    /// The object was in storage already but has been modified
110    Mutate,
111    /// The object was created in this transaction
112    Create,
113    /// The object was previously wrapped in another object, but has been restored to storage
114    Unwrap,
115}
116
117#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
118pub enum DeleteKind {
119    /// An object is provided in the call input, and gets deleted.
120    Normal,
121    /// An object is not provided in the call input, but gets unwrapped
122    /// from another object, and then gets deleted.
123    UnwrapThenDelete,
124    /// An object is provided in the call input, and gets wrapped into another object.
125    Wrap,
126}
127
128#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
129pub enum MarkerValue {
130    /// An object was received at the given version in the transaction and is no longer able
131    /// to be received at that version in subequent transactions.
132    Received,
133    /// A fastpath object was deleted, wrapped, or transferred to consensus at the given
134    /// version, and is no longer able to be accessed or used in subsequent transactions via
135    /// fastpath unless/until it is returned to fastpath.
136    FastpathStreamEnded,
137    /// A consensus object was deleted or removed from consensus by the transaction and is no longer
138    /// able to be accessed or used in subsequent transactions with the same initial shared version.
139    ConsensusStreamEnded(TransactionDigest),
140}
141
142/// DeleteKind together with the old sequence number prior to the deletion, if available.
143/// For normal deletion and wrap, we always will consult the object store to obtain the old sequence number.
144/// For UnwrapThenDelete however, in the old protocol where simplified_unwrap_then_delete is false,
145/// we will consult the object store to obtain the old sequence number, which latter will be put in
146/// modified_at_versions; in the new protocol where simplified_unwrap_then_delete is true,
147/// we will not consult the object store, and hence won't have the old sequence number.
148#[derive(Debug)]
149pub enum DeleteKindWithOldVersion {
150    Normal(SequenceNumber),
151    // This variant will be deprecated when we turn on simplified_unwrap_then_delete.
152    UnwrapThenDeleteDEPRECATED(SequenceNumber),
153    UnwrapThenDelete,
154    Wrap(SequenceNumber),
155}
156
157impl DeleteKindWithOldVersion {
158    pub fn old_version(&self) -> Option<SequenceNumber> {
159        match self {
160            DeleteKindWithOldVersion::Normal(version)
161            | DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(version)
162            | DeleteKindWithOldVersion::Wrap(version) => Some(*version),
163            DeleteKindWithOldVersion::UnwrapThenDelete => None,
164        }
165    }
166
167    pub fn to_delete_kind(&self) -> DeleteKind {
168        match self {
169            DeleteKindWithOldVersion::Normal(_) => DeleteKind::Normal,
170            DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(_)
171            | DeleteKindWithOldVersion::UnwrapThenDelete => DeleteKind::UnwrapThenDelete,
172            DeleteKindWithOldVersion::Wrap(_) => DeleteKind::Wrap,
173        }
174    }
175}
176
177#[derive(Debug)]
178pub enum ObjectChange {
179    Write(Object, WriteKind),
180    // DeleteKind together with the old sequence number prior to the deletion, if available.
181    Delete(DeleteKindWithOldVersion),
182}
183
184pub trait StorageView: Storage + ParentSync + ChildObjectResolver {}
185impl<T: Storage + ParentSync + ChildObjectResolver> StorageView for T {}
186
187/// An abstraction of the (possibly distributed) store for objects. This
188/// API only allows for the retrieval of objects, not any state changes
189pub trait ChildObjectResolver {
190    /// `child` must have an `ObjectOwner` ownership equal to `owner`.
191    fn read_child_object(
192        &self,
193        parent: &ObjectID,
194        child: &ObjectID,
195        child_version_upper_bound: SequenceNumber,
196    ) -> SuiResult<Option<Object>>;
197
198    /// `receiving_object_id` must have an `AddressOwner` ownership equal to `owner`.
199    /// `get_object_received_at_version` must be the exact version at which the object will be received,
200    /// and it cannot have been previously received at that version. NB: An object not existing at
201    /// that version, and not having valid access to the object will be treated exactly the same
202    /// and `Ok(None)` must be returned.
203    fn get_object_received_at_version(
204        &self,
205        owner: &ObjectID,
206        receiving_object_id: &ObjectID,
207        receive_object_at_version: SequenceNumber,
208        epoch_id: EpochId,
209    ) -> SuiResult<Option<Object>>;
210}
211
212pub struct DenyListResult {
213    /// Ok if all regulated coin owners are allowed.
214    /// Err if any regulated coin owner is denied (returning the error for first one denied).
215    pub result: Result<(), ExecutionError>,
216    /// The number of non-gas-coin owners in the transaction results
217    pub num_non_gas_coin_owners: u64,
218}
219
220/// An abstraction of the (possibly distributed) store for objects, and (soon) events and transactions
221pub trait Storage {
222    fn reset(&mut self);
223
224    fn read_object(&self, id: &ObjectID) -> Option<&Object>;
225
226    fn record_execution_results(&mut self, results: ExecutionResults)
227    -> Result<(), ExecutionError>;
228
229    fn save_loaded_runtime_objects(
230        &mut self,
231        loaded_runtime_objects: BTreeMap<ObjectID, DynamicallyLoadedObjectMetadata>,
232    );
233
234    fn save_wrapped_object_containers(
235        &mut self,
236        wrapped_object_containers: BTreeMap<ObjectID, ObjectID>,
237    );
238
239    /// Given the set of all coin types and owners that are receiving the coins during execution,
240    /// Check coin denylist v2, and return the number of non-gas-coin owners.
241    fn check_coin_deny_list(
242        &self,
243        receiving_funds_type_and_owners: BTreeMap<TypeTag, BTreeSet<SuiAddress>>,
244    ) -> DenyListResult;
245
246    fn record_generated_object_ids(&mut self, generated_ids: BTreeSet<ObjectID>);
247}
248
249pub type PackageFetchResults<Package> = Result<Vec<Package>, Vec<ObjectID>>;
250
251#[derive(Clone, Debug)]
252pub struct PackageObject {
253    package_object: Object,
254}
255
256impl PackageObject {
257    pub fn new(package_object: Object) -> Self {
258        assert!(package_object.is_package());
259        Self { package_object }
260    }
261
262    pub fn object(&self) -> &Object {
263        &self.package_object
264    }
265
266    pub fn move_package(&self) -> &MovePackage {
267        self.package_object.data.try_as_package().unwrap()
268    }
269}
270
271impl From<PackageObject> for Object {
272    fn from(package_object_arc: PackageObject) -> Self {
273        package_object_arc.package_object
274    }
275}
276
277pub trait BackingPackageStore {
278    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>>;
279}
280
281impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Box<S> {
282    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
283        BackingPackageStore::get_package_object(self.as_ref(), package_id)
284    }
285}
286
287impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Arc<S> {
288    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
289        BackingPackageStore::get_package_object(self.as_ref(), package_id)
290    }
291}
292
293impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &S {
294    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
295        BackingPackageStore::get_package_object(*self, package_id)
296    }
297}
298
299impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &mut S {
300    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
301        BackingPackageStore::get_package_object(*self, package_id)
302    }
303}
304
305/// A BackingPackageStore that overlays objects on top of a backing store.
306/// This allows resolving packages from a set of objects (e.g., output objects from a transaction)
307/// before falling back to the backing store.
308pub struct OverlayBackingPackageStore<'a, S> {
309    overlay: &'a ObjectSet,
310    backing: S,
311}
312
313impl<'a, S> OverlayBackingPackageStore<'a, S> {
314    pub fn new(overlay: &'a ObjectSet, backing: S) -> Self {
315        Self { overlay, backing }
316    }
317}
318
319impl<S: BackingPackageStore> BackingPackageStore for OverlayBackingPackageStore<'_, S> {
320    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
321        // First check the overlay for the object
322        for obj in self.overlay.iter() {
323            if &obj.id() == package_id {
324                // Found in overlay - check if it's a package
325                fp_ensure!(
326                    obj.is_package(),
327                    SuiErrorKind::BadObjectType {
328                        error: format!("Package expected, Move object found: {package_id}"),
329                    }
330                    .into()
331                );
332                return Ok(Some(PackageObject::new(obj.clone())));
333            }
334        }
335        // Not in overlay, fall back to the backing store
336        self.backing.get_package_object(package_id)
337    }
338}
339
340pub fn load_package_object_from_object_store(
341    store: &impl ObjectStore,
342    package_id: &ObjectID,
343) -> SuiResult<Option<PackageObject>> {
344    let package = store.get_object(package_id);
345    if let Some(obj) = &package {
346        fp_ensure!(
347            obj.is_package(),
348            SuiErrorKind::BadObjectType {
349                error: format!("Package expected, Move object found: {package_id}"),
350            }
351            .into()
352        );
353    }
354    Ok(package.map(PackageObject::new))
355}
356
357/// Returns Ok(<package object for each package id in `package_ids`>) if all package IDs in
358/// `package_id` were found. If any package in `package_ids` was not found it returns a list
359/// of any package ids that are unable to be found>).
360pub fn get_package_objects<'a>(
361    store: &impl BackingPackageStore,
362    package_ids: impl IntoIterator<Item = &'a ObjectID>,
363) -> SuiResult<PackageFetchResults<PackageObject>> {
364    let packages: Vec<Result<_, _>> = package_ids
365        .into_iter()
366        .map(|id| match store.get_package_object(id) {
367            Ok(None) => Ok(Err(*id)),
368            Ok(Some(o)) => Ok(Ok(o)),
369            Err(x) => Err(x),
370        })
371        .collect::<SuiResult<_>>()?;
372
373    let (fetched, failed_to_fetch): (Vec<_>, Vec<_>) = packages.into_iter().partition_result();
374    if !failed_to_fetch.is_empty() {
375        Ok(Err(failed_to_fetch))
376    } else {
377        Ok(Ok(fetched))
378    }
379}
380
381pub fn get_module(
382    store: impl BackingPackageStore,
383    module_id: &ModuleId,
384) -> Result<Option<Vec<u8>>, SuiError> {
385    Ok(store
386        .get_package_object(&ObjectID::from(*module_id.address()))?
387        .and_then(|package| {
388            package
389                .move_package()
390                .serialized_module_map()
391                .get(module_id.name().as_str())
392                .cloned()
393        }))
394}
395
396pub fn get_package(
397    store: impl BackingPackageStore,
398    id: &ObjectID,
399) -> SuiResult<Option<SerializedPackage>> {
400    store
401        .get_package_object(id)?
402        .map(|package| package.move_package().into_serialized_move_package())
403        .transpose()
404}
405
406pub fn get_module_by_id<S: BackingPackageStore>(
407    store: &S,
408    id: &ModuleId,
409) -> anyhow::Result<Option<CompiledModule>, SuiError> {
410    Ok(get_module(store, id)?
411        .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap()))
412}
413
414/// A `BackingPackageStore` that resolves packages from a backing store, but also includes any
415/// packages that were published in the current transaction execution. This can be used to resolve
416/// Move modules right after transaction execution, but newly published packages have not yet been
417/// committed to the backing store on a fullnode.
418pub struct PostExecutionPackageResolver {
419    backing_store: Arc<dyn BackingPackageStore>,
420    new_packages: BTreeMap<ObjectID, PackageObject>,
421}
422
423impl PostExecutionPackageResolver {
424    pub fn new(
425        backing_store: Arc<dyn BackingPackageStore>,
426        output_objects: &Option<Vec<Object>>,
427    ) -> Self {
428        let new_packages = output_objects
429            .iter()
430            .flatten()
431            .filter_map(|o| {
432                if o.is_package() {
433                    Some((o.id(), PackageObject::new(o.clone())))
434                } else {
435                    None
436                }
437            })
438            .collect();
439        Self {
440            backing_store,
441            new_packages,
442        }
443    }
444}
445
446impl BackingPackageStore for PostExecutionPackageResolver {
447    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
448        if let Some(package) = self.new_packages.get(package_id) {
449            Ok(Some(package.clone()))
450        } else {
451            self.backing_store.get_package_object(package_id)
452        }
453    }
454}
455
456pub trait ParentSync {
457    /// This function is only called by older protocol versions.
458    /// It creates an explicit dependency to tombstones, which is not desired.
459    fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef>;
460}
461
462impl<S: ParentSync> ParentSync for std::sync::Arc<S> {
463    fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
464        ParentSync::get_latest_parent_entry_ref_deprecated(self.as_ref(), object_id)
465    }
466}
467
468impl<S: ParentSync> ParentSync for &S {
469    fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
470        ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id)
471    }
472}
473
474impl<S: ParentSync> ParentSync for &mut S {
475    fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
476        ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id)
477    }
478}
479
480impl<S: ChildObjectResolver> ChildObjectResolver for std::sync::Arc<S> {
481    fn read_child_object(
482        &self,
483        parent: &ObjectID,
484        child: &ObjectID,
485        child_version_upper_bound: SequenceNumber,
486    ) -> SuiResult<Option<Object>> {
487        ChildObjectResolver::read_child_object(
488            self.as_ref(),
489            parent,
490            child,
491            child_version_upper_bound,
492        )
493    }
494    fn get_object_received_at_version(
495        &self,
496        owner: &ObjectID,
497        receiving_object_id: &ObjectID,
498        receive_object_at_version: SequenceNumber,
499        epoch_id: EpochId,
500    ) -> SuiResult<Option<Object>> {
501        ChildObjectResolver::get_object_received_at_version(
502            self.as_ref(),
503            owner,
504            receiving_object_id,
505            receive_object_at_version,
506            epoch_id,
507        )
508    }
509}
510
511impl<S: ChildObjectResolver> ChildObjectResolver for &S {
512    fn read_child_object(
513        &self,
514        parent: &ObjectID,
515        child: &ObjectID,
516        child_version_upper_bound: SequenceNumber,
517    ) -> SuiResult<Option<Object>> {
518        ChildObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
519    }
520    fn get_object_received_at_version(
521        &self,
522        owner: &ObjectID,
523        receiving_object_id: &ObjectID,
524        receive_object_at_version: SequenceNumber,
525        epoch_id: EpochId,
526    ) -> SuiResult<Option<Object>> {
527        ChildObjectResolver::get_object_received_at_version(
528            *self,
529            owner,
530            receiving_object_id,
531            receive_object_at_version,
532            epoch_id,
533        )
534    }
535}
536
537impl<S: ChildObjectResolver> ChildObjectResolver for &mut S {
538    fn read_child_object(
539        &self,
540        parent: &ObjectID,
541        child: &ObjectID,
542        child_version_upper_bound: SequenceNumber,
543    ) -> SuiResult<Option<Object>> {
544        ChildObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
545    }
546    fn get_object_received_at_version(
547        &self,
548        owner: &ObjectID,
549        receiving_object_id: &ObjectID,
550        receive_object_at_version: SequenceNumber,
551        epoch_id: EpochId,
552    ) -> SuiResult<Option<Object>> {
553        ChildObjectResolver::get_object_received_at_version(
554            *self,
555            owner,
556            receiving_object_id,
557            receive_object_at_version,
558            epoch_id,
559        )
560    }
561}
562
563#[serde_as]
564#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
565pub struct ObjectKey(pub ObjectID, pub VersionNumber);
566
567impl ObjectKey {
568    pub const ZERO: ObjectKey = ObjectKey(ObjectID::ZERO, VersionNumber::MIN);
569
570    pub fn max_for_id(id: &ObjectID) -> Self {
571        Self(*id, VersionNumber::MAX)
572    }
573
574    pub fn min_for_id(id: &ObjectID) -> Self {
575        Self(*id, VersionNumber::MIN)
576    }
577}
578
579impl From<ObjectRef> for ObjectKey {
580    fn from(object_ref: ObjectRef) -> Self {
581        ObjectKey::from(&object_ref)
582    }
583}
584
585impl From<&ObjectRef> for ObjectKey {
586    fn from(object_ref: &ObjectRef) -> Self {
587        Self(object_ref.0, object_ref.1)
588    }
589}
590
591#[serde_as]
592#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
593pub struct ConsensusObjectKey(pub ConsensusObjectSequenceKey, pub VersionNumber);
594
595/// FullObjectKey represents a unique object a specific version. For fastpath objects, this
596/// is the same as ObjectKey. For consensus objects, this includes the start version, which
597/// may change if an object is transferred out of and back into consensus.
598#[serde_as]
599#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
600pub enum FullObjectKey {
601    Fastpath(ObjectKey),
602    Consensus(ConsensusObjectKey),
603}
604
605impl FullObjectKey {
606    pub fn max_for_id(id: &FullObjectID) -> Self {
607        match id {
608            FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey::max_for_id(object_id)),
609            FullObjectID::Consensus(consensus_object_sequence_key) => Self::Consensus(
610                ConsensusObjectKey(*consensus_object_sequence_key, VersionNumber::MAX),
611            ),
612        }
613    }
614
615    pub fn min_for_id(id: &FullObjectID) -> Self {
616        match id {
617            FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey::min_for_id(object_id)),
618            FullObjectID::Consensus(consensus_object_sequence_key) => Self::Consensus(
619                ConsensusObjectKey(*consensus_object_sequence_key, VersionNumber::MIN),
620            ),
621        }
622    }
623
624    pub fn new(object_id: FullObjectID, version: VersionNumber) -> Self {
625        match object_id {
626            FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey(object_id, version)),
627            FullObjectID::Consensus(consensus_object_sequence_key) => {
628                Self::Consensus(ConsensusObjectKey(consensus_object_sequence_key, version))
629            }
630        }
631    }
632
633    pub fn id(&self) -> FullObjectID {
634        match self {
635            FullObjectKey::Fastpath(object_key) => FullObjectID::Fastpath(object_key.0),
636            FullObjectKey::Consensus(consensus_object_key) => {
637                FullObjectID::Consensus(consensus_object_key.0)
638            }
639        }
640    }
641
642    pub fn version(&self) -> VersionNumber {
643        match self {
644            FullObjectKey::Fastpath(object_key) => object_key.1,
645            FullObjectKey::Consensus(consensus_object_key) => consensus_object_key.1,
646        }
647    }
648}
649
650impl From<FullObjectRef> for FullObjectKey {
651    fn from(object_ref: FullObjectRef) -> Self {
652        FullObjectKey::from(&object_ref)
653    }
654}
655
656impl From<&FullObjectRef> for FullObjectKey {
657    fn from(object_ref: &FullObjectRef) -> Self {
658        FullObjectKey::new(object_ref.0, object_ref.1)
659    }
660}
661
662#[derive(Clone)]
663pub enum ObjectOrTombstone {
664    Object(Object),
665    Tombstone(ObjectRef),
666}
667
668impl ObjectOrTombstone {
669    pub fn as_objref(&self) -> ObjectRef {
670        match self {
671            ObjectOrTombstone::Object(obj) => obj.compute_object_reference(),
672            ObjectOrTombstone::Tombstone(obref) => *obref,
673        }
674    }
675}
676
677impl From<Object> for ObjectOrTombstone {
678    fn from(object: Object) -> Self {
679        ObjectOrTombstone::Object(object)
680    }
681}
682
683/// Fetch the `ObjectKey`s (IDs and versions) for non-shared input objects.  Includes owned,
684/// and immutable objects as well as the gas objects, but not move packages or shared objects.
685pub fn transaction_non_shared_input_object_keys(
686    tx: &SenderSignedData,
687) -> SuiResult<Vec<ObjectKey>> {
688    use crate::transaction::InputObjectKind as I;
689    Ok(tx
690        .intent_message()
691        .value
692        .input_objects()?
693        .into_iter()
694        .filter_map(|object| match object {
695            I::MovePackage(_) | I::SharedMoveObject { .. } => None,
696            I::ImmOrOwnedMoveObject(obj) => Some(obj.into()),
697        })
698        .collect())
699}
700
701pub fn transaction_receiving_object_keys(tx: &SenderSignedData) -> Vec<ObjectKey> {
702    tx.intent_message()
703        .value
704        .receiving_objects()
705        .into_iter()
706        .map(|oref| oref.into())
707        .collect()
708}
709
710impl Display for DeleteKind {
711    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
712        match self {
713            DeleteKind::Wrap => write!(f, "Wrap"),
714            DeleteKind::Normal => write!(f, "Normal"),
715            DeleteKind::UnwrapThenDelete => write!(f, "UnwrapThenDelete"),
716        }
717    }
718}
719
720pub trait BackingStore:
721    BackingPackageStore + ChildObjectResolver + ObjectStore + ParentSync
722{
723    fn as_object_store(&self) -> &dyn ObjectStore;
724}
725
726impl<T> BackingStore for T
727where
728    T: BackingPackageStore,
729    T: ChildObjectResolver,
730    T: ObjectStore,
731    T: ParentSync,
732{
733    fn as_object_store(&self) -> &dyn ObjectStore {
734        self
735    }
736}
737
738pub fn get_transaction_input_objects(
739    object_store: &dyn ObjectStore,
740    effects: &TransactionEffects,
741) -> Result<Vec<Object>, StorageError> {
742    let input_object_keys = effects
743        .modified_at_versions()
744        .into_iter()
745        .map(|(object_id, version)| ObjectKey(object_id, version))
746        .collect::<Vec<_>>();
747
748    let input_objects = object_store
749        .multi_get_objects_by_key(&input_object_keys)
750        .into_iter()
751        .enumerate()
752        .map(|(idx, maybe_object)| {
753            maybe_object.ok_or_else(|| {
754                StorageError::custom(format!(
755                    "missing input object key {:?} from tx {} effects {}",
756                    input_object_keys[idx],
757                    effects.transaction_digest(),
758                    effects.digest()
759                ))
760            })
761        })
762        .collect::<Result<Vec<_>, _>>()?;
763    Ok(input_objects)
764}
765
766pub fn get_transaction_output_objects(
767    object_store: &dyn ObjectStore,
768    effects: &TransactionEffects,
769) -> Result<Vec<Object>, StorageError> {
770    let output_object_keys = effects
771        .all_changed_objects()
772        .into_iter()
773        .map(|(object_ref, _owner, _kind)| ObjectKey::from(object_ref))
774        .collect::<Vec<_>>();
775
776    let output_objects = object_store
777        .multi_get_objects_by_key(&output_object_keys)
778        .into_iter()
779        .enumerate()
780        .map(|(idx, maybe_object)| {
781            maybe_object.ok_or_else(|| {
782                StorageError::custom(format!(
783                    "missing output object key {:?} from tx {} effects {}",
784                    output_object_keys[idx],
785                    effects.transaction_digest(),
786                    effects.digest()
787                ))
788            })
789        })
790        .collect::<Result<Vec<_>, _>>()?;
791    Ok(output_objects)
792}
793
794// Returns an iterator over the ObjectKey's of objects read or written by this transaction
795pub fn get_transaction_object_set(
796    transaction: &TransactionData,
797    effects: &TransactionEffects,
798    unchanged_loaded_runtime_objects: &[ObjectKey],
799) -> BTreeSet<ObjectKey> {
800    // enumerate the full set of input objects in order to properly capture immutable objects that
801    // may not appear in the effects.
802    //
803    // This excludes packages
804    let input_objects = transaction
805        .input_objects()
806        .expect("txn was executed and must have valid input objects")
807        .into_iter()
808        .filter_map(|input| {
809            input
810                .version()
811                .map(|version| ObjectKey(input.object_id(), version))
812        });
813
814    // The full set of output/written objects as well as any of their initial versions
815    let modified_set = effects
816        .object_changes()
817        .into_iter()
818        .flat_map(|change| {
819            [
820                change
821                    .input_version
822                    .map(|version| ObjectKey(change.id, version)),
823                change
824                    .output_version
825                    .map(|version| ObjectKey(change.id, version)),
826            ]
827        })
828        .flatten();
829
830    // The set of unchanged consensus objects
831    let unchanged_consensus =
832        effects
833            .unchanged_consensus_objects()
834            .into_iter()
835            .flat_map(|unchanged| {
836                if let crate::effects::UnchangedConsensusKind::ReadOnlyRoot((version, _)) =
837                    unchanged.1
838                {
839                    Some(ObjectKey(unchanged.0, version))
840                } else {
841                    None
842                }
843            });
844
845    input_objects
846        .chain(modified_set)
847        .chain(unchanged_consensus)
848        .chain(unchanged_loaded_runtime_objects.iter().copied())
849        .collect()
850}
851
852// A BackingStore to pass to execution in order to track all objects loaded during execution.
853//
854// Today this is used to very accurately track the objects that were loaded but unchanged during
855// execution.
856pub struct TrackingBackingStore<'a> {
857    inner: &'a dyn crate::storage::BackingStore,
858    read_objects: std::cell::RefCell<ObjectSet>,
859}
860
861impl<'a> TrackingBackingStore<'a> {
862    pub fn new(inner: &'a dyn crate::storage::BackingStore) -> Self {
863        Self {
864            inner,
865            read_objects: Default::default(),
866        }
867    }
868
869    pub fn into_read_objects(self) -> ObjectSet {
870        self.read_objects.into_inner()
871    }
872
873    fn track_object(&self, object: &Object) {
874        self.read_objects.borrow_mut().insert(object.clone());
875    }
876}
877
878impl BackingPackageStore for TrackingBackingStore<'_> {
879    fn get_package_object(
880        &self,
881        package_id: &ObjectID,
882    ) -> crate::error::SuiResult<Option<PackageObject>> {
883        self.inner.get_package_object(package_id).inspect(|o| {
884            o.as_ref()
885                .inspect(|package| self.track_object(package.object()));
886        })
887    }
888}
889
890impl ChildObjectResolver for TrackingBackingStore<'_> {
891    fn read_child_object(
892        &self,
893        parent: &ObjectID,
894        child: &ObjectID,
895        child_version_upper_bound: SequenceNumber,
896    ) -> crate::error::SuiResult<Option<Object>> {
897        self.inner
898            .read_child_object(parent, child, child_version_upper_bound)
899            .inspect(|o| {
900                o.as_ref().inspect(|object| self.track_object(object));
901            })
902    }
903
904    fn get_object_received_at_version(
905        &self,
906        owner: &ObjectID,
907        receiving_object_id: &ObjectID,
908        receive_object_at_version: SequenceNumber,
909        epoch_id: crate::committee::EpochId,
910    ) -> crate::error::SuiResult<Option<Object>> {
911        self.inner
912            .get_object_received_at_version(
913                owner,
914                receiving_object_id,
915                receive_object_at_version,
916                epoch_id,
917            )
918            .inspect(|o| {
919                o.as_ref().inspect(|object| self.track_object(object));
920            })
921    }
922}
923
924impl crate::storage::ObjectStore for TrackingBackingStore<'_> {
925    fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
926        self.inner
927            .get_object(object_id)
928            .inspect(|o| self.track_object(o))
929    }
930
931    fn get_object_by_key(
932        &self,
933        object_id: &ObjectID,
934        version: crate::base_types::VersionNumber,
935    ) -> Option<Object> {
936        self.inner
937            .get_object_by_key(object_id, version)
938            .inspect(|o| self.track_object(o))
939    }
940}
941
942impl ParentSync for TrackingBackingStore<'_> {
943    fn get_latest_parent_entry_ref_deprecated(
944        &self,
945        object_id: ObjectID,
946    ) -> Option<crate::base_types::ObjectRef> {
947        self.inner.get_latest_parent_entry_ref_deprecated(object_id)
948    }
949}