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: BackingPackageStore {
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    /// Get's the package at the given version. Returns `Some(package)` only if the `package_id` is
213    /// a `MovePackage` with the given `package_version`. Returns `None` in all other cases.
214    ///
215    /// Since the has the _possibility_ of doing unsequenced reads of object IDs it is important
216    /// here that:
217    /// * If the package object does not exist; or
218    /// * If the package object exists but is not a Move package; or
219    /// * If the package object exists and is a Move package, but the version is not the supplied version.
220    ///
221    /// All return the same error.
222    ///
223    /// To be extra careful, we simply return `None` in all cases unless the object is a package
224    /// with the exact version supplied, and let the caller decide how to handle it.
225    fn get_package_at_version(
226        &self,
227        package_id: &ObjectID,
228        package_version: SequenceNumber,
229    ) -> Option<MovePackage> {
230        let move_pkg = self
231            .get_package_object(package_id)
232            .ok()
233            .flatten()?
234            .into_move_package();
235        if move_pkg.version() == package_version {
236            Some(move_pkg)
237        } else {
238            None
239        }
240    }
241}
242
243pub struct DenyListResult {
244    /// Ok if all regulated coin owners are allowed.
245    /// Err if any regulated coin owner is denied (returning the error for first one denied).
246    pub result: Result<(), ExecutionError>,
247    /// The number of non-gas-coin owners in the transaction results
248    pub num_non_gas_coin_owners: u64,
249}
250
251/// An abstraction of the (possibly distributed) store for objects, and (soon) events and transactions
252pub trait Storage {
253    fn reset(&mut self);
254
255    fn read_object(&self, id: &ObjectID) -> Option<&Object>;
256
257    fn record_execution_results(&mut self, results: ExecutionResults)
258    -> Result<(), ExecutionError>;
259
260    fn save_loaded_runtime_objects(
261        &mut self,
262        loaded_runtime_objects: BTreeMap<ObjectID, DynamicallyLoadedObjectMetadata>,
263    );
264
265    fn save_wrapped_object_containers(
266        &mut self,
267        wrapped_object_containers: BTreeMap<ObjectID, ObjectID>,
268    );
269
270    /// Given the set of all coin types and owners that are receiving the coins during execution,
271    /// Check coin denylist v2, and return the number of non-gas-coin owners.
272    fn check_coin_deny_list(
273        &self,
274        receiving_funds_type_and_owners: BTreeMap<TypeTag, BTreeSet<SuiAddress>>,
275    ) -> DenyListResult;
276
277    fn record_generated_object_ids(&mut self, generated_ids: BTreeSet<ObjectID>);
278}
279
280pub type PackageFetchResults<Package> = Result<Vec<Package>, Vec<ObjectID>>;
281
282#[derive(Clone, Debug)]
283pub struct PackageObject {
284    package_object: Object,
285}
286
287impl PackageObject {
288    pub fn new(package_object: Object) -> Self {
289        assert!(package_object.is_package());
290        Self { package_object }
291    }
292
293    pub fn object(&self) -> &Object {
294        &self.package_object
295    }
296
297    pub fn move_package(&self) -> &MovePackage {
298        self.package_object.data.try_as_package().unwrap()
299    }
300
301    pub fn into_move_package(self) -> MovePackage {
302        self.package_object
303            .into_inner()
304            .data
305            .try_into_package()
306            .unwrap()
307    }
308}
309
310impl From<PackageObject> for Object {
311    fn from(package_object_arc: PackageObject) -> Self {
312        package_object_arc.package_object
313    }
314}
315
316pub trait BackingPackageStore {
317    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>>;
318}
319
320impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Box<S> {
321    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
322        BackingPackageStore::get_package_object(self.as_ref(), package_id)
323    }
324}
325
326impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Arc<S> {
327    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
328        BackingPackageStore::get_package_object(self.as_ref(), package_id)
329    }
330}
331
332impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &S {
333    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
334        BackingPackageStore::get_package_object(*self, package_id)
335    }
336}
337
338impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &mut S {
339    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
340        BackingPackageStore::get_package_object(*self, package_id)
341    }
342}
343
344/// A BackingPackageStore that overlays objects on top of a backing store.
345/// This allows resolving packages from a set of objects (e.g., output objects from a transaction)
346/// before falling back to the backing store.
347pub struct OverlayBackingPackageStore<'a, S> {
348    overlay: &'a ObjectSet,
349    backing: S,
350}
351
352impl<'a, S> OverlayBackingPackageStore<'a, S> {
353    pub fn new(overlay: &'a ObjectSet, backing: S) -> Self {
354        Self { overlay, backing }
355    }
356}
357
358impl<S: BackingPackageStore> BackingPackageStore for OverlayBackingPackageStore<'_, S> {
359    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
360        // First check the overlay for the object
361        for obj in self.overlay.iter() {
362            if &obj.id() == package_id {
363                // Found in overlay - check if it's a package
364                fp_ensure!(
365                    obj.is_package(),
366                    SuiErrorKind::BadObjectType {
367                        error: format!("Package expected, Move object found: {package_id}"),
368                    }
369                    .into()
370                );
371                return Ok(Some(PackageObject::new(obj.clone())));
372            }
373        }
374        // Not in overlay, fall back to the backing store
375        self.backing.get_package_object(package_id)
376    }
377}
378
379pub fn load_package_object_from_object_store(
380    store: &impl ObjectStore,
381    package_id: &ObjectID,
382) -> SuiResult<Option<PackageObject>> {
383    let package = store.get_object(package_id);
384    if let Some(obj) = &package {
385        fp_ensure!(
386            obj.is_package(),
387            SuiErrorKind::BadObjectType {
388                error: format!("Package expected, Move object found: {package_id}"),
389            }
390            .into()
391        );
392    }
393    Ok(package.map(PackageObject::new))
394}
395
396/// Returns Ok(<package object for each package id in `package_ids`>) if all package IDs in
397/// `package_id` were found. If any package in `package_ids` was not found it returns a list
398/// of any package ids that are unable to be found>).
399pub fn get_package_objects<'a>(
400    store: &impl BackingPackageStore,
401    package_ids: impl IntoIterator<Item = &'a ObjectID>,
402) -> SuiResult<PackageFetchResults<PackageObject>> {
403    let packages: Vec<Result<_, _>> = package_ids
404        .into_iter()
405        .map(|id| match store.get_package_object(id) {
406            Ok(None) => Ok(Err(*id)),
407            Ok(Some(o)) => Ok(Ok(o)),
408            Err(x) => Err(x),
409        })
410        .collect::<SuiResult<_>>()?;
411
412    let (fetched, failed_to_fetch): (Vec<_>, Vec<_>) = packages.into_iter().partition_result();
413    if !failed_to_fetch.is_empty() {
414        Ok(Err(failed_to_fetch))
415    } else {
416        Ok(Ok(fetched))
417    }
418}
419
420pub fn get_module(
421    store: impl BackingPackageStore,
422    module_id: &ModuleId,
423) -> Result<Option<Vec<u8>>, SuiError> {
424    Ok(store
425        .get_package_object(&ObjectID::from(*module_id.address()))?
426        .and_then(|package| {
427            package
428                .move_package()
429                .serialized_module_map()
430                .get(module_id.name().as_str())
431                .cloned()
432        }))
433}
434
435pub fn get_package(
436    store: impl BackingPackageStore,
437    id: &ObjectID,
438) -> SuiResult<Option<SerializedPackage>> {
439    store
440        .get_package_object(id)?
441        .map(|package| package.move_package().into_serialized_move_package())
442        .transpose()
443}
444
445pub fn get_module_by_id<S: BackingPackageStore>(
446    store: &S,
447    id: &ModuleId,
448) -> anyhow::Result<Option<CompiledModule>, SuiError> {
449    Ok(get_module(store, id)?
450        .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap()))
451}
452
453/// A `BackingPackageStore` that resolves packages from a backing store, but also includes any
454/// packages that were published in the current transaction execution. This can be used to resolve
455/// Move modules right after transaction execution, but newly published packages have not yet been
456/// committed to the backing store on a fullnode.
457pub struct PostExecutionPackageResolver {
458    backing_store: Arc<dyn BackingPackageStore>,
459    new_packages: BTreeMap<ObjectID, PackageObject>,
460}
461
462impl PostExecutionPackageResolver {
463    pub fn new(
464        backing_store: Arc<dyn BackingPackageStore>,
465        output_objects: &Option<Vec<Object>>,
466    ) -> Self {
467        let new_packages = output_objects
468            .iter()
469            .flatten()
470            .filter_map(|o| {
471                if o.is_package() {
472                    Some((o.id(), PackageObject::new(o.clone())))
473                } else {
474                    None
475                }
476            })
477            .collect();
478        Self {
479            backing_store,
480            new_packages,
481        }
482    }
483}
484
485impl BackingPackageStore for PostExecutionPackageResolver {
486    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
487        if let Some(package) = self.new_packages.get(package_id) {
488            Ok(Some(package.clone()))
489        } else {
490            self.backing_store.get_package_object(package_id)
491        }
492    }
493}
494
495pub trait ParentSync {
496    /// This function is only called by older protocol versions.
497    /// It creates an explicit dependency to tombstones, which is not desired.
498    fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef>;
499}
500
501impl<S: ParentSync> ParentSync for std::sync::Arc<S> {
502    fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
503        ParentSync::get_latest_parent_entry_ref_deprecated(self.as_ref(), object_id)
504    }
505}
506
507impl<S: ParentSync> ParentSync for &S {
508    fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
509        ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id)
510    }
511}
512
513impl<S: ParentSync> ParentSync for &mut S {
514    fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
515        ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id)
516    }
517}
518
519impl<S: RuntimeObjectResolver> RuntimeObjectResolver for std::sync::Arc<S> {
520    fn read_child_object(
521        &self,
522        parent: &ObjectID,
523        child: &ObjectID,
524        child_version_upper_bound: SequenceNumber,
525    ) -> SuiResult<Option<Object>> {
526        RuntimeObjectResolver::read_child_object(
527            self.as_ref(),
528            parent,
529            child,
530            child_version_upper_bound,
531        )
532    }
533    fn get_object_received_at_version(
534        &self,
535        owner: &ObjectID,
536        receiving_object_id: &ObjectID,
537        receive_object_at_version: SequenceNumber,
538        epoch_id: EpochId,
539    ) -> SuiResult<Option<Object>> {
540        RuntimeObjectResolver::get_object_received_at_version(
541            self.as_ref(),
542            owner,
543            receiving_object_id,
544            receive_object_at_version,
545            epoch_id,
546        )
547    }
548}
549
550impl<S: RuntimeObjectResolver> RuntimeObjectResolver for &S {
551    fn read_child_object(
552        &self,
553        parent: &ObjectID,
554        child: &ObjectID,
555        child_version_upper_bound: SequenceNumber,
556    ) -> SuiResult<Option<Object>> {
557        RuntimeObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
558    }
559    fn get_object_received_at_version(
560        &self,
561        owner: &ObjectID,
562        receiving_object_id: &ObjectID,
563        receive_object_at_version: SequenceNumber,
564        epoch_id: EpochId,
565    ) -> SuiResult<Option<Object>> {
566        RuntimeObjectResolver::get_object_received_at_version(
567            *self,
568            owner,
569            receiving_object_id,
570            receive_object_at_version,
571            epoch_id,
572        )
573    }
574}
575
576impl<S: RuntimeObjectResolver> RuntimeObjectResolver for &mut S {
577    fn read_child_object(
578        &self,
579        parent: &ObjectID,
580        child: &ObjectID,
581        child_version_upper_bound: SequenceNumber,
582    ) -> SuiResult<Option<Object>> {
583        RuntimeObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
584    }
585    fn get_object_received_at_version(
586        &self,
587        owner: &ObjectID,
588        receiving_object_id: &ObjectID,
589        receive_object_at_version: SequenceNumber,
590        epoch_id: EpochId,
591    ) -> SuiResult<Option<Object>> {
592        RuntimeObjectResolver::get_object_received_at_version(
593            *self,
594            owner,
595            receiving_object_id,
596            receive_object_at_version,
597            epoch_id,
598        )
599    }
600}
601
602#[serde_as]
603#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
604pub struct ObjectKey(pub ObjectID, pub VersionNumber);
605
606impl ObjectKey {
607    pub const ZERO: ObjectKey = ObjectKey(ObjectID::ZERO, VersionNumber::MIN);
608
609    pub fn max_for_id(id: &ObjectID) -> Self {
610        Self(*id, VersionNumber::MAX)
611    }
612
613    pub fn min_for_id(id: &ObjectID) -> Self {
614        Self(*id, VersionNumber::MIN)
615    }
616}
617
618impl From<ObjectRef> for ObjectKey {
619    fn from(object_ref: ObjectRef) -> Self {
620        ObjectKey::from(&object_ref)
621    }
622}
623
624impl From<&ObjectRef> for ObjectKey {
625    fn from(object_ref: &ObjectRef) -> Self {
626        Self(object_ref.0, object_ref.1)
627    }
628}
629
630#[serde_as]
631#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
632pub struct ConsensusObjectKey(pub ConsensusObjectSequenceKey, pub VersionNumber);
633
634/// FullObjectKey represents a unique object a specific version. For fastpath objects, this
635/// is the same as ObjectKey. For consensus objects, this includes the start version, which
636/// may change if an object is transferred out of and back into consensus.
637#[serde_as]
638#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
639pub enum FullObjectKey {
640    Fastpath(ObjectKey),
641    Consensus(ConsensusObjectKey),
642}
643
644impl FullObjectKey {
645    pub fn max_for_id(id: &FullObjectID) -> Self {
646        match id {
647            FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey::max_for_id(object_id)),
648            FullObjectID::Consensus(consensus_object_sequence_key) => Self::Consensus(
649                ConsensusObjectKey(*consensus_object_sequence_key, VersionNumber::MAX),
650            ),
651        }
652    }
653
654    pub fn min_for_id(id: &FullObjectID) -> Self {
655        match id {
656            FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey::min_for_id(object_id)),
657            FullObjectID::Consensus(consensus_object_sequence_key) => Self::Consensus(
658                ConsensusObjectKey(*consensus_object_sequence_key, VersionNumber::MIN),
659            ),
660        }
661    }
662
663    pub fn new(object_id: FullObjectID, version: VersionNumber) -> Self {
664        match object_id {
665            FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey(object_id, version)),
666            FullObjectID::Consensus(consensus_object_sequence_key) => {
667                Self::Consensus(ConsensusObjectKey(consensus_object_sequence_key, version))
668            }
669        }
670    }
671
672    pub fn id(&self) -> FullObjectID {
673        match self {
674            FullObjectKey::Fastpath(object_key) => FullObjectID::Fastpath(object_key.0),
675            FullObjectKey::Consensus(consensus_object_key) => {
676                FullObjectID::Consensus(consensus_object_key.0)
677            }
678        }
679    }
680
681    pub fn version(&self) -> VersionNumber {
682        match self {
683            FullObjectKey::Fastpath(object_key) => object_key.1,
684            FullObjectKey::Consensus(consensus_object_key) => consensus_object_key.1,
685        }
686    }
687}
688
689impl From<FullObjectRef> for FullObjectKey {
690    fn from(object_ref: FullObjectRef) -> Self {
691        FullObjectKey::from(&object_ref)
692    }
693}
694
695impl From<&FullObjectRef> for FullObjectKey {
696    fn from(object_ref: &FullObjectRef) -> Self {
697        FullObjectKey::new(object_ref.0, object_ref.1)
698    }
699}
700
701#[derive(Clone)]
702pub enum ObjectOrTombstone {
703    Object(Object),
704    Tombstone(ObjectRef),
705}
706
707impl ObjectOrTombstone {
708    pub fn as_objref(&self) -> ObjectRef {
709        match self {
710            ObjectOrTombstone::Object(obj) => obj.compute_object_reference(),
711            ObjectOrTombstone::Tombstone(obref) => *obref,
712        }
713    }
714}
715
716impl From<Object> for ObjectOrTombstone {
717    fn from(object: Object) -> Self {
718        ObjectOrTombstone::Object(object)
719    }
720}
721
722/// Fetch the `ObjectKey`s (IDs and versions) for non-shared input objects.  Includes owned,
723/// and immutable objects as well as the gas objects, but not move packages or shared objects.
724pub fn transaction_non_shared_input_object_keys(
725    tx: &SenderSignedData,
726) -> SuiResult<Vec<ObjectKey>> {
727    use crate::transaction::InputObjectKind as I;
728    Ok(tx
729        .intent_message()
730        .value
731        .input_objects()?
732        .into_iter()
733        .filter_map(|object| match object {
734            I::MovePackage(_) | I::SharedMoveObject { .. } => None,
735            I::ImmOrOwnedMoveObject(obj) => Some(obj.into()),
736        })
737        .collect())
738}
739
740pub fn transaction_receiving_object_keys(tx: &SenderSignedData) -> Vec<ObjectKey> {
741    tx.intent_message()
742        .value
743        .receiving_objects()
744        .into_iter()
745        .map(|oref| oref.into())
746        .collect()
747}
748
749impl Display for DeleteKind {
750    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
751        match self {
752            DeleteKind::Wrap => write!(f, "Wrap"),
753            DeleteKind::Normal => write!(f, "Normal"),
754            DeleteKind::UnwrapThenDelete => write!(f, "UnwrapThenDelete"),
755        }
756    }
757}
758
759pub trait BackingStore:
760    BackingPackageStore + RuntimeObjectResolver + ObjectStore + ParentSync
761{
762    fn as_object_store(&self) -> &dyn ObjectStore;
763}
764
765impl<T> BackingStore for T
766where
767    T: BackingPackageStore,
768    T: RuntimeObjectResolver,
769    T: ObjectStore,
770    T: ParentSync,
771{
772    fn as_object_store(&self) -> &dyn ObjectStore {
773        self
774    }
775}
776
777pub fn get_transaction_input_objects(
778    object_store: &dyn ObjectStore,
779    effects: &TransactionEffects,
780) -> Result<Vec<Object>, StorageError> {
781    let input_object_keys = effects
782        .modified_at_versions()
783        .into_iter()
784        .map(|(object_id, version)| ObjectKey(object_id, version))
785        .collect::<Vec<_>>();
786
787    let input_objects = object_store
788        .multi_get_objects_by_key(&input_object_keys)
789        .into_iter()
790        .enumerate()
791        .map(|(idx, maybe_object)| {
792            maybe_object.ok_or_else(|| {
793                StorageError::custom(format!(
794                    "missing input object key {:?} from tx {} effects {}",
795                    input_object_keys[idx],
796                    effects.transaction_digest(),
797                    effects.digest()
798                ))
799            })
800        })
801        .collect::<Result<Vec<_>, _>>()?;
802    Ok(input_objects)
803}
804
805pub fn get_transaction_output_objects(
806    object_store: &dyn ObjectStore,
807    effects: &TransactionEffects,
808) -> Result<Vec<Object>, StorageError> {
809    let output_object_keys = effects
810        .all_changed_objects()
811        .into_iter()
812        .map(|(object_ref, _owner, _kind)| ObjectKey::from(object_ref))
813        .collect::<Vec<_>>();
814
815    let output_objects = object_store
816        .multi_get_objects_by_key(&output_object_keys)
817        .into_iter()
818        .enumerate()
819        .map(|(idx, maybe_object)| {
820            maybe_object.ok_or_else(|| {
821                StorageError::custom(format!(
822                    "missing output object key {:?} from tx {} effects {}",
823                    output_object_keys[idx],
824                    effects.transaction_digest(),
825                    effects.digest()
826                ))
827            })
828        })
829        .collect::<Result<Vec<_>, _>>()?;
830    Ok(output_objects)
831}
832
833// Returns an iterator over the ObjectKey's of objects read or written by this transaction
834pub fn get_transaction_object_set(
835    transaction: &TransactionData,
836    effects: &TransactionEffects,
837    unchanged_loaded_runtime_objects: &[ObjectKey],
838) -> BTreeSet<ObjectKey> {
839    // enumerate the full set of input objects in order to properly capture immutable objects that
840    // may not appear in the effects.
841    //
842    // This excludes packages
843    let input_objects = transaction
844        .input_objects()
845        .expect("txn was executed and must have valid input objects")
846        .into_iter()
847        .filter_map(|input| {
848            input
849                .version()
850                .map(|version| ObjectKey(input.object_id(), version))
851        });
852
853    // The full set of output/written objects as well as any of their initial versions
854    let modified_set = effects
855        .object_changes()
856        .into_iter()
857        .flat_map(|change| {
858            [
859                change
860                    .input_version
861                    .map(|version| ObjectKey(change.id, version)),
862                change
863                    .output_version
864                    .map(|version| ObjectKey(change.id, version)),
865            ]
866        })
867        .flatten();
868
869    // The set of unchanged consensus objects
870    let unchanged_consensus =
871        effects
872            .unchanged_consensus_objects()
873            .into_iter()
874            .flat_map(|unchanged| {
875                if let crate::effects::UnchangedConsensusKind::ReadOnlyRoot((version, _)) =
876                    unchanged.1
877                {
878                    Some(ObjectKey(unchanged.0, version))
879                } else {
880                    None
881                }
882            });
883
884    input_objects
885        .chain(modified_set)
886        .chain(unchanged_consensus)
887        .chain(unchanged_loaded_runtime_objects.iter().copied())
888        .collect()
889}
890
891// A BackingStore to pass to execution in order to track all objects loaded during execution.
892//
893// Today this is used to very accurately track the objects that were loaded but unchanged during
894// execution.
895pub struct TrackingBackingStore<'a> {
896    inner: &'a dyn crate::storage::BackingStore,
897    read_objects: std::cell::RefCell<ObjectSet>,
898}
899
900impl<'a> TrackingBackingStore<'a> {
901    pub fn new(inner: &'a dyn crate::storage::BackingStore) -> Self {
902        Self {
903            inner,
904            read_objects: Default::default(),
905        }
906    }
907
908    pub fn into_read_objects(self) -> ObjectSet {
909        self.read_objects.into_inner()
910    }
911
912    fn track_object(&self, object: &Object) {
913        self.read_objects.borrow_mut().insert(object.clone());
914    }
915}
916
917impl BackingPackageStore for TrackingBackingStore<'_> {
918    fn get_package_object(
919        &self,
920        package_id: &ObjectID,
921    ) -> crate::error::SuiResult<Option<PackageObject>> {
922        self.inner.get_package_object(package_id).inspect(|o| {
923            o.as_ref()
924                .inspect(|package| self.track_object(package.object()));
925        })
926    }
927}
928
929impl RuntimeObjectResolver for TrackingBackingStore<'_> {
930    fn read_child_object(
931        &self,
932        parent: &ObjectID,
933        child: &ObjectID,
934        child_version_upper_bound: SequenceNumber,
935    ) -> crate::error::SuiResult<Option<Object>> {
936        self.inner
937            .read_child_object(parent, child, child_version_upper_bound)
938            .inspect(|o| {
939                o.as_ref().inspect(|object| self.track_object(object));
940            })
941    }
942
943    fn get_object_received_at_version(
944        &self,
945        owner: &ObjectID,
946        receiving_object_id: &ObjectID,
947        receive_object_at_version: SequenceNumber,
948        epoch_id: crate::committee::EpochId,
949    ) -> crate::error::SuiResult<Option<Object>> {
950        self.inner
951            .get_object_received_at_version(
952                owner,
953                receiving_object_id,
954                receive_object_at_version,
955                epoch_id,
956            )
957            .inspect(|o| {
958                o.as_ref().inspect(|object| self.track_object(object));
959            })
960    }
961}
962
963impl crate::storage::ObjectStore for TrackingBackingStore<'_> {
964    fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
965        self.inner
966            .get_object(object_id)
967            .inspect(|o| self.track_object(o))
968    }
969
970    fn get_object_by_key(
971        &self,
972        object_id: &ObjectID,
973        version: crate::base_types::VersionNumber,
974    ) -> Option<Object> {
975        self.inner
976            .get_object_by_key(object_id, version)
977            .inspect(|o| self.track_object(o))
978    }
979}
980
981impl ParentSync for TrackingBackingStore<'_> {
982    fn get_latest_parent_entry_ref_deprecated(
983        &self,
984        object_id: ObjectID,
985    ) -> Option<crate::base_types::ObjectRef> {
986        self.inner.get_latest_parent_entry_ref_deprecated(object_id)
987    }
988}