1use crate::accumulators::funds_read::AccountFundsRead;
5use crate::authority::AuthorityStore;
6use crate::authority::authority_per_epoch_store::AuthorityPerEpochStore;
7use crate::authority::authority_store::ExecutionLockWriteGuard;
8#[cfg(test)]
9use crate::authority::authority_store::SuiLockResult;
10use crate::authority::backpressure::BackpressureManager;
11use crate::authority::epoch_start_configuration::EpochFlag;
12use crate::authority::epoch_start_configuration::EpochStartConfiguration;
13use crate::global_state_hasher::GlobalStateHashStore;
14use crate::transaction_outputs::TransactionOutputs;
15use either::Either;
16use itertools::Itertools;
17use mysten_common::ZipDebugEqIteratorExt;
18use sui_types::accumulator_event::AccumulatorEvent;
19use sui_types::bridge::Bridge;
20
21use futures::{FutureExt, future::BoxFuture};
22use prometheus::Registry;
23use std::collections::HashSet;
24use std::path::Path;
25use std::sync::Arc;
26use sui_config::ExecutionCacheConfig;
27use sui_protocol_config::ProtocolVersion;
28use sui_types::base_types::{FullObjectID, VerifiedExecutionData};
29use sui_types::digests::{TransactionDigest, TransactionEffectsDigest};
30use sui_types::effects::{TransactionEffects, TransactionEvents};
31use sui_types::error::{SuiError, SuiErrorKind, SuiResult, UserInputError};
32use sui_types::executable_transaction::VerifiedExecutableTransaction;
33use sui_types::messages_checkpoint::CheckpointSequenceNumber;
34use sui_types::object::Object;
35use sui_types::storage::{
36 BackingPackageStore, BackingStore, FullObjectKey, MarkerValue, ObjectKey, ObjectOrTombstone,
37 ObjectStore, PackageObject, ParentSync, RuntimeObjectResolver,
38};
39use sui_types::sui_system_state::SuiSystemState;
40use sui_types::transaction::VerifiedTransaction;
41use sui_types::{
42 base_types::{EpochId, ObjectID, ObjectRef, SequenceNumber},
43 object::Owner,
44 storage::InputKey,
45};
46use typed_store::rocks::DBBatch;
47
48pub(crate) mod cache_types;
49pub mod metrics;
50mod object_locks;
51pub mod writeback_cache;
52
53pub use writeback_cache::WritebackCache;
54
55use metrics::ExecutionCacheMetrics;
56
57#[derive(Clone)]
62pub struct ExecutionCacheTraitPointers {
63 pub object_cache_reader: Arc<dyn ObjectCacheRead>,
64 pub transaction_cache_reader: Arc<dyn TransactionCacheRead>,
65 pub cache_writer: Arc<dyn ExecutionCacheWrite>,
66 pub backing_store: Arc<dyn BackingStore + Send + Sync>,
67 pub runtime_object_resolver: Arc<dyn RuntimeObjectResolver + Send + Sync>,
68 pub backing_package_store: Arc<dyn BackingPackageStore + Send + Sync>,
69 pub object_store: Arc<dyn ObjectStore + Send + Sync>,
70 pub reconfig_api: Arc<dyn ExecutionCacheReconfigAPI>,
71 pub global_state_hash_store: Arc<dyn GlobalStateHashStore>,
72 pub checkpoint_cache: Arc<dyn CheckpointCache>,
73 pub state_sync_store: Arc<dyn StateSyncAPI>,
74 pub cache_commit: Arc<dyn ExecutionCacheCommit>,
75 pub testing_api: Arc<dyn TestingAPI>,
76 pub account_funds_read: Arc<dyn AccountFundsRead>,
77}
78
79impl ExecutionCacheTraitPointers {
80 pub fn new<T>(cache: Arc<T>) -> Self
81 where
82 T: ObjectCacheRead
83 + TransactionCacheRead
84 + ExecutionCacheWrite
85 + BackingStore
86 + ExecutionCacheReconfigAPI
87 + GlobalStateHashStore
88 + CheckpointCache
89 + StateSyncAPI
90 + ExecutionCacheCommit
91 + TestingAPI
92 + AccountFundsRead
93 + 'static,
94 {
95 Self {
96 object_cache_reader: cache.clone(),
97 transaction_cache_reader: cache.clone(),
98 cache_writer: cache.clone(),
99 backing_store: cache.clone(),
100 runtime_object_resolver: cache.clone(),
101 backing_package_store: cache.clone(),
102 object_store: cache.clone(),
103 reconfig_api: cache.clone(),
104 global_state_hash_store: cache.clone(),
105 checkpoint_cache: cache.clone(),
106 state_sync_store: cache.clone(),
107 cache_commit: cache.clone(),
108 testing_api: cache.clone(),
109 account_funds_read: cache.clone(),
110 }
111 }
112}
113
114pub fn build_execution_cache(
115 cache_config: &ExecutionCacheConfig,
116 prometheus_registry: &Registry,
117 store: &Arc<AuthorityStore>,
118 backpressure_manager: Arc<BackpressureManager>,
119) -> ExecutionCacheTraitPointers {
120 let execution_cache_metrics = Arc::new(ExecutionCacheMetrics::new(prometheus_registry));
121
122 ExecutionCacheTraitPointers::new(
123 WritebackCache::new(
124 cache_config,
125 store.clone(),
126 execution_cache_metrics,
127 backpressure_manager,
128 )
129 .into(),
130 )
131}
132
133pub fn build_execution_cache_from_env(
136 prometheus_registry: &Registry,
137 store: &Arc<AuthorityStore>,
138) -> ExecutionCacheTraitPointers {
139 let execution_cache_metrics = Arc::new(ExecutionCacheMetrics::new(prometheus_registry));
140
141 ExecutionCacheTraitPointers::new(
142 WritebackCache::new(
143 &Default::default(),
144 store.clone(),
145 execution_cache_metrics,
146 BackpressureManager::new_for_tests(),
147 )
148 .into(),
149 )
150}
151
152pub type Batch = (Vec<Arc<TransactionOutputs>>, DBBatch);
153
154pub trait ExecutionCacheCommit: Send + Sync {
155 fn build_db_batch(&self, epoch: EpochId, digests: &[TransactionDigest]) -> Batch;
157
158 fn set_highest_committed_checkpoint_in_batch(
165 &self,
166 batch: &mut Batch,
167 checkpoint: CheckpointSequenceNumber,
168 );
169
170 fn commit_transaction_outputs(
174 &self,
175 epoch: EpochId,
176 batch: Batch,
177 digests: &[TransactionDigest],
178 );
179
180 fn persist_transaction(&self, transaction: &VerifiedExecutableTransaction);
184
185 fn approximate_pending_transaction_count(&self) -> u64;
187}
188
189pub trait ObjectCacheRead: Send + Sync {
190 fn get_package_object(&self, id: &ObjectID) -> SuiResult<Option<PackageObject>>;
191 fn force_reload_system_packages(&self, system_package_ids: &[ObjectID]);
192
193 fn get_object(&self, id: &ObjectID) -> Option<Object>;
194
195 fn get_objects(&self, objects: &[ObjectID]) -> Vec<Option<Object>> {
196 let mut ret = Vec::with_capacity(objects.len());
197 for object_id in objects {
198 ret.push(self.get_object(object_id));
199 }
200 ret
201 }
202
203 fn get_latest_object_ref_or_tombstone(&self, object_id: ObjectID) -> Option<ObjectRef>;
204
205 fn get_latest_object_or_tombstone(
206 &self,
207 object_id: ObjectID,
208 ) -> Option<(ObjectKey, ObjectOrTombstone)>;
209
210 fn get_object_by_key(&self, object_id: &ObjectID, version: SequenceNumber) -> Option<Object>;
211
212 fn multi_get_objects_by_key(&self, object_keys: &[ObjectKey]) -> Vec<Option<Object>>;
213
214 fn object_exists_by_key(&self, object_id: &ObjectID, version: SequenceNumber) -> bool;
215
216 fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> Vec<bool>;
217
218 fn multi_get_objects_with_more_accurate_error_return(
226 &self,
227 object_refs: &[ObjectRef],
228 ) -> Result<Vec<Object>, SuiError> {
229 let objects = self
230 .multi_get_objects_by_key(&object_refs.iter().map(ObjectKey::from).collect::<Vec<_>>());
231 let mut result = Vec::new();
232 for (object_opt, object_ref) in objects.into_iter().zip_debug_eq(object_refs) {
233 match object_opt {
234 None => {
235 let live_objref = self._get_live_objref(object_ref.0)?;
236 let error = if live_objref.1 >= object_ref.1 {
237 UserInputError::ObjectVersionUnavailableForConsumption {
238 provided_obj_ref: *object_ref,
239 current_version: live_objref.1,
240 }
241 } else {
242 UserInputError::ObjectNotFound {
243 object_id: object_ref.0,
244 version: Some(object_ref.1),
245 }
246 };
247 return Err(SuiErrorKind::UserInputError { error }.into());
248 }
249 Some(object) => {
250 result.push(object);
251 }
252 }
253 }
254 assert_eq!(result.len(), object_refs.len());
255 Ok(result)
256 }
257
258 fn multi_input_objects_available(
262 &self,
263 keys: &[InputKey],
264 receiving_objects: &HashSet<InputKey>,
265 epoch: EpochId,
266 ) -> Vec<bool> {
267 let mut results = vec![false; keys.len()];
268 let non_canceled_keys = keys.iter().enumerate().filter(|(idx, key)| {
269 if key.is_cancelled() {
270 results[*idx] = true;
272 false
273 } else {
274 true
275 }
276 });
277 let (move_object_keys, package_object_keys): (Vec<_>, Vec<_>) = non_canceled_keys
278 .partition_map(|(idx, key)| match key {
279 InputKey::VersionedObject { id, version } => Either::Left((idx, (id, version))),
280 InputKey::Package { id } => Either::Right((idx, id)),
281 });
282
283 for ((idx, (id, version)), has_key) in move_object_keys.iter().zip_debug_eq(
284 self.multi_object_exists_by_key(
285 &move_object_keys
286 .iter()
287 .map(|(_, k)| ObjectKey(k.0.id(), *k.1))
288 .collect::<Vec<_>>(),
289 ),
290 ) {
291 if has_key {
293 results[*idx] = true;
294 } else if receiving_objects.contains(&InputKey::VersionedObject {
295 id: **id,
296 version: **version,
297 }) {
298 let is_available = self
305 .get_object(&id.id())
306 .map(|obj| obj.version() >= **version)
307 .unwrap_or(false)
308 || self.fastpath_stream_ended_at_version_or_after(id.id(), **version, epoch);
309 results[*idx] = is_available;
310 } else {
311 let is_consensus_stream_ended = self
314 .get_consensus_stream_end_tx_digest(FullObjectKey::new(**id, **version), epoch)
315 .is_some();
316 results[*idx] = is_consensus_stream_ended;
317 }
318 }
319
320 package_object_keys.into_iter().for_each(|(idx, id)| {
321 results[idx] = self.get_package_object(id).is_ok_and(|p| p.is_some());
324 });
325
326 results
327 }
328
329 fn multi_input_objects_available_cache_only(&self, keys: &[InputKey]) -> Vec<bool>;
330
331 fn find_object_lt_or_eq_version(
336 &self,
337 object_id: ObjectID,
338 version: SequenceNumber,
339 ) -> Option<Object>;
340
341 #[cfg(test)]
343 fn get_lock(&self, obj_ref: ObjectRef, epoch_store: &AuthorityPerEpochStore) -> SuiLockResult;
344
345 fn _get_live_objref(&self, object_id: ObjectID) -> SuiResult<ObjectRef>;
347
348 fn get_sui_system_state_object_unsafe(&self) -> SuiResult<SuiSystemState>;
349
350 fn get_bridge_object_unsafe(&self) -> SuiResult<Bridge>;
351
352 fn get_marker_value(&self, object_key: FullObjectKey, epoch_id: EpochId)
356 -> Option<MarkerValue>;
357
358 fn get_latest_marker(
360 &self,
361 object_id: FullObjectID,
362 epoch_id: EpochId,
363 ) -> Option<(SequenceNumber, MarkerValue)>;
364
365 fn get_last_consensus_stream_end_info(
368 &self,
369 object_id: FullObjectID,
370 epoch_id: EpochId,
371 ) -> Option<(SequenceNumber, TransactionDigest)> {
372 match self.get_latest_marker(object_id, epoch_id) {
373 Some((version, MarkerValue::ConsensusStreamEnded(digest))) => Some((version, digest)),
374 _ => None,
375 }
376 }
377
378 fn get_consensus_stream_end_tx_digest(
381 &self,
382 object_key: FullObjectKey,
383 epoch_id: EpochId,
384 ) -> Option<TransactionDigest> {
385 match self.get_marker_value(object_key, epoch_id) {
386 Some(MarkerValue::ConsensusStreamEnded(digest)) => Some(digest),
387 _ => None,
388 }
389 }
390
391 fn have_received_object_at_version(
392 &self,
393 object_key: FullObjectKey,
394 epoch_id: EpochId,
395 ) -> bool {
396 matches!(
397 self.get_marker_value(object_key, epoch_id),
398 Some(MarkerValue::Received)
399 )
400 }
401
402 fn fastpath_stream_ended_at_version_or_after(
403 &self,
404 object_id: ObjectID,
405 version: SequenceNumber,
406 epoch_id: EpochId,
407 ) -> bool {
408 let full_id = FullObjectID::Fastpath(object_id); matches!(
410 self.get_latest_marker(full_id, epoch_id),
411 Some((marker_version, MarkerValue::FastpathStreamEnded)) if marker_version >= version
412 )
413 }
414
415 fn get_highest_pruned_checkpoint(&self) -> Option<CheckpointSequenceNumber>;
417
418 fn notify_read_input_objects<'a>(
426 &'a self,
427 input_and_receiving_keys: &'a [InputKey],
428 receiving_keys: &'a HashSet<InputKey>,
429 epoch: EpochId,
430 ) -> BoxFuture<'a, ()>;
431}
432
433pub trait TransactionCacheRead: Send + Sync {
434 fn multi_get_transaction_blocks(
435 &self,
436 digests: &[TransactionDigest],
437 ) -> Vec<Option<Arc<VerifiedTransaction>>>;
438
439 fn get_transaction_block(
440 &self,
441 digest: &TransactionDigest,
442 ) -> Option<Arc<VerifiedTransaction>> {
443 self.multi_get_transaction_blocks(&[*digest])
444 .pop()
445 .expect("multi-get must return correct number of items")
446 }
447
448 fn multi_get_executed_effects_digests(
449 &self,
450 digests: &[TransactionDigest],
451 ) -> Vec<Option<TransactionEffectsDigest>>;
452
453 fn is_tx_already_executed(&self, digest: &TransactionDigest) -> bool {
454 self.multi_get_executed_effects_digests(&[*digest])
455 .pop()
456 .expect("multi-get must return correct number of items")
457 .is_some()
458 }
459
460 fn multi_get_executed_effects(
461 &self,
462 digests: &[TransactionDigest],
463 ) -> Vec<Option<TransactionEffects>> {
464 let effects_digests = self.multi_get_executed_effects_digests(digests);
465 assert_eq!(effects_digests.len(), digests.len());
466
467 let mut results = vec![None; digests.len()];
468 let mut fetch_digests = Vec::with_capacity(digests.len());
469 let mut fetch_indices = Vec::with_capacity(digests.len());
470
471 for (i, digest) in effects_digests.into_iter().enumerate() {
472 if let Some(digest) = digest {
473 fetch_digests.push(digest);
474 fetch_indices.push(i);
475 }
476 }
477
478 let effects = self.multi_get_effects(&fetch_digests);
479 for (i, effects) in fetch_indices.into_iter().zip_debug_eq(effects) {
480 results[i] = effects;
481 }
482
483 results
484 }
485
486 fn get_executed_effects(&self, digest: &TransactionDigest) -> Option<TransactionEffects> {
487 self.multi_get_executed_effects(&[*digest])
488 .pop()
489 .expect("multi-get must return correct number of items")
490 }
491
492 fn transaction_executed_in_last_epoch(
493 &self,
494 digest: &TransactionDigest,
495 current_epoch: EpochId,
496 ) -> bool;
497
498 fn multi_get_effects(
499 &self,
500 digests: &[TransactionEffectsDigest],
501 ) -> Vec<Option<TransactionEffects>>;
502
503 fn get_effects(&self, digest: &TransactionEffectsDigest) -> Option<TransactionEffects> {
504 self.multi_get_effects(&[*digest])
505 .pop()
506 .expect("multi-get must return correct number of items")
507 }
508
509 fn multi_get_events(&self, digests: &[TransactionDigest]) -> Vec<Option<TransactionEvents>>;
510
511 fn get_events(&self, digest: &TransactionDigest) -> Option<TransactionEvents> {
512 self.multi_get_events(&[*digest])
513 .pop()
514 .expect("multi-get must return correct number of items")
515 }
516
517 fn get_unchanged_loaded_runtime_objects(
518 &self,
519 digest: &TransactionDigest,
520 ) -> Option<Vec<ObjectKey>>;
521
522 fn multi_get_unchanged_loaded_runtime_objects(
523 &self,
524 digests: &[TransactionDigest],
525 ) -> Vec<Option<Vec<ObjectKey>>> {
526 digests
527 .iter()
528 .map(|digest| self.get_unchanged_loaded_runtime_objects(digest))
529 .collect()
530 }
531
532 fn take_accumulator_events(&self, digest: &TransactionDigest) -> Option<Vec<AccumulatorEvent>>;
533
534 fn notify_read_executed_effects_digests<'a>(
535 &'a self,
536 task_name: &'static str,
537 digests: &'a [TransactionDigest],
538 ) -> BoxFuture<'a, Vec<TransactionEffectsDigest>>;
539
540 fn notify_read_executed_effects<'a>(
553 &'a self,
554 task_name: &'static str,
555 digests: &'a [TransactionDigest],
556 ) -> BoxFuture<'a, Vec<TransactionEffects>> {
557 async move {
558 self.notify_read_executed_effects_may_fail(task_name, digests)
559 .await
560 .unwrap_or_else(|e| panic!("effects must exist: {e}"))
561 }
562 .boxed()
563 }
564
565 fn notify_read_executed_effects_may_fail<'a>(
570 &'a self,
571 task_name: &'static str,
572 digests: &'a [TransactionDigest],
573 ) -> BoxFuture<'a, SuiResult<Vec<TransactionEffects>>> {
574 async move {
575 let effects_digests = self
576 .notify_read_executed_effects_digests(task_name, digests)
577 .await;
578 self.multi_get_effects(&effects_digests)
579 .into_iter()
580 .zip_debug_eq(digests)
581 .map(|(e, digest)| {
582 e.ok_or_else(|| {
583 SuiError::from(SuiErrorKind::TransactionEffectsNotFound { digest: *digest })
584 })
585 })
586 .collect()
587 }
588 .boxed()
589 }
590}
591
592pub trait ExecutionCacheWrite: Send + Sync {
593 fn write_transaction_outputs(&self, epoch_id: EpochId, tx_outputs: Arc<TransactionOutputs>);
611
612 fn validate_owned_object_versions(&self, owned_input_objects: &[ObjectRef]) -> SuiResult;
615
616 #[cfg(test)]
620 fn write_object_entry_for_test(&self, object: Object);
621}
622
623pub trait CheckpointCache: Send + Sync {
624 fn deprecated_get_transaction_checkpoint(
629 &self,
630 digest: &TransactionDigest,
631 ) -> Option<(EpochId, CheckpointSequenceNumber)>;
632
633 fn deprecated_multi_get_transaction_checkpoint(
634 &self,
635 digests: &[TransactionDigest],
636 ) -> Vec<Option<(EpochId, CheckpointSequenceNumber)>>;
637
638 fn deprecated_insert_finalized_transactions(
639 &self,
640 digests: &[TransactionDigest],
641 epoch: EpochId,
642 sequence: CheckpointSequenceNumber,
643 );
644}
645
646pub trait ExecutionCacheReconfigAPI: Send + Sync {
647 fn insert_genesis_object(&self, object: Object);
648 fn bulk_insert_genesis_objects(&self, objects: &[Object]);
649
650 fn set_epoch_start_configuration(&self, epoch_start_config: &EpochStartConfiguration);
651
652 fn update_epoch_flags_metrics(&self, old: &[EpochFlag], new: &[EpochFlag]);
653
654 fn clear_state_end_of_epoch(&self, execution_guard: &ExecutionLockWriteGuard<'_>);
655
656 fn expensive_check_sui_conservation(
657 &self,
658 old_epoch_store: &AuthorityPerEpochStore,
659 ) -> SuiResult;
660
661 fn checkpoint_db(&self, path: &Path) -> SuiResult;
662
663 fn maybe_reaccumulate_state_hash(
666 &self,
667 cur_epoch_store: &AuthorityPerEpochStore,
668 new_protocol_version: ProtocolVersion,
669 );
670
671 fn reconfigure_cache<'a>(
675 &'a self,
676 epoch_start_config: &'a EpochStartConfiguration,
677 ) -> BoxFuture<'a, ()>;
678}
679
680pub trait StateSyncAPI: Send + Sync {
684 fn insert_transaction_and_effects(
685 &self,
686 transaction: &VerifiedTransaction,
687 transaction_effects: &TransactionEffects,
688 );
689
690 fn multi_insert_transaction_and_effects(
691 &self,
692 transactions_and_effects: &[VerifiedExecutionData],
693 );
694}
695
696pub trait TestingAPI: Send + Sync {
697 fn database_for_testing(&self) -> Arc<AuthorityStore>;
698
699 fn cache_for_testing(&self) -> &WritebackCache;
700}
701
702macro_rules! implement_storage_traits {
703 ($implementor: ident) => {
704 impl ObjectStore for $implementor {
705 fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
706 ObjectCacheRead::get_object(self, object_id)
707 }
708
709 fn get_object_by_key(
710 &self,
711 object_id: &ObjectID,
712 version: sui_types::base_types::VersionNumber,
713 ) -> Option<Object> {
714 ObjectCacheRead::get_object_by_key(self, object_id, version)
715 }
716
717 fn load_implicitly_read_system_object(
718 &self,
719 object_id: &ObjectID,
720 version: sui_types::base_types::ConsensusObjectVersion,
721 ) -> Option<Object> {
722 $implementor::load_implicitly_read_system_object(self, object_id, version)
723 }
724 }
725
726 impl RuntimeObjectResolver for $implementor {
727 fn read_child_object(
728 &self,
729 parent: &ObjectID,
730 child: &ObjectID,
731 child_version_upper_bound: SequenceNumber,
732 ) -> SuiResult<Option<Object>> {
733 let Some(child_object) =
734 self.find_object_lt_or_eq_version(*child, child_version_upper_bound)
735 else {
736 return Ok(None);
737 };
738
739 let parent = *parent;
740 if child_object.owner != Owner::ObjectOwner(parent.into()) {
741 return Err(SuiErrorKind::InvalidChildObjectAccess {
742 object: *child,
743 given_parent: parent,
744 actual_owner: child_object.owner.clone(),
745 }
746 .into());
747 }
748 Ok(Some(child_object))
749 }
750
751 fn get_object_received_at_version(
752 &self,
753 owner: &ObjectID,
754 receiving_object_id: &ObjectID,
755 receive_object_at_version: SequenceNumber,
756 epoch_id: EpochId,
757 ) -> SuiResult<Option<Object>> {
758 let Some(recv_object) = ObjectCacheRead::get_object_by_key(
759 self,
760 receiving_object_id,
761 receive_object_at_version,
762 ) else {
763 return Ok(None);
764 };
765
766 if recv_object.owner != Owner::AddressOwner((*owner).into())
772 || self.have_received_object_at_version(
773 FullObjectKey::new(
775 FullObjectID::new(*receiving_object_id, None),
776 receive_object_at_version,
777 ),
778 epoch_id,
779 )
780 {
781 return Ok(None);
782 }
783
784 Ok(Some(recv_object))
785 }
786 }
787
788 impl BackingPackageStore for $implementor {
789 fn get_package_object(
790 &self,
791 package_id: &ObjectID,
792 ) -> SuiResult<Option<PackageObject>> {
793 ObjectCacheRead::get_package_object(self, package_id)
794 }
795 }
796
797 impl ParentSync for $implementor {
798 fn get_latest_parent_entry_ref_deprecated(
799 &self,
800 object_id: ObjectID,
801 ) -> Option<ObjectRef> {
802 ObjectCacheRead::get_latest_object_ref_or_tombstone(self, object_id)
803 }
804 }
805 };
806}
807
808macro_rules! implement_passthrough_traits {
810 ($implementor: ident) => {
811 impl CheckpointCache for $implementor {
812 fn deprecated_get_transaction_checkpoint(
813 &self,
814 digest: &TransactionDigest,
815 ) -> Option<(EpochId, CheckpointSequenceNumber)> {
816 self.store
817 .deprecated_get_transaction_checkpoint(digest)
818 .expect("db error")
819 }
820
821 fn deprecated_multi_get_transaction_checkpoint(
822 &self,
823 digests: &[TransactionDigest],
824 ) -> Vec<Option<(EpochId, CheckpointSequenceNumber)>> {
825 self.store
826 .deprecated_multi_get_transaction_checkpoint(digests)
827 .expect("db error")
828 }
829
830 fn deprecated_insert_finalized_transactions(
831 &self,
832 digests: &[TransactionDigest],
833 epoch: EpochId,
834 sequence: CheckpointSequenceNumber,
835 ) {
836 self.store
837 .deprecated_insert_finalized_transactions(digests, epoch, sequence)
838 .expect("db error");
839 }
840 }
841
842 impl ExecutionCacheReconfigAPI for $implementor {
843 fn insert_genesis_object(&self, object: Object) {
844 self.insert_genesis_object_impl(object)
845 }
846
847 fn bulk_insert_genesis_objects(&self, objects: &[Object]) {
848 self.bulk_insert_genesis_objects_impl(objects)
849 }
850
851 fn set_epoch_start_configuration(&self, epoch_start_config: &EpochStartConfiguration) {
852 self.store
853 .set_epoch_start_configuration(epoch_start_config)
854 .expect("db error");
855 }
856
857 fn update_epoch_flags_metrics(&self, old: &[EpochFlag], new: &[EpochFlag]) {
858 self.store.update_epoch_flags_metrics(old, new)
859 }
860
861 fn clear_state_end_of_epoch(&self, execution_guard: &ExecutionLockWriteGuard<'_>) {
862 self.clear_state_end_of_epoch_impl(execution_guard)
863 }
864
865 fn expensive_check_sui_conservation(
866 &self,
867 old_epoch_store: &AuthorityPerEpochStore,
868 ) -> SuiResult {
869 self.store
870 .expensive_check_sui_conservation(self, old_epoch_store)
871 }
872
873 fn checkpoint_db(&self, path: &std::path::Path) -> SuiResult {
874 self.store.perpetual_tables.checkpoint_db(path)
875 }
876
877 fn maybe_reaccumulate_state_hash(
878 &self,
879 cur_epoch_store: &AuthorityPerEpochStore,
880 new_protocol_version: ProtocolVersion,
881 ) {
882 self.store
883 .maybe_reaccumulate_state_hash(cur_epoch_store, new_protocol_version)
884 }
885
886 fn reconfigure_cache<'a>(
887 &'a self,
888 _: &'a EpochStartConfiguration,
889 ) -> BoxFuture<'a, ()> {
890 std::future::ready(()).boxed()
894 }
895 }
896
897 impl TestingAPI for $implementor {
898 fn database_for_testing(&self) -> Arc<AuthorityStore> {
899 self.store.clone()
900 }
901
902 fn cache_for_testing(&self) -> &WritebackCache {
903 self
904 }
905 }
906 };
907}
908
909use implement_passthrough_traits;
910
911implement_storage_traits!(WritebackCache);
912
913pub trait ExecutionCacheAPI:
914 ObjectCacheRead
915 + ExecutionCacheWrite
916 + ExecutionCacheCommit
917 + ExecutionCacheReconfigAPI
918 + CheckpointCache
919 + StateSyncAPI
920{
921}