Skip to main content

sui_types/storage/
mod.rs

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