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