sui_types/storage/
mod.rs

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