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