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