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