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