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