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