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