sui_core/accumulators/
coin_reservations.rs1use std::sync::Arc;
5
6use moka::sync::Cache as MokaCache;
7use move_core_types::language_storage::TypeTag;
8use sui_types::{
9 base_types::{ObjectID, SequenceNumber, SuiAddress},
10 coin_reservation::{
11 CoinReservationResolver, CoinReservationResolverTrait, ParsedObjectRefWithdrawal,
12 },
13 error::{UserInputError, UserInputResult},
14 storage::ChildObjectResolver,
15 transaction::FundsWithdrawalArg,
16};
17
18pub struct CachingCoinReservationResolver {
21 inner: CoinReservationResolver,
22 cache: MokaCache<ObjectID, UserInputResult<(SuiAddress, TypeTag)>>,
23}
24
25impl CachingCoinReservationResolver {
26 pub fn new(child_object_resolver: Arc<dyn ChildObjectResolver + Send + Sync>) -> Self {
27 Self {
28 inner: CoinReservationResolver::new(child_object_resolver),
29 cache: MokaCache::builder().max_capacity(1000).build(),
30 }
31 }
32
33 fn get_owner_and_type_cached(
34 &self,
35 object_id: ObjectID,
36 accumulator_version: Option<SequenceNumber>,
37 ) -> UserInputResult<(SuiAddress, TypeTag)> {
38 if let Some(cached) = self.cache.get(&object_id) {
48 return cached;
49 }
50 match self
51 .inner
52 .get_owner_and_type_for_object(object_id, accumulator_version)
53 {
54 Ok(Some(value)) => {
55 self.cache.insert(object_id, Ok(value.clone()));
56 Ok(value)
57 }
58 Ok(None) => Err(UserInputError::InvalidWithdrawReservation {
59 error: format!("coin reservation object id {} not found", object_id),
60 }),
61 Err(e) => {
62 self.cache.insert(object_id, Err(e.clone()));
63 Err(e)
64 }
65 }
66 }
67
68 pub fn resolve_funds_withdrawal(
69 &self,
70 sender: SuiAddress,
71 coin_reservation: ParsedObjectRefWithdrawal,
72 accumulator_version: Option<SequenceNumber>,
73 ) -> UserInputResult<FundsWithdrawalArg> {
74 let (owner, type_tag) = self
75 .get_owner_and_type_cached(coin_reservation.unmasked_object_id, accumulator_version)?;
76
77 if sender != owner {
78 return Err(UserInputError::InvalidWithdrawReservation {
79 error: format!(
80 "coin reservation object id {} is owned by {}, not sender {}",
81 coin_reservation.unmasked_object_id, owner, sender
82 ),
83 });
84 }
85
86 Ok(FundsWithdrawalArg::balance_from_sender(
87 coin_reservation.reservation_amount(),
88 type_tag,
89 ))
90 }
91}
92
93impl CoinReservationResolverTrait for CachingCoinReservationResolver {
94 fn resolve_funds_withdrawal(
95 &self,
96 sender: SuiAddress,
97 coin_reservation: ParsedObjectRefWithdrawal,
98 accumulator_version: Option<SequenceNumber>,
99 ) -> UserInputResult<FundsWithdrawalArg> {
100 CachingCoinReservationResolver::resolve_funds_withdrawal(
101 self,
102 sender,
103 coin_reservation,
104 accumulator_version,
105 )
106 }
107}
108
109impl CoinReservationResolverTrait for &'_ CachingCoinReservationResolver {
110 fn resolve_funds_withdrawal(
111 &self,
112 sender: SuiAddress,
113 coin_reservation: ParsedObjectRefWithdrawal,
114 accumulator_version: Option<SequenceNumber>,
115 ) -> UserInputResult<FundsWithdrawalArg> {
116 CachingCoinReservationResolver::resolve_funds_withdrawal(
117 self,
118 sender,
119 coin_reservation,
120 accumulator_version,
121 )
122 }
123}