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