casper_storage/data_access_layer/
balance_hold.rs1use crate::{
2 data_access_layer::{balance::BalanceFailure, BalanceIdentifier},
3 tracking_copy::TrackingCopyError,
4};
5use casper_types::{
6 account::AccountHash,
7 execution::Effects,
8 system::mint::{BalanceHoldAddr, BalanceHoldAddrTag},
9 Digest, ProtocolVersion, StoredValue, U512,
10};
11use std::fmt::{Display, Formatter};
12use thiserror::Error;
13
14#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
16pub enum BalanceHoldKind {
17 #[default]
19 All,
20 Tag(BalanceHoldAddrTag),
22}
23
24impl BalanceHoldKind {
25 pub fn matches(&self, balance_hold_addr_tag: BalanceHoldAddrTag) -> bool {
27 match self {
28 BalanceHoldKind::All => true,
29 BalanceHoldKind::Tag(tag) => tag == &balance_hold_addr_tag,
30 }
31 }
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
36pub enum BalanceHoldMode {
37 Hold {
39 identifier: BalanceIdentifier,
41 hold_amount: U512,
43 insufficient_handling: InsufficientBalanceHandling,
45 },
46 Clear {
48 identifier: BalanceIdentifier,
50 },
51}
52
53impl Default for BalanceHoldMode {
54 fn default() -> Self {
55 BalanceHoldMode::Hold {
56 insufficient_handling: InsufficientBalanceHandling::HoldRemaining,
57 hold_amount: U512::zero(),
58 identifier: BalanceIdentifier::Account(AccountHash::default()),
59 }
60 }
61}
62
63#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
65pub enum InsufficientBalanceHandling {
66 #[default]
68 HoldRemaining,
69 Noop,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Default)]
75pub struct BalanceHoldRequest {
76 state_hash: Digest,
77 protocol_version: ProtocolVersion,
78 hold_kind: BalanceHoldKind,
79 hold_mode: BalanceHoldMode,
80}
81
82impl BalanceHoldRequest {
83 #[allow(clippy::too_many_arguments)]
85 pub fn new_gas_hold(
86 state_hash: Digest,
87 protocol_version: ProtocolVersion,
88 identifier: BalanceIdentifier,
89 hold_amount: U512,
90 insufficient_handling: InsufficientBalanceHandling,
91 ) -> Self {
92 let hold_kind = BalanceHoldKind::Tag(BalanceHoldAddrTag::Gas);
93 let hold_mode = BalanceHoldMode::Hold {
94 identifier,
95 hold_amount,
96 insufficient_handling,
97 };
98 BalanceHoldRequest {
99 state_hash,
100 protocol_version,
101 hold_kind,
102 hold_mode,
103 }
104 }
105
106 #[allow(clippy::too_many_arguments)]
108 pub fn new_processing_hold(
109 state_hash: Digest,
110 protocol_version: ProtocolVersion,
111 identifier: BalanceIdentifier,
112 hold_amount: U512,
113 insufficient_handling: InsufficientBalanceHandling,
114 ) -> Self {
115 let hold_kind = BalanceHoldKind::Tag(BalanceHoldAddrTag::Processing);
116 let hold_mode = BalanceHoldMode::Hold {
117 identifier,
118 hold_amount,
119 insufficient_handling,
120 };
121 BalanceHoldRequest {
122 state_hash,
123 protocol_version,
124 hold_kind,
125 hold_mode,
126 }
127 }
128
129 pub fn new_clear(
131 state_hash: Digest,
132 protocol_version: ProtocolVersion,
133 hold_kind: BalanceHoldKind,
134 identifier: BalanceIdentifier,
135 ) -> Self {
136 let hold_mode = BalanceHoldMode::Clear { identifier };
137 BalanceHoldRequest {
138 state_hash,
139 protocol_version,
140 hold_kind,
141 hold_mode,
142 }
143 }
144
145 pub fn state_hash(&self) -> Digest {
147 self.state_hash
148 }
149
150 pub fn protocol_version(&self) -> ProtocolVersion {
152 self.protocol_version
153 }
154
155 pub fn balance_hold_kind(&self) -> BalanceHoldKind {
157 self.hold_kind
158 }
159
160 pub fn balance_hold_mode(&self) -> BalanceHoldMode {
162 self.hold_mode.clone()
163 }
164}
165
166#[derive(Error, Debug, Clone)]
168#[non_exhaustive]
169pub enum BalanceHoldError {
170 TrackingCopy(TrackingCopyError),
172 Balance(BalanceFailure),
174 InsufficientBalance {
176 remaining_balance: U512,
178 },
179 UnexpectedWildcardVariant, UnexpectedHoldValue(StoredValue),
183}
184
185impl From<BalanceFailure> for BalanceHoldError {
186 fn from(be: BalanceFailure) -> Self {
187 BalanceHoldError::Balance(be)
188 }
189}
190
191impl From<TrackingCopyError> for BalanceHoldError {
192 fn from(tce: TrackingCopyError) -> Self {
193 BalanceHoldError::TrackingCopy(tce)
194 }
195}
196
197impl Display for BalanceHoldError {
198 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
199 match self {
200 BalanceHoldError::TrackingCopy(err) => {
201 write!(f, "TrackingCopy: {:?}", err)
202 }
203 BalanceHoldError::InsufficientBalance { remaining_balance } => {
204 write!(f, "InsufficientBalance: {}", remaining_balance)
205 }
206 BalanceHoldError::UnexpectedWildcardVariant => {
207 write!(
208 f,
209 "UnexpectedWildcardVariant: unsupported use of BalanceHoldKind::All"
210 )
211 }
212 BalanceHoldError::Balance(be) => Display::fmt(be, f),
213 BalanceHoldError::UnexpectedHoldValue(value) => {
214 write!(f, "Found an unexpected hold value in storage: {:?}", value,)
215 }
216 }
217 }
218}
219
220#[derive(Debug)]
222pub enum BalanceHoldResult {
223 RootNotFound,
225 BlockTimeNotFound,
227 Success {
229 holds: Option<Vec<BalanceHoldAddr>>,
231 total_balance: Box<U512>,
233 available_balance: Box<U512>,
235 hold: Box<U512>,
237 held: Box<U512>,
239 effects: Box<Effects>,
241 },
242 Failure(BalanceHoldError),
244}
245
246impl BalanceHoldResult {
247 pub fn success(
249 holds: Option<Vec<BalanceHoldAddr>>,
250 total_balance: U512,
251 available_balance: U512,
252 hold: U512,
253 held: U512,
254 effects: Effects,
255 ) -> Self {
256 BalanceHoldResult::Success {
257 holds,
258 total_balance: Box::new(total_balance),
259 available_balance: Box::new(available_balance),
260 hold: Box::new(hold),
261 held: Box::new(held),
262 effects: Box::new(effects),
263 }
264 }
265
266 pub fn total_balance(&self) -> Option<&U512> {
268 match self {
269 BalanceHoldResult::Success { total_balance, .. } => Some(total_balance),
270 _ => None,
271 }
272 }
273
274 pub fn available_balance(&self) -> Option<&U512> {
276 match self {
277 BalanceHoldResult::Success {
278 available_balance, ..
279 } => Some(available_balance),
280 _ => None,
281 }
282 }
283
284 pub fn held(&self) -> Option<&U512> {
286 match self {
287 BalanceHoldResult::Success { held, .. } => Some(held),
288 _ => None,
289 }
290 }
291
292 pub fn holds(&self) -> Option<Vec<BalanceHoldAddr>> {
294 match self {
295 BalanceHoldResult::RootNotFound
296 | BalanceHoldResult::BlockTimeNotFound
297 | BalanceHoldResult::Failure(_) => None,
298 BalanceHoldResult::Success { holds, .. } => holds.clone(),
299 }
300 }
301
302 pub fn has_holds(&self) -> bool {
304 match self.holds() {
305 None => false,
306 Some(holds) => !holds.is_empty(),
307 }
308 }
309
310 pub fn is_fully_covered(&self) -> bool {
312 match self {
313 BalanceHoldResult::RootNotFound
314 | BalanceHoldResult::BlockTimeNotFound
315 | BalanceHoldResult::Failure(_) => false,
316 BalanceHoldResult::Success { hold, held, .. } => hold == held,
317 }
318 }
319
320 pub fn is_success(&self) -> bool {
322 matches!(self, BalanceHoldResult::Success { .. })
323 }
324
325 pub fn is_root_not_found(&self) -> bool {
327 matches!(self, BalanceHoldResult::RootNotFound)
328 }
329
330 pub fn effects(&self) -> Effects {
332 match self {
333 BalanceHoldResult::RootNotFound
334 | BalanceHoldResult::BlockTimeNotFound
335 | BalanceHoldResult::Failure(_) => Effects::new(),
336 BalanceHoldResult::Success { effects, .. } => *effects.clone(),
337 }
338 }
339
340 pub fn error_message(&self) -> String {
342 match self {
343 BalanceHoldResult::Success { hold, held, .. } => {
344 if hold == held {
345 String::default()
346 } else {
347 format!(
348 "insufficient balance to cover hold amount: {}, held remaining amount: {}",
349 hold, held
350 )
351 }
352 }
353 BalanceHoldResult::RootNotFound => "root not found".to_string(),
354 BalanceHoldResult::BlockTimeNotFound => "block time not found".to_string(),
355 BalanceHoldResult::Failure(bhe) => {
356 format!("{:?}", bhe)
357 }
358 }
359 }
360}
361
362impl From<BalanceFailure> for BalanceHoldResult {
363 fn from(be: BalanceFailure) -> Self {
364 BalanceHoldResult::Failure(be.into())
365 }
366}
367
368impl From<TrackingCopyError> for BalanceHoldResult {
369 fn from(tce: TrackingCopyError) -> Self {
370 BalanceHoldResult::Failure(tce.into())
371 }
372}