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::LedgerBitmapBucket;
42pub use read_store::LedgerBitmapBucketIter;
43pub use read_store::LedgerBitmapBucketIterator;
44pub use read_store::LedgerTxSeqDigest;
45pub use read_store::LedgerTxSeqDigestIterator;
46pub use read_store::OwnedObjectInfo;
47pub use read_store::ReadStore;
48pub use read_store::RpcIndexes;
49pub use read_store::RpcStateReader;
50pub use read_store::TransactionInfo;
51use serde::{Deserialize, Serialize};
52use serde_with::serde_as;
53pub use shared_in_memory_store::SharedInMemoryStore;
54pub use shared_in_memory_store::SingleCheckpointSharedInMemoryStore;
55use std::collections::{BTreeMap, BTreeSet};
56use std::fmt::{Display, Formatter};
57use std::sync::Arc;
58pub use write_store::WriteStore;
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
62pub enum InputKey {
63 VersionedObject {
64 id: FullObjectID,
65 version: SequenceNumber,
66 },
67 Package {
68 id: ObjectID,
69 },
70}
71
72impl InputKey {
73 pub fn id(&self) -> FullObjectID {
74 match self {
75 InputKey::VersionedObject { id, .. } => *id,
76 InputKey::Package { id } => FullObjectID::Fastpath(*id),
77 }
78 }
79
80 pub fn version(&self) -> Option<SequenceNumber> {
81 match self {
82 InputKey::VersionedObject { version, .. } => Some(*version),
83 InputKey::Package { .. } => None,
84 }
85 }
86
87 pub fn is_cancelled(&self) -> bool {
88 match self {
89 InputKey::VersionedObject { version, .. } => version.is_cancelled(),
90 InputKey::Package { .. } => false,
91 }
92 }
93}
94
95impl From<&Object> for InputKey {
96 fn from(obj: &Object) -> Self {
97 if obj.is_package() {
98 InputKey::Package { id: obj.id() }
99 } else {
100 InputKey::VersionedObject {
101 id: obj.full_id(),
102 version: obj.version(),
103 }
104 }
105 }
106}
107
108#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
109pub enum WriteKind {
110 Mutate,
112 Create,
114 Unwrap,
116}
117
118#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
119pub enum DeleteKind {
120 Normal,
122 UnwrapThenDelete,
125 Wrap,
127}
128
129#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
130pub enum MarkerValue {
131 Received,
134 FastpathStreamEnded,
138 ConsensusStreamEnded(TransactionDigest),
141}
142
143#[derive(Debug)]
150pub enum DeleteKindWithOldVersion {
151 Normal(SequenceNumber),
152 UnwrapThenDeleteDEPRECATED(SequenceNumber),
154 UnwrapThenDelete,
155 Wrap(SequenceNumber),
156}
157
158impl DeleteKindWithOldVersion {
159 pub fn old_version(&self) -> Option<SequenceNumber> {
160 match self {
161 DeleteKindWithOldVersion::Normal(version)
162 | DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(version)
163 | DeleteKindWithOldVersion::Wrap(version) => Some(*version),
164 DeleteKindWithOldVersion::UnwrapThenDelete => None,
165 }
166 }
167
168 pub fn to_delete_kind(&self) -> DeleteKind {
169 match self {
170 DeleteKindWithOldVersion::Normal(_) => DeleteKind::Normal,
171 DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(_)
172 | DeleteKindWithOldVersion::UnwrapThenDelete => DeleteKind::UnwrapThenDelete,
173 DeleteKindWithOldVersion::Wrap(_) => DeleteKind::Wrap,
174 }
175 }
176}
177
178#[derive(Debug)]
179pub enum ObjectChange {
180 Write(Object, WriteKind),
181 Delete(DeleteKindWithOldVersion),
183}
184
185pub trait StorageView: Storage + ParentSync + RuntimeObjectResolver {}
186impl<T: Storage + ParentSync + RuntimeObjectResolver> StorageView for T {}
187
188pub trait RuntimeObjectResolver {
191 fn read_child_object(
193 &self,
194 parent: &ObjectID,
195 child: &ObjectID,
196 child_version_upper_bound: SequenceNumber,
197 ) -> SuiResult<Option<Object>>;
198
199 fn get_object_received_at_version(
205 &self,
206 owner: &ObjectID,
207 receiving_object_id: &ObjectID,
208 receive_object_at_version: SequenceNumber,
209 epoch_id: EpochId,
210 ) -> SuiResult<Option<Object>>;
211}
212
213pub struct DenyListResult {
214 pub result: Result<(), ExecutionError>,
217 pub num_non_gas_coin_owners: u64,
219}
220
221pub trait Storage {
223 fn reset(&mut self);
224
225 fn read_object(&self, id: &ObjectID) -> Option<&Object>;
226
227 fn record_execution_results(&mut self, results: ExecutionResults)
228 -> Result<(), ExecutionError>;
229
230 fn save_loaded_runtime_objects(
231 &mut self,
232 loaded_runtime_objects: BTreeMap<ObjectID, DynamicallyLoadedObjectMetadata>,
233 );
234
235 fn save_wrapped_object_containers(
236 &mut self,
237 wrapped_object_containers: BTreeMap<ObjectID, ObjectID>,
238 );
239
240 fn check_coin_deny_list(
243 &self,
244 receiving_funds_type_and_owners: BTreeMap<TypeTag, BTreeSet<SuiAddress>>,
245 ) -> DenyListResult;
246
247 fn record_generated_object_ids(&mut self, generated_ids: BTreeSet<ObjectID>);
248}
249
250pub type PackageFetchResults<Package> = Result<Vec<Package>, Vec<ObjectID>>;
251
252#[derive(Clone, Debug)]
253pub struct PackageObject {
254 package_object: Object,
255}
256
257impl PackageObject {
258 pub fn new(package_object: Object) -> Self {
259 assert!(package_object.is_package());
260 Self { package_object }
261 }
262
263 pub fn object(&self) -> &Object {
264 &self.package_object
265 }
266
267 pub fn move_package(&self) -> &MovePackage {
268 self.package_object.data.try_as_package().unwrap()
269 }
270}
271
272impl From<PackageObject> for Object {
273 fn from(package_object_arc: PackageObject) -> Self {
274 package_object_arc.package_object
275 }
276}
277
278pub trait BackingPackageStore {
279 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>>;
280}
281
282impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Box<S> {
283 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
284 BackingPackageStore::get_package_object(self.as_ref(), package_id)
285 }
286}
287
288impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Arc<S> {
289 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
290 BackingPackageStore::get_package_object(self.as_ref(), package_id)
291 }
292}
293
294impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &S {
295 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
296 BackingPackageStore::get_package_object(*self, package_id)
297 }
298}
299
300impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &mut S {
301 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
302 BackingPackageStore::get_package_object(*self, package_id)
303 }
304}
305
306pub struct OverlayBackingPackageStore<'a, S> {
310 overlay: &'a ObjectSet,
311 backing: S,
312}
313
314impl<'a, S> OverlayBackingPackageStore<'a, S> {
315 pub fn new(overlay: &'a ObjectSet, backing: S) -> Self {
316 Self { overlay, backing }
317 }
318}
319
320impl<S: BackingPackageStore> BackingPackageStore for OverlayBackingPackageStore<'_, S> {
321 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
322 for obj in self.overlay.iter() {
324 if &obj.id() == package_id {
325 fp_ensure!(
327 obj.is_package(),
328 SuiErrorKind::BadObjectType {
329 error: format!("Package expected, Move object found: {package_id}"),
330 }
331 .into()
332 );
333 return Ok(Some(PackageObject::new(obj.clone())));
334 }
335 }
336 self.backing.get_package_object(package_id)
338 }
339}
340
341pub fn load_package_object_from_object_store(
342 store: &impl ObjectStore,
343 package_id: &ObjectID,
344) -> SuiResult<Option<PackageObject>> {
345 let package = store.get_object(package_id);
346 if let Some(obj) = &package {
347 fp_ensure!(
348 obj.is_package(),
349 SuiErrorKind::BadObjectType {
350 error: format!("Package expected, Move object found: {package_id}"),
351 }
352 .into()
353 );
354 }
355 Ok(package.map(PackageObject::new))
356}
357
358pub fn get_package_objects<'a>(
362 store: &impl BackingPackageStore,
363 package_ids: impl IntoIterator<Item = &'a ObjectID>,
364) -> SuiResult<PackageFetchResults<PackageObject>> {
365 let packages: Vec<Result<_, _>> = package_ids
366 .into_iter()
367 .map(|id| match store.get_package_object(id) {
368 Ok(None) => Ok(Err(*id)),
369 Ok(Some(o)) => Ok(Ok(o)),
370 Err(x) => Err(x),
371 })
372 .collect::<SuiResult<_>>()?;
373
374 let (fetched, failed_to_fetch): (Vec<_>, Vec<_>) = packages.into_iter().partition_result();
375 if !failed_to_fetch.is_empty() {
376 Ok(Err(failed_to_fetch))
377 } else {
378 Ok(Ok(fetched))
379 }
380}
381
382pub fn get_module(
383 store: impl BackingPackageStore,
384 module_id: &ModuleId,
385) -> Result<Option<Vec<u8>>, SuiError> {
386 Ok(store
387 .get_package_object(&ObjectID::from(*module_id.address()))?
388 .and_then(|package| {
389 package
390 .move_package()
391 .serialized_module_map()
392 .get(module_id.name().as_str())
393 .cloned()
394 }))
395}
396
397pub fn get_package(
398 store: impl BackingPackageStore,
399 id: &ObjectID,
400) -> SuiResult<Option<SerializedPackage>> {
401 store
402 .get_package_object(id)?
403 .map(|package| package.move_package().into_serialized_move_package())
404 .transpose()
405}
406
407pub fn get_module_by_id<S: BackingPackageStore>(
408 store: &S,
409 id: &ModuleId,
410) -> anyhow::Result<Option<CompiledModule>, SuiError> {
411 Ok(get_module(store, id)?
412 .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap()))
413}
414
415pub struct PostExecutionPackageResolver {
420 backing_store: Arc<dyn BackingPackageStore>,
421 new_packages: BTreeMap<ObjectID, PackageObject>,
422}
423
424impl PostExecutionPackageResolver {
425 pub fn new(
426 backing_store: Arc<dyn BackingPackageStore>,
427 output_objects: &Option<Vec<Object>>,
428 ) -> Self {
429 let new_packages = output_objects
430 .iter()
431 .flatten()
432 .filter_map(|o| {
433 if o.is_package() {
434 Some((o.id(), PackageObject::new(o.clone())))
435 } else {
436 None
437 }
438 })
439 .collect();
440 Self {
441 backing_store,
442 new_packages,
443 }
444 }
445}
446
447impl BackingPackageStore for PostExecutionPackageResolver {
448 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
449 if let Some(package) = self.new_packages.get(package_id) {
450 Ok(Some(package.clone()))
451 } else {
452 self.backing_store.get_package_object(package_id)
453 }
454 }
455}
456
457pub trait ParentSync {
458 fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef>;
461}
462
463impl<S: ParentSync> ParentSync for std::sync::Arc<S> {
464 fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
465 ParentSync::get_latest_parent_entry_ref_deprecated(self.as_ref(), object_id)
466 }
467}
468
469impl<S: ParentSync> ParentSync for &S {
470 fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
471 ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id)
472 }
473}
474
475impl<S: ParentSync> ParentSync for &mut S {
476 fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
477 ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id)
478 }
479}
480
481impl<S: RuntimeObjectResolver> RuntimeObjectResolver for std::sync::Arc<S> {
482 fn read_child_object(
483 &self,
484 parent: &ObjectID,
485 child: &ObjectID,
486 child_version_upper_bound: SequenceNumber,
487 ) -> SuiResult<Option<Object>> {
488 RuntimeObjectResolver::read_child_object(
489 self.as_ref(),
490 parent,
491 child,
492 child_version_upper_bound,
493 )
494 }
495 fn get_object_received_at_version(
496 &self,
497 owner: &ObjectID,
498 receiving_object_id: &ObjectID,
499 receive_object_at_version: SequenceNumber,
500 epoch_id: EpochId,
501 ) -> SuiResult<Option<Object>> {
502 RuntimeObjectResolver::get_object_received_at_version(
503 self.as_ref(),
504 owner,
505 receiving_object_id,
506 receive_object_at_version,
507 epoch_id,
508 )
509 }
510}
511
512impl<S: RuntimeObjectResolver> RuntimeObjectResolver for &S {
513 fn read_child_object(
514 &self,
515 parent: &ObjectID,
516 child: &ObjectID,
517 child_version_upper_bound: SequenceNumber,
518 ) -> SuiResult<Option<Object>> {
519 RuntimeObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
520 }
521 fn get_object_received_at_version(
522 &self,
523 owner: &ObjectID,
524 receiving_object_id: &ObjectID,
525 receive_object_at_version: SequenceNumber,
526 epoch_id: EpochId,
527 ) -> SuiResult<Option<Object>> {
528 RuntimeObjectResolver::get_object_received_at_version(
529 *self,
530 owner,
531 receiving_object_id,
532 receive_object_at_version,
533 epoch_id,
534 )
535 }
536}
537
538impl<S: RuntimeObjectResolver> RuntimeObjectResolver for &mut S {
539 fn read_child_object(
540 &self,
541 parent: &ObjectID,
542 child: &ObjectID,
543 child_version_upper_bound: SequenceNumber,
544 ) -> SuiResult<Option<Object>> {
545 RuntimeObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
546 }
547 fn get_object_received_at_version(
548 &self,
549 owner: &ObjectID,
550 receiving_object_id: &ObjectID,
551 receive_object_at_version: SequenceNumber,
552 epoch_id: EpochId,
553 ) -> SuiResult<Option<Object>> {
554 RuntimeObjectResolver::get_object_received_at_version(
555 *self,
556 owner,
557 receiving_object_id,
558 receive_object_at_version,
559 epoch_id,
560 )
561 }
562}
563
564#[serde_as]
565#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
566pub struct ObjectKey(pub ObjectID, pub VersionNumber);
567
568impl ObjectKey {
569 pub const ZERO: ObjectKey = ObjectKey(ObjectID::ZERO, VersionNumber::MIN);
570
571 pub fn max_for_id(id: &ObjectID) -> Self {
572 Self(*id, VersionNumber::MAX)
573 }
574
575 pub fn min_for_id(id: &ObjectID) -> Self {
576 Self(*id, VersionNumber::MIN)
577 }
578}
579
580impl From<ObjectRef> for ObjectKey {
581 fn from(object_ref: ObjectRef) -> Self {
582 ObjectKey::from(&object_ref)
583 }
584}
585
586impl From<&ObjectRef> for ObjectKey {
587 fn from(object_ref: &ObjectRef) -> Self {
588 Self(object_ref.0, object_ref.1)
589 }
590}
591
592#[serde_as]
593#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
594pub struct ConsensusObjectKey(pub ConsensusObjectSequenceKey, pub VersionNumber);
595
596#[serde_as]
600#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
601pub enum FullObjectKey {
602 Fastpath(ObjectKey),
603 Consensus(ConsensusObjectKey),
604}
605
606impl FullObjectKey {
607 pub fn max_for_id(id: &FullObjectID) -> Self {
608 match id {
609 FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey::max_for_id(object_id)),
610 FullObjectID::Consensus(consensus_object_sequence_key) => Self::Consensus(
611 ConsensusObjectKey(*consensus_object_sequence_key, VersionNumber::MAX),
612 ),
613 }
614 }
615
616 pub fn min_for_id(id: &FullObjectID) -> Self {
617 match id {
618 FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey::min_for_id(object_id)),
619 FullObjectID::Consensus(consensus_object_sequence_key) => Self::Consensus(
620 ConsensusObjectKey(*consensus_object_sequence_key, VersionNumber::MIN),
621 ),
622 }
623 }
624
625 pub fn new(object_id: FullObjectID, version: VersionNumber) -> Self {
626 match object_id {
627 FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey(object_id, version)),
628 FullObjectID::Consensus(consensus_object_sequence_key) => {
629 Self::Consensus(ConsensusObjectKey(consensus_object_sequence_key, version))
630 }
631 }
632 }
633
634 pub fn id(&self) -> FullObjectID {
635 match self {
636 FullObjectKey::Fastpath(object_key) => FullObjectID::Fastpath(object_key.0),
637 FullObjectKey::Consensus(consensus_object_key) => {
638 FullObjectID::Consensus(consensus_object_key.0)
639 }
640 }
641 }
642
643 pub fn version(&self) -> VersionNumber {
644 match self {
645 FullObjectKey::Fastpath(object_key) => object_key.1,
646 FullObjectKey::Consensus(consensus_object_key) => consensus_object_key.1,
647 }
648 }
649}
650
651impl From<FullObjectRef> for FullObjectKey {
652 fn from(object_ref: FullObjectRef) -> Self {
653 FullObjectKey::from(&object_ref)
654 }
655}
656
657impl From<&FullObjectRef> for FullObjectKey {
658 fn from(object_ref: &FullObjectRef) -> Self {
659 FullObjectKey::new(object_ref.0, object_ref.1)
660 }
661}
662
663#[derive(Clone)]
664pub enum ObjectOrTombstone {
665 Object(Object),
666 Tombstone(ObjectRef),
667}
668
669impl ObjectOrTombstone {
670 pub fn as_objref(&self) -> ObjectRef {
671 match self {
672 ObjectOrTombstone::Object(obj) => obj.compute_object_reference(),
673 ObjectOrTombstone::Tombstone(obref) => *obref,
674 }
675 }
676}
677
678impl From<Object> for ObjectOrTombstone {
679 fn from(object: Object) -> Self {
680 ObjectOrTombstone::Object(object)
681 }
682}
683
684pub fn transaction_non_shared_input_object_keys(
687 tx: &SenderSignedData,
688) -> SuiResult<Vec<ObjectKey>> {
689 use crate::transaction::InputObjectKind as I;
690 Ok(tx
691 .intent_message()
692 .value
693 .input_objects()?
694 .into_iter()
695 .filter_map(|object| match object {
696 I::MovePackage(_) | I::SharedMoveObject { .. } => None,
697 I::ImmOrOwnedMoveObject(obj) => Some(obj.into()),
698 })
699 .collect())
700}
701
702pub fn transaction_receiving_object_keys(tx: &SenderSignedData) -> Vec<ObjectKey> {
703 tx.intent_message()
704 .value
705 .receiving_objects()
706 .into_iter()
707 .map(|oref| oref.into())
708 .collect()
709}
710
711impl Display for DeleteKind {
712 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
713 match self {
714 DeleteKind::Wrap => write!(f, "Wrap"),
715 DeleteKind::Normal => write!(f, "Normal"),
716 DeleteKind::UnwrapThenDelete => write!(f, "UnwrapThenDelete"),
717 }
718 }
719}
720
721pub trait BackingStore:
722 BackingPackageStore + RuntimeObjectResolver + ObjectStore + ParentSync
723{
724 fn as_object_store(&self) -> &dyn ObjectStore;
725}
726
727impl<T> BackingStore for T
728where
729 T: BackingPackageStore,
730 T: RuntimeObjectResolver,
731 T: ObjectStore,
732 T: ParentSync,
733{
734 fn as_object_store(&self) -> &dyn ObjectStore {
735 self
736 }
737}
738
739pub fn get_transaction_input_objects(
740 object_store: &dyn ObjectStore,
741 effects: &TransactionEffects,
742) -> Result<Vec<Object>, StorageError> {
743 let input_object_keys = effects
744 .modified_at_versions()
745 .into_iter()
746 .map(|(object_id, version)| ObjectKey(object_id, version))
747 .collect::<Vec<_>>();
748
749 let input_objects = object_store
750 .multi_get_objects_by_key(&input_object_keys)
751 .into_iter()
752 .enumerate()
753 .map(|(idx, maybe_object)| {
754 maybe_object.ok_or_else(|| {
755 StorageError::custom(format!(
756 "missing input object key {:?} from tx {} effects {}",
757 input_object_keys[idx],
758 effects.transaction_digest(),
759 effects.digest()
760 ))
761 })
762 })
763 .collect::<Result<Vec<_>, _>>()?;
764 Ok(input_objects)
765}
766
767pub fn get_transaction_output_objects(
768 object_store: &dyn ObjectStore,
769 effects: &TransactionEffects,
770) -> Result<Vec<Object>, StorageError> {
771 let output_object_keys = effects
772 .all_changed_objects()
773 .into_iter()
774 .map(|(object_ref, _owner, _kind)| ObjectKey::from(object_ref))
775 .collect::<Vec<_>>();
776
777 let output_objects = object_store
778 .multi_get_objects_by_key(&output_object_keys)
779 .into_iter()
780 .enumerate()
781 .map(|(idx, maybe_object)| {
782 maybe_object.ok_or_else(|| {
783 StorageError::custom(format!(
784 "missing output object key {:?} from tx {} effects {}",
785 output_object_keys[idx],
786 effects.transaction_digest(),
787 effects.digest()
788 ))
789 })
790 })
791 .collect::<Result<Vec<_>, _>>()?;
792 Ok(output_objects)
793}
794
795pub fn get_transaction_object_set(
797 transaction: &TransactionData,
798 effects: &TransactionEffects,
799 unchanged_loaded_runtime_objects: &[ObjectKey],
800) -> BTreeSet<ObjectKey> {
801 let input_objects = transaction
806 .input_objects()
807 .expect("txn was executed and must have valid input objects")
808 .into_iter()
809 .filter_map(|input| {
810 input
811 .version()
812 .map(|version| ObjectKey(input.object_id(), version))
813 });
814
815 let modified_set = effects
817 .object_changes()
818 .into_iter()
819 .flat_map(|change| {
820 [
821 change
822 .input_version
823 .map(|version| ObjectKey(change.id, version)),
824 change
825 .output_version
826 .map(|version| ObjectKey(change.id, version)),
827 ]
828 })
829 .flatten();
830
831 let unchanged_consensus =
833 effects
834 .unchanged_consensus_objects()
835 .into_iter()
836 .flat_map(|unchanged| {
837 if let crate::effects::UnchangedConsensusKind::ReadOnlyRoot((version, _)) =
838 unchanged.1
839 {
840 Some(ObjectKey(unchanged.0, version))
841 } else {
842 None
843 }
844 });
845
846 input_objects
847 .chain(modified_set)
848 .chain(unchanged_consensus)
849 .chain(unchanged_loaded_runtime_objects.iter().copied())
850 .collect()
851}
852
853pub struct TrackingBackingStore<'a> {
858 inner: &'a dyn crate::storage::BackingStore,
859 read_objects: std::cell::RefCell<ObjectSet>,
860}
861
862impl<'a> TrackingBackingStore<'a> {
863 pub fn new(inner: &'a dyn crate::storage::BackingStore) -> Self {
864 Self {
865 inner,
866 read_objects: Default::default(),
867 }
868 }
869
870 pub fn into_read_objects(self) -> ObjectSet {
871 self.read_objects.into_inner()
872 }
873
874 fn track_object(&self, object: &Object) {
875 self.read_objects.borrow_mut().insert(object.clone());
876 }
877}
878
879impl BackingPackageStore for TrackingBackingStore<'_> {
880 fn get_package_object(
881 &self,
882 package_id: &ObjectID,
883 ) -> crate::error::SuiResult<Option<PackageObject>> {
884 self.inner.get_package_object(package_id).inspect(|o| {
885 o.as_ref()
886 .inspect(|package| self.track_object(package.object()));
887 })
888 }
889}
890
891impl RuntimeObjectResolver for TrackingBackingStore<'_> {
892 fn read_child_object(
893 &self,
894 parent: &ObjectID,
895 child: &ObjectID,
896 child_version_upper_bound: SequenceNumber,
897 ) -> crate::error::SuiResult<Option<Object>> {
898 self.inner
899 .read_child_object(parent, child, child_version_upper_bound)
900 .inspect(|o| {
901 o.as_ref().inspect(|object| self.track_object(object));
902 })
903 }
904
905 fn get_object_received_at_version(
906 &self,
907 owner: &ObjectID,
908 receiving_object_id: &ObjectID,
909 receive_object_at_version: SequenceNumber,
910 epoch_id: crate::committee::EpochId,
911 ) -> crate::error::SuiResult<Option<Object>> {
912 self.inner
913 .get_object_received_at_version(
914 owner,
915 receiving_object_id,
916 receive_object_at_version,
917 epoch_id,
918 )
919 .inspect(|o| {
920 o.as_ref().inspect(|object| self.track_object(object));
921 })
922 }
923}
924
925impl crate::storage::ObjectStore for TrackingBackingStore<'_> {
926 fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
927 self.inner
928 .get_object(object_id)
929 .inspect(|o| self.track_object(o))
930 }
931
932 fn get_object_by_key(
933 &self,
934 object_id: &ObjectID,
935 version: crate::base_types::VersionNumber,
936 ) -> Option<Object> {
937 self.inner
938 .get_object_by_key(object_id, version)
939 .inspect(|o| self.track_object(o))
940 }
941}
942
943impl ParentSync for TrackingBackingStore<'_> {
944 fn get_latest_parent_entry_ref_deprecated(
945 &self,
946 object_id: ObjectID,
947 ) -> Option<crate::base_types::ObjectRef> {
948 self.inner.get_latest_parent_entry_ref_deprecated(object_id)
949 }
950}