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