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