1pub mod error;
5mod object_store_trait;
6mod read_store;
7mod shared_in_memory_store;
8mod write_store;
9
10use crate::SUI_ACCUMULATOR_ROOT_OBJECT_ID;
11use crate::base_types::{
12 ConsensusObjectSequenceKey, ConsensusObjectVersion, FullObjectID, FullObjectRef, SuiAddress,
13 SystemObjectVersions, TransactionDigest, VersionNumber,
14};
15use crate::committee::EpochId;
16use crate::effects::InputConsensusObject;
17use crate::effects::{TransactionEffects, TransactionEffectsAPI};
18use crate::error::{ExecutionError, SuiError, SuiErrorKind};
19use crate::execution::{DynamicallyLoadedObjectMetadata, ExecutionResults};
20use crate::full_checkpoint_content::ObjectSet;
21use crate::message_envelope::Message;
22use crate::move_package::MovePackage;
23use crate::storage::error::Error as StorageError;
24use crate::transaction::TransactionData;
25use crate::transaction::{SenderSignedData, TransactionDataAPI};
26use crate::{
27 base_types::{ObjectID, ObjectRef, SequenceNumber},
28 error::SuiResult,
29 object::Object,
30};
31use itertools::Itertools;
32use move_binary_format::CompiledModule;
33use move_core_types::language_storage::{ModuleId, TypeTag};
34use move_core_types::resolver::SerializedPackage;
35pub use object_store_trait::ObjectStore;
36pub use read_store::BalanceInfo;
37pub use read_store::BalanceIterator;
38pub use read_store::CoinInfo;
39pub use read_store::DynamicFieldIndexInfo;
40pub use read_store::DynamicFieldIteratorItem;
41pub use read_store::DynamicFieldKey;
42pub use read_store::EpochInfo;
43pub use read_store::LedgerBitmapBucket;
44pub use read_store::LedgerBitmapBucketIter;
45pub use read_store::LedgerBitmapBucketIterator;
46pub use read_store::LedgerTxSeqDigest;
47pub use read_store::LedgerTxSeqDigestIterator;
48pub use read_store::OwnedObjectInfo;
49pub use read_store::ReadStore;
50pub use read_store::RpcIndexes;
51pub use read_store::RpcStateReader;
52pub use read_store::TransactionInfo;
53use serde::{Deserialize, Serialize};
54use serde_with::serde_as;
55pub use shared_in_memory_store::SharedInMemoryStore;
56pub use shared_in_memory_store::SingleCheckpointSharedInMemoryStore;
57use std::collections::{BTreeMap, BTreeSet};
58use std::fmt::{Display, Formatter};
59use std::sync::Arc;
60pub use write_store::WriteStore;
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
64pub enum InputKey {
65 VersionedObject {
66 id: FullObjectID,
67 version: SequenceNumber,
68 },
69 Package {
70 id: ObjectID,
71 },
72}
73
74impl InputKey {
75 pub fn id(&self) -> FullObjectID {
76 match self {
77 InputKey::VersionedObject { id, .. } => *id,
78 InputKey::Package { id } => FullObjectID::Fastpath(*id),
79 }
80 }
81
82 pub fn version(&self) -> Option<SequenceNumber> {
83 match self {
84 InputKey::VersionedObject { version, .. } => Some(*version),
85 InputKey::Package { .. } => None,
86 }
87 }
88
89 pub fn is_cancelled(&self) -> bool {
90 match self {
91 InputKey::VersionedObject { version, .. } => version.is_cancelled(),
92 InputKey::Package { .. } => false,
93 }
94 }
95}
96
97impl From<&Object> for InputKey {
98 fn from(obj: &Object) -> Self {
99 if obj.is_package() {
100 InputKey::Package { id: obj.id() }
101 } else {
102 InputKey::VersionedObject {
103 id: obj.full_id(),
104 version: obj.version(),
105 }
106 }
107 }
108}
109
110#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
111pub enum WriteKind {
112 Mutate,
114 Create,
116 Unwrap,
118}
119
120#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
121pub enum DeleteKind {
122 Normal,
124 UnwrapThenDelete,
127 Wrap,
129}
130
131#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
132pub enum MarkerValue {
133 Received,
136 FastpathStreamEnded,
140 ConsensusStreamEnded(TransactionDigest),
143}
144
145#[derive(Debug)]
152pub enum DeleteKindWithOldVersion {
153 Normal(SequenceNumber),
154 UnwrapThenDeleteDEPRECATED(SequenceNumber),
156 UnwrapThenDelete,
157 Wrap(SequenceNumber),
158}
159
160impl DeleteKindWithOldVersion {
161 pub fn old_version(&self) -> Option<SequenceNumber> {
162 match self {
163 DeleteKindWithOldVersion::Normal(version)
164 | DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(version)
165 | DeleteKindWithOldVersion::Wrap(version) => Some(*version),
166 DeleteKindWithOldVersion::UnwrapThenDelete => None,
167 }
168 }
169
170 pub fn to_delete_kind(&self) -> DeleteKind {
171 match self {
172 DeleteKindWithOldVersion::Normal(_) => DeleteKind::Normal,
173 DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(_)
174 | DeleteKindWithOldVersion::UnwrapThenDelete => DeleteKind::UnwrapThenDelete,
175 DeleteKindWithOldVersion::Wrap(_) => DeleteKind::Wrap,
176 }
177 }
178}
179
180#[derive(Debug)]
181pub enum ObjectChange {
182 Write(Object, WriteKind),
183 Delete(DeleteKindWithOldVersion),
185}
186
187pub trait StorageView: Storage + ParentSync + RuntimeObjectResolver {}
188impl<T: Storage + ParentSync + RuntimeObjectResolver> StorageView for T {}
189
190pub trait RuntimeObjectResolver: BackingPackageStore {
193 fn read_child_object(
195 &self,
196 parent: &ObjectID,
197 child: &ObjectID,
198 child_version_upper_bound: SequenceNumber,
199 ) -> SuiResult<Option<Object>>;
200
201 fn get_object_received_at_version(
207 &self,
208 owner: &ObjectID,
209 receiving_object_id: &ObjectID,
210 receive_object_at_version: SequenceNumber,
211 epoch_id: EpochId,
212 ) -> SuiResult<Option<Object>>;
213
214 fn get_package_at_version(
228 &self,
229 package_id: &ObjectID,
230 package_version: SequenceNumber,
231 ) -> Option<MovePackage> {
232 let move_pkg = self
233 .get_package_object(package_id)
234 .ok()
235 .flatten()?
236 .into_move_package();
237 if move_pkg.version() == package_version {
238 Some(move_pkg)
239 } else {
240 None
241 }
242 }
243}
244
245pub struct DenyListResult {
246 pub result: Result<(), ExecutionError>,
249 pub num_non_gas_coin_owners: u64,
251}
252
253pub trait Storage {
255 fn reset(&mut self);
256
257 fn read_object(&self, id: &ObjectID) -> Option<&Object>;
258
259 fn record_execution_results(&mut self, results: ExecutionResults)
260 -> Result<(), ExecutionError>;
261
262 fn save_loaded_runtime_objects(
263 &mut self,
264 loaded_runtime_objects: BTreeMap<ObjectID, DynamicallyLoadedObjectMetadata>,
265 );
266
267 fn save_wrapped_object_containers(
268 &mut self,
269 wrapped_object_containers: BTreeMap<ObjectID, ObjectID>,
270 );
271
272 fn check_coin_deny_list(
275 &self,
276 receiving_funds_type_and_owners: BTreeMap<TypeTag, BTreeSet<SuiAddress>>,
277 ) -> DenyListResult;
278
279 fn record_generated_object_ids(&mut self, generated_ids: BTreeSet<ObjectID>);
280}
281
282pub type PackageFetchResults<Package> = Result<Vec<Package>, Vec<ObjectID>>;
283
284#[derive(Clone, Debug)]
285pub struct PackageObject {
286 package_object: Object,
287}
288
289impl PackageObject {
290 pub fn new(package_object: Object) -> Self {
291 assert!(package_object.is_package());
292 Self { package_object }
293 }
294
295 pub fn object(&self) -> &Object {
296 &self.package_object
297 }
298
299 pub fn move_package(&self) -> &MovePackage {
300 self.package_object.data.try_as_package().unwrap()
301 }
302
303 pub fn into_move_package(self) -> MovePackage {
304 self.package_object
305 .into_inner()
306 .data
307 .try_into_package()
308 .unwrap()
309 }
310}
311
312impl From<PackageObject> for Object {
313 fn from(package_object_arc: PackageObject) -> Self {
314 package_object_arc.package_object
315 }
316}
317
318pub trait BackingPackageStore {
319 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>>;
320}
321
322impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Box<S> {
323 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
324 BackingPackageStore::get_package_object(self.as_ref(), package_id)
325 }
326}
327
328impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Arc<S> {
329 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
330 BackingPackageStore::get_package_object(self.as_ref(), package_id)
331 }
332}
333
334impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &S {
335 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
336 BackingPackageStore::get_package_object(*self, package_id)
337 }
338}
339
340impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &mut S {
341 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
342 BackingPackageStore::get_package_object(*self, package_id)
343 }
344}
345
346pub struct OverlayBackingPackageStore<'a, S> {
350 overlay: &'a ObjectSet,
351 backing: S,
352}
353
354impl<'a, S> OverlayBackingPackageStore<'a, S> {
355 pub fn new(overlay: &'a ObjectSet, backing: S) -> Self {
356 Self { overlay, backing }
357 }
358}
359
360impl<S: BackingPackageStore> BackingPackageStore for OverlayBackingPackageStore<'_, S> {
361 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
362 for obj in self.overlay.iter() {
364 if &obj.id() == package_id {
365 fp_ensure!(
367 obj.is_package(),
368 SuiErrorKind::BadObjectType {
369 error: format!("Package expected, Move object found: {package_id}"),
370 }
371 .into()
372 );
373 return Ok(Some(PackageObject::new(obj.clone())));
374 }
375 }
376 self.backing.get_package_object(package_id)
378 }
379}
380
381pub fn load_package_object_from_object_store(
382 store: &impl ObjectStore,
383 package_id: &ObjectID,
384) -> SuiResult<Option<PackageObject>> {
385 let package = store.get_object(package_id);
386 if let Some(obj) = &package {
387 fp_ensure!(
388 obj.is_package(),
389 SuiErrorKind::BadObjectType {
390 error: format!("Package expected, Move object found: {package_id}"),
391 }
392 .into()
393 );
394 }
395 Ok(package.map(PackageObject::new))
396}
397
398pub fn get_package_objects<'a>(
402 store: &impl BackingPackageStore,
403 package_ids: impl IntoIterator<Item = &'a ObjectID>,
404) -> SuiResult<PackageFetchResults<PackageObject>> {
405 let packages: Vec<Result<_, _>> = package_ids
406 .into_iter()
407 .map(|id| match store.get_package_object(id) {
408 Ok(None) => Ok(Err(*id)),
409 Ok(Some(o)) => Ok(Ok(o)),
410 Err(x) => Err(x),
411 })
412 .collect::<SuiResult<_>>()?;
413
414 let (fetched, failed_to_fetch): (Vec<_>, Vec<_>) = packages.into_iter().partition_result();
415 if !failed_to_fetch.is_empty() {
416 Ok(Err(failed_to_fetch))
417 } else {
418 Ok(Ok(fetched))
419 }
420}
421
422pub fn get_module(
423 store: impl BackingPackageStore,
424 module_id: &ModuleId,
425) -> Result<Option<Vec<u8>>, SuiError> {
426 Ok(store
427 .get_package_object(&ObjectID::from(*module_id.address()))?
428 .and_then(|package| {
429 package
430 .move_package()
431 .serialized_module_map()
432 .get(module_id.name().as_str())
433 .cloned()
434 }))
435}
436
437pub fn get_package(
438 store: impl BackingPackageStore,
439 id: &ObjectID,
440) -> SuiResult<Option<SerializedPackage>> {
441 store
442 .get_package_object(id)?
443 .map(|package| package.move_package().into_serialized_move_package())
444 .transpose()
445}
446
447pub fn get_module_by_id<S: BackingPackageStore>(
448 store: &S,
449 id: &ModuleId,
450) -> anyhow::Result<Option<CompiledModule>, SuiError> {
451 Ok(get_module(store, id)?
452 .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap()))
453}
454
455pub struct PostExecutionPackageResolver {
460 backing_store: Arc<dyn BackingPackageStore>,
461 new_packages: BTreeMap<ObjectID, PackageObject>,
462}
463
464impl PostExecutionPackageResolver {
465 pub fn new(
466 backing_store: Arc<dyn BackingPackageStore>,
467 output_objects: &Option<Vec<Object>>,
468 ) -> Self {
469 let new_packages = output_objects
470 .iter()
471 .flatten()
472 .filter_map(|o| {
473 if o.is_package() {
474 Some((o.id(), PackageObject::new(o.clone())))
475 } else {
476 None
477 }
478 })
479 .collect();
480 Self {
481 backing_store,
482 new_packages,
483 }
484 }
485}
486
487impl BackingPackageStore for PostExecutionPackageResolver {
488 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
489 if let Some(package) = self.new_packages.get(package_id) {
490 Ok(Some(package.clone()))
491 } else {
492 self.backing_store.get_package_object(package_id)
493 }
494 }
495}
496
497pub trait ParentSync {
498 fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef>;
501}
502
503impl<S: ParentSync> ParentSync for std::sync::Arc<S> {
504 fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
505 ParentSync::get_latest_parent_entry_ref_deprecated(self.as_ref(), object_id)
506 }
507}
508
509impl<S: ParentSync> ParentSync for &S {
510 fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
511 ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id)
512 }
513}
514
515impl<S: ParentSync> ParentSync for &mut S {
516 fn get_latest_parent_entry_ref_deprecated(&self, object_id: ObjectID) -> Option<ObjectRef> {
517 ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id)
518 }
519}
520
521impl<S: RuntimeObjectResolver> RuntimeObjectResolver for std::sync::Arc<S> {
522 fn read_child_object(
523 &self,
524 parent: &ObjectID,
525 child: &ObjectID,
526 child_version_upper_bound: SequenceNumber,
527 ) -> SuiResult<Option<Object>> {
528 RuntimeObjectResolver::read_child_object(
529 self.as_ref(),
530 parent,
531 child,
532 child_version_upper_bound,
533 )
534 }
535 fn get_object_received_at_version(
536 &self,
537 owner: &ObjectID,
538 receiving_object_id: &ObjectID,
539 receive_object_at_version: SequenceNumber,
540 epoch_id: EpochId,
541 ) -> SuiResult<Option<Object>> {
542 RuntimeObjectResolver::get_object_received_at_version(
543 self.as_ref(),
544 owner,
545 receiving_object_id,
546 receive_object_at_version,
547 epoch_id,
548 )
549 }
550}
551
552impl<S: RuntimeObjectResolver> RuntimeObjectResolver for &S {
553 fn read_child_object(
554 &self,
555 parent: &ObjectID,
556 child: &ObjectID,
557 child_version_upper_bound: SequenceNumber,
558 ) -> SuiResult<Option<Object>> {
559 RuntimeObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
560 }
561 fn get_object_received_at_version(
562 &self,
563 owner: &ObjectID,
564 receiving_object_id: &ObjectID,
565 receive_object_at_version: SequenceNumber,
566 epoch_id: EpochId,
567 ) -> SuiResult<Option<Object>> {
568 RuntimeObjectResolver::get_object_received_at_version(
569 *self,
570 owner,
571 receiving_object_id,
572 receive_object_at_version,
573 epoch_id,
574 )
575 }
576}
577
578impl<S: RuntimeObjectResolver> RuntimeObjectResolver for &mut S {
579 fn read_child_object(
580 &self,
581 parent: &ObjectID,
582 child: &ObjectID,
583 child_version_upper_bound: SequenceNumber,
584 ) -> SuiResult<Option<Object>> {
585 RuntimeObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
586 }
587 fn get_object_received_at_version(
588 &self,
589 owner: &ObjectID,
590 receiving_object_id: &ObjectID,
591 receive_object_at_version: SequenceNumber,
592 epoch_id: EpochId,
593 ) -> SuiResult<Option<Object>> {
594 RuntimeObjectResolver::get_object_received_at_version(
595 *self,
596 owner,
597 receiving_object_id,
598 receive_object_at_version,
599 epoch_id,
600 )
601 }
602}
603
604#[serde_as]
605#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
606pub struct ObjectKey(pub ObjectID, pub VersionNumber);
607
608impl ObjectKey {
609 pub const ZERO: ObjectKey = ObjectKey(ObjectID::ZERO, VersionNumber::MIN);
610
611 pub fn max_for_id(id: &ObjectID) -> Self {
612 Self(*id, VersionNumber::MAX)
613 }
614
615 pub fn min_for_id(id: &ObjectID) -> Self {
616 Self(*id, VersionNumber::MIN)
617 }
618}
619
620impl From<ObjectRef> for ObjectKey {
621 fn from(object_ref: ObjectRef) -> Self {
622 ObjectKey::from(&object_ref)
623 }
624}
625
626impl From<&ObjectRef> for ObjectKey {
627 fn from(object_ref: &ObjectRef) -> Self {
628 Self(object_ref.0, object_ref.1)
629 }
630}
631
632#[serde_as]
633#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
634pub struct ConsensusObjectKey(pub ConsensusObjectSequenceKey, pub VersionNumber);
635
636#[serde_as]
640#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
641pub enum FullObjectKey {
642 Fastpath(ObjectKey),
643 Consensus(ConsensusObjectKey),
644}
645
646impl FullObjectKey {
647 pub fn max_for_id(id: &FullObjectID) -> Self {
648 match id {
649 FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey::max_for_id(object_id)),
650 FullObjectID::Consensus(consensus_object_sequence_key) => Self::Consensus(
651 ConsensusObjectKey(*consensus_object_sequence_key, VersionNumber::MAX),
652 ),
653 }
654 }
655
656 pub fn min_for_id(id: &FullObjectID) -> Self {
657 match id {
658 FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey::min_for_id(object_id)),
659 FullObjectID::Consensus(consensus_object_sequence_key) => Self::Consensus(
660 ConsensusObjectKey(*consensus_object_sequence_key, VersionNumber::MIN),
661 ),
662 }
663 }
664
665 pub fn new(object_id: FullObjectID, version: VersionNumber) -> Self {
666 match object_id {
667 FullObjectID::Fastpath(object_id) => Self::Fastpath(ObjectKey(object_id, version)),
668 FullObjectID::Consensus(consensus_object_sequence_key) => {
669 Self::Consensus(ConsensusObjectKey(consensus_object_sequence_key, version))
670 }
671 }
672 }
673
674 pub fn id(&self) -> FullObjectID {
675 match self {
676 FullObjectKey::Fastpath(object_key) => FullObjectID::Fastpath(object_key.0),
677 FullObjectKey::Consensus(consensus_object_key) => {
678 FullObjectID::Consensus(consensus_object_key.0)
679 }
680 }
681 }
682
683 pub fn version(&self) -> VersionNumber {
684 match self {
685 FullObjectKey::Fastpath(object_key) => object_key.1,
686 FullObjectKey::Consensus(consensus_object_key) => consensus_object_key.1,
687 }
688 }
689}
690
691impl From<FullObjectRef> for FullObjectKey {
692 fn from(object_ref: FullObjectRef) -> Self {
693 FullObjectKey::from(&object_ref)
694 }
695}
696
697impl From<&FullObjectRef> for FullObjectKey {
698 fn from(object_ref: &FullObjectRef) -> Self {
699 FullObjectKey::new(object_ref.0, object_ref.1)
700 }
701}
702
703#[derive(Clone)]
704pub enum ObjectOrTombstone {
705 Object(Object),
706 Tombstone(ObjectRef),
707}
708
709impl ObjectOrTombstone {
710 pub fn as_objref(&self) -> ObjectRef {
711 match self {
712 ObjectOrTombstone::Object(obj) => obj.compute_object_reference(),
713 ObjectOrTombstone::Tombstone(obref) => *obref,
714 }
715 }
716}
717
718impl From<Object> for ObjectOrTombstone {
719 fn from(object: Object) -> Self {
720 ObjectOrTombstone::Object(object)
721 }
722}
723
724pub fn transaction_non_shared_input_object_keys(
727 tx: &SenderSignedData,
728) -> SuiResult<Vec<ObjectKey>> {
729 use crate::transaction::InputObjectKind as I;
730 Ok(tx
731 .intent_message()
732 .value
733 .input_objects()?
734 .into_iter()
735 .filter_map(|object| match object {
736 I::MovePackage(_) | I::SharedMoveObject { .. } => None,
737 I::ImmOrOwnedMoveObject(obj) => Some(obj.into()),
738 })
739 .collect())
740}
741
742pub fn transaction_receiving_object_keys(tx: &SenderSignedData) -> Vec<ObjectKey> {
743 tx.intent_message()
744 .value
745 .receiving_objects()
746 .into_iter()
747 .map(|oref| oref.into())
748 .collect()
749}
750
751impl Display for DeleteKind {
752 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
753 match self {
754 DeleteKind::Wrap => write!(f, "Wrap"),
755 DeleteKind::Normal => write!(f, "Normal"),
756 DeleteKind::UnwrapThenDelete => write!(f, "UnwrapThenDelete"),
757 }
758 }
759}
760
761pub trait BackingStore: RuntimeObjectResolver + ObjectStore + ParentSync {}
762
763impl<T> BackingStore for T
764where
765 T: RuntimeObjectResolver,
766 T: ObjectStore,
767 T: ParentSync,
768{
769}
770
771pub fn get_transaction_input_objects(
772 object_store: &dyn ObjectStore,
773 effects: &TransactionEffects,
774) -> Result<Vec<Object>, StorageError> {
775 let input_object_keys = effects
776 .modified_at_versions()
777 .into_iter()
778 .map(|(object_id, version)| ObjectKey(object_id, version))
779 .collect::<Vec<_>>();
780
781 let input_objects = object_store
782 .multi_get_objects_by_key(&input_object_keys)
783 .into_iter()
784 .enumerate()
785 .map(|(idx, maybe_object)| {
786 maybe_object.ok_or_else(|| {
787 StorageError::custom(format!(
788 "missing input object key {:?} from tx {} effects {}",
789 input_object_keys[idx],
790 effects.transaction_digest(),
791 effects.digest()
792 ))
793 })
794 })
795 .collect::<Result<Vec<_>, _>>()?;
796 Ok(input_objects)
797}
798
799pub fn get_transaction_output_objects(
800 object_store: &dyn ObjectStore,
801 effects: &TransactionEffects,
802) -> Result<Vec<Object>, StorageError> {
803 let output_object_keys = effects
804 .all_changed_objects()
805 .into_iter()
806 .map(|(object_ref, _owner, _kind)| ObjectKey::from(object_ref))
807 .collect::<Vec<_>>();
808
809 let output_objects = object_store
810 .multi_get_objects_by_key(&output_object_keys)
811 .into_iter()
812 .enumerate()
813 .map(|(idx, maybe_object)| {
814 maybe_object.ok_or_else(|| {
815 StorageError::custom(format!(
816 "missing output object key {:?} from tx {} effects {}",
817 output_object_keys[idx],
818 effects.transaction_digest(),
819 effects.digest()
820 ))
821 })
822 })
823 .collect::<Result<Vec<_>, _>>()?;
824 Ok(output_objects)
825}
826
827impl SystemObjectVersions {
828 pub fn from_effects(effects: &TransactionEffects, store: &dyn ObjectStore) -> Self {
830 let accumulator_version = effects
831 .accessed_consensus_objects()
832 .into_iter()
833 .find_map(|ico| match ico {
834 InputConsensusObject::Mutate((id, version, _))
835 | InputConsensusObject::ReadOnly((id, version, _))
836 if id == SUI_ACCUMULATOR_ROOT_OBJECT_ID =>
837 {
838 Some(version)
839 }
840 _ => None,
841 })
842 .map(|version| {
843 let initial_shared_version = store
844 .get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)
845 .and_then(|object| object.owner().start_version())
846 .unwrap();
849 ConsensusObjectVersion {
850 initial_shared_version,
851 version,
852 }
853 });
854 Self::new(accumulator_version)
855 }
856
857 pub fn from_latest_in_store(store: &dyn ObjectStore) -> Self {
861 let accumulator_version = store
862 .get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)
863 .map(|object| {
864 let initial_shared_version = object
865 .owner()
866 .start_version()
867 .expect("accumulator root must be a consensus object");
868 ConsensusObjectVersion {
869 initial_shared_version,
870 version: object.version(),
871 }
872 });
873 Self::new(accumulator_version)
874 }
875}
876
877pub fn get_transaction_object_set(
879 transaction: &TransactionData,
880 effects: &TransactionEffects,
881 unchanged_loaded_runtime_objects: &[ObjectKey],
882) -> BTreeSet<ObjectKey> {
883 let input_objects = transaction
888 .input_objects()
889 .expect("txn was executed and must have valid input objects")
890 .into_iter()
891 .filter_map(|input| {
892 input
893 .version()
894 .map(|version| ObjectKey(input.object_id(), version))
895 });
896
897 let modified_set = effects
899 .object_changes()
900 .into_iter()
901 .flat_map(|change| {
902 [
903 change
904 .input_version
905 .map(|version| ObjectKey(change.id, version)),
906 change
907 .output_version
908 .map(|version| ObjectKey(change.id, version)),
909 ]
910 })
911 .flatten();
912
913 let unchanged_consensus =
915 effects
916 .unchanged_consensus_objects()
917 .into_iter()
918 .flat_map(|unchanged| {
919 if let crate::effects::UnchangedConsensusKind::ReadOnlyRoot((version, _)) =
920 unchanged.1
921 {
922 Some(ObjectKey(unchanged.0, version))
923 } else {
924 None
925 }
926 });
927
928 input_objects
929 .chain(modified_set)
930 .chain(unchanged_consensus)
931 .chain(unchanged_loaded_runtime_objects.iter().copied())
932 .collect()
933}
934
935pub struct TrackingBackingStore<'a> {
940 inner: &'a dyn crate::storage::BackingStore,
941 read_objects: std::cell::RefCell<ObjectSet>,
942}
943
944impl<'a> TrackingBackingStore<'a> {
945 pub fn new(inner: &'a dyn crate::storage::BackingStore) -> Self {
946 Self {
947 inner,
948 read_objects: Default::default(),
949 }
950 }
951
952 pub fn into_read_objects(self) -> ObjectSet {
953 self.read_objects.into_inner()
954 }
955
956 fn track_object(&self, object: &Object) {
957 self.read_objects.borrow_mut().insert(object.clone());
958 }
959}
960
961impl BackingPackageStore for TrackingBackingStore<'_> {
962 fn get_package_object(
963 &self,
964 package_id: &ObjectID,
965 ) -> crate::error::SuiResult<Option<PackageObject>> {
966 self.inner.get_package_object(package_id).inspect(|o| {
967 o.as_ref()
968 .inspect(|package| self.track_object(package.object()));
969 })
970 }
971}
972
973impl RuntimeObjectResolver for TrackingBackingStore<'_> {
974 fn read_child_object(
975 &self,
976 parent: &ObjectID,
977 child: &ObjectID,
978 child_version_upper_bound: SequenceNumber,
979 ) -> crate::error::SuiResult<Option<Object>> {
980 self.inner
981 .read_child_object(parent, child, child_version_upper_bound)
982 .inspect(|o| {
983 o.as_ref().inspect(|object| self.track_object(object));
984 })
985 }
986
987 fn get_object_received_at_version(
988 &self,
989 owner: &ObjectID,
990 receiving_object_id: &ObjectID,
991 receive_object_at_version: SequenceNumber,
992 epoch_id: crate::committee::EpochId,
993 ) -> crate::error::SuiResult<Option<Object>> {
994 self.inner
995 .get_object_received_at_version(
996 owner,
997 receiving_object_id,
998 receive_object_at_version,
999 epoch_id,
1000 )
1001 .inspect(|o| {
1002 o.as_ref().inspect(|object| self.track_object(object));
1003 })
1004 }
1005}
1006
1007impl crate::storage::ObjectStore for TrackingBackingStore<'_> {
1008 fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
1009 self.inner
1010 .get_object(object_id)
1011 .inspect(|o| self.track_object(o))
1012 }
1013
1014 fn load_implicitly_read_system_object(
1015 &self,
1016 object_id: &ObjectID,
1017 version: crate::base_types::ConsensusObjectVersion,
1018 ) -> Option<Object> {
1019 self.inner
1020 .load_implicitly_read_system_object(object_id, version)
1021 }
1022
1023 fn get_object_by_key(
1024 &self,
1025 object_id: &ObjectID,
1026 version: crate::base_types::VersionNumber,
1027 ) -> Option<Object> {
1028 self.inner
1029 .get_object_by_key(object_id, version)
1030 .inspect(|o| self.track_object(o))
1031 }
1032}
1033
1034impl ParentSync for TrackingBackingStore<'_> {
1035 fn get_latest_parent_entry_ref_deprecated(
1036 &self,
1037 object_id: ObjectID,
1038 ) -> Option<crate::base_types::ObjectRef> {
1039 self.inner.get_latest_parent_entry_ref_deprecated(object_id)
1040 }
1041}