1pub 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#[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 Mutate,
107 Create,
109 Unwrap,
111}
112
113#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
114pub enum DeleteKind {
115 Normal,
117 UnwrapThenDelete,
120 Wrap,
122}
123
124#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
125pub enum MarkerValue {
126 Received,
129 FastpathStreamEnded,
133 ConsensusStreamEnded(TransactionDigest),
136}
137
138#[derive(Debug)]
145pub enum DeleteKindWithOldVersion {
146 Normal(SequenceNumber),
147 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 Delete(DeleteKindWithOldVersion),
178}
179
180pub trait StorageView: Storage + ParentSync + ChildObjectResolver {}
181impl<T: Storage + ParentSync + ChildObjectResolver> StorageView for T {}
182
183pub trait ChildObjectResolver {
186 fn read_child_object(
188 &self,
189 parent: &ObjectID,
190 child: &ObjectID,
191 child_version_upper_bound: SequenceNumber,
192 ) -> SuiResult<Option<Object>>;
193
194 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 pub result: Result<(), ExecutionError>,
212 pub num_non_gas_coin_owners: u64,
214}
215
216pub 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 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
318pub 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
375pub 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 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#[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
644pub 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
755pub fn get_transaction_object_set(
757 transaction: &TransactionData,
758 effects: &TransactionEffects,
759 unchanged_loaded_runtime_objects: &[ObjectKey],
760) -> BTreeSet<ObjectKey> {
761 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 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 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
813pub 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}