1use std::collections::BTreeSet;
2use tracing::{debug, error};
3
4use casper_storage::{
5 global_state::{error::Error as GlobalStateError, state::StateReader},
6 system::{
7 auction::{
8 providers::{AccountProvider, MintProvider, RuntimeProvider, StorageProvider},
9 Auction,
10 },
11 mint::Mint,
12 },
13};
14use casper_types::{
15 account::AccountHash,
16 bytesrepr::{FromBytes, ToBytes},
17 system::{
18 auction::{BidAddr, BidKind, EraInfo, Error, Unbond, UnbondEra, UnbondKind},
19 mint,
20 },
21 AccessRights, CLTyped, CLValue, Key, KeyTag, PublicKey, RuntimeArgs, StoredValue, URef, U512,
22};
23
24use super::Runtime;
25use crate::execution::ExecError;
26
27impl From<ExecError> for Option<Error> {
28 fn from(exec_error: ExecError) -> Self {
29 match exec_error {
30 ExecError::GasLimit => Some(Error::GasLimit),
33 _ => None,
35 }
36 }
37}
38
39impl<R> StorageProvider for Runtime<'_, R>
40where
41 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
42{
43 fn read<T: FromBytes + CLTyped>(&mut self, uref: URef) -> Result<Option<T>, Error> {
44 match self.context.read_gs(&uref.into()) {
45 Ok(Some(StoredValue::CLValue(cl_value))) => {
46 Ok(Some(cl_value.into_t().map_err(|_| Error::CLValue)?))
47 }
48 Ok(Some(_)) => {
49 error!("StorageProvider::read: unexpected StoredValue variant");
50 Err(Error::Storage)
51 }
52 Ok(None) => Ok(None),
53 Err(ExecError::BytesRepr(_)) => Err(Error::Serialization),
54 Err(ExecError::GasLimit) => Err(Error::GasLimit),
57 Err(err) => {
58 error!("StorageProvider::read: {:?}", err);
59 Err(Error::Storage)
60 }
61 }
62 }
63
64 fn write<T: ToBytes + CLTyped>(&mut self, uref: URef, value: T) -> Result<(), Error> {
65 let cl_value = CLValue::from_t(value).map_err(|_| Error::CLValue)?;
66 self.context
67 .metered_write_gs(uref.into(), StoredValue::CLValue(cl_value))
68 .map_err(|exec_error| {
69 error!("StorageProvider::write: {:?}", exec_error);
70 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
71 })
72 }
73
74 fn read_bid(&mut self, key: &Key) -> Result<Option<BidKind>, Error> {
75 match self.context.read_gs(key) {
76 Ok(Some(StoredValue::BidKind(bid_kind))) => Ok(Some(bid_kind)),
77 Ok(Some(_)) => {
78 error!("StorageProvider::read_bid: unexpected StoredValue variant");
79 Err(Error::Storage)
80 }
81 Ok(None) => Ok(None),
82 Err(ExecError::BytesRepr(_)) => Err(Error::Serialization),
83 Err(ExecError::GasLimit) => Err(Error::GasLimit),
86 Err(err) => {
87 error!("StorageProvider::read_bid: {:?}", err);
88 Err(Error::Storage)
89 }
90 }
91 }
92
93 fn write_bid(&mut self, key: Key, bid_kind: BidKind) -> Result<(), Error> {
94 self.context
95 .metered_write_gs_unsafe(key, StoredValue::BidKind(bid_kind))
96 .map_err(|exec_error| {
97 error!("StorageProvider::write_bid: {:?}", exec_error);
98 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
99 })
100 }
101
102 fn read_unbond(&mut self, bid_addr: BidAddr) -> Result<Option<Unbond>, Error> {
103 match self.context.read_gs(&Key::BidAddr(bid_addr)) {
104 Ok(Some(StoredValue::BidKind(BidKind::Unbond(unbonds)))) => Ok(Some(*unbonds)),
105 Ok(Some(_)) => {
106 error!("StorageProvider::read_unbonds: unexpected StoredValue variant");
107 Err(Error::Storage)
108 }
109 Ok(None) => Ok(None),
110 Err(ExecError::BytesRepr(_)) => Err(Error::Serialization),
111 Err(ExecError::GasLimit) => Err(Error::GasLimit),
114 Err(err) => {
115 error!("StorageProvider::read_unbonds: {:?}", err);
116 Err(Error::Storage)
117 }
118 }
119 }
120
121 fn write_unbond(&mut self, bid_addr: BidAddr, unbond: Option<Unbond>) -> Result<(), Error> {
122 let unbond_key = Key::BidAddr(bid_addr);
123 match unbond {
124 Some(unbond) => self
125 .context
126 .metered_write_gs_unsafe(
127 unbond_key,
128 StoredValue::BidKind(BidKind::Unbond(Box::new(unbond))),
129 )
130 .map_err(|exec_error| {
131 error!("StorageProvider::write_unbond: {:?}", exec_error);
132 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
133 }),
134 None => {
135 self.context.prune_gs_unsafe(unbond_key);
136 Ok(())
137 }
138 }
139 }
140
141 fn record_era_info(&mut self, era_info: EraInfo) -> Result<(), Error> {
142 Runtime::record_era_info(self, era_info)
143 .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::RecordEraInfo))
144 }
145
146 fn prune_bid(&mut self, bid_addr: BidAddr) {
147 Runtime::prune(self, bid_addr.into());
148 }
149}
150
151impl<R> RuntimeProvider for Runtime<'_, R>
152where
153 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
154{
155 fn get_caller(&self) -> AccountHash {
156 self.context.get_initiator()
157 }
158
159 fn is_allowed_session_caller(&self, account_hash: &AccountHash) -> bool {
160 Runtime::is_allowed_session_caller(self, account_hash)
161 }
162
163 fn is_valid_uref(&self, uref: URef) -> bool {
164 self.context.validate_uref(&uref).is_ok()
165 }
166
167 fn named_keys_get(&self, name: &str) -> Option<Key> {
168 self.context.named_keys_get(name).cloned()
169 }
170
171 fn get_keys(&mut self, key_tag: &KeyTag) -> Result<BTreeSet<Key>, Error> {
172 self.context.get_keys(key_tag).map_err(|err| {
173 error!(%key_tag, "RuntimeProvider::get_keys: {:?}", err);
174 Error::Storage
175 })
176 }
177
178 fn get_keys_by_prefix(&mut self, prefix: &[u8]) -> Result<Vec<Key>, Error> {
179 self.context
180 .get_keys_with_prefix(prefix)
181 .map_err(|exec_error| {
182 error!("RuntimeProvider::get_keys_by_prefix: {:?}", exec_error);
183 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
184 })
185 }
186
187 fn delegator_count(&mut self, bid_addr: &BidAddr) -> Result<usize, Error> {
188 let delegated_accounts = {
189 let prefix = bid_addr.delegated_account_prefix()?;
190 let keys = self
191 .context
192 .get_keys_with_prefix(&prefix)
193 .map_err(|exec_error| {
194 error!("RuntimeProvider::delegator_count accounts {:?}", exec_error);
195 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
196 })?;
197 keys.len()
198 };
199 let delegated_purses = {
200 let prefix = bid_addr.delegated_purse_prefix()?;
201 let keys = self
202 .context
203 .get_keys_with_prefix(&prefix)
204 .map_err(|exec_error| {
205 error!("RuntimeProvider::delegator_count purses {:?}", exec_error);
206 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
207 })?;
208 keys.len()
209 };
210 Ok(delegated_accounts.saturating_add(delegated_purses))
211 }
212
213 fn reservation_count(&mut self, bid_addr: &BidAddr) -> Result<usize, Error> {
214 let reserved_accounts = {
215 let reservation_prefix = bid_addr.reserved_account_prefix()?;
216 let reservation_keys = self
217 .context
218 .get_keys_with_prefix(&reservation_prefix)
219 .map_err(|exec_error| {
220 error!("RuntimeProvider::reservation_count {:?}", exec_error);
221 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
222 })?;
223 reservation_keys.len()
224 };
225 let reserved_purses = {
226 let reservation_prefix = bid_addr.reserved_purse_prefix()?;
227 let reservation_keys = self
228 .context
229 .get_keys_with_prefix(&reservation_prefix)
230 .map_err(|exec_error| {
231 error!("RuntimeProvider::reservation_count {:?}", exec_error);
232 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
233 })?;
234 reservation_keys.len()
235 };
236 Ok(reserved_accounts.saturating_add(reserved_purses))
237 }
238
239 fn used_reservation_count(&mut self, bid_addr: &BidAddr) -> Result<usize, Error> {
240 let reservation_account_prefix = bid_addr.reserved_account_prefix()?;
241 let reservation_purse_prefix = bid_addr.reserved_purse_prefix()?;
242
243 let reservation_keys = {
244 let mut ret = self
245 .context
246 .get_keys_with_prefix(&reservation_account_prefix)
247 .map_err(|exec_error| {
248 error!("RuntimeProvider::reservation_count {:?}", exec_error);
249 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
250 })?;
251 let purses = self
252 .context
253 .get_keys_with_prefix(&reservation_purse_prefix)
254 .map_err(|exec_error| {
255 error!("RuntimeProvider::reservation_count {:?}", exec_error);
256 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
257 })?;
258 ret.extend(purses);
259 ret
260 };
261
262 let mut used = 0;
263 for reservation_key in reservation_keys {
264 if let Key::BidAddr(BidAddr::ReservedDelegationAccount {
265 validator,
266 delegator,
267 }) = reservation_key
268 {
269 let key_to_check = Key::BidAddr(BidAddr::DelegatedAccount {
270 validator,
271 delegator,
272 });
273 if let Ok(Some(_)) = self.context.read_gs(&key_to_check) {
274 used += 1;
275 }
276 }
277 if let Key::BidAddr(BidAddr::ReservedDelegationPurse {
278 validator,
279 delegator,
280 }) = reservation_key
281 {
282 let key_to_check = Key::BidAddr(BidAddr::DelegatedPurse {
283 validator,
284 delegator,
285 });
286 if let Ok(Some(_)) = self.context.read_gs(&key_to_check) {
287 used += 1;
288 }
289 }
290 }
291 Ok(used)
292 }
293
294 fn vesting_schedule_period_millis(&self) -> u64 {
295 self.context
296 .engine_config()
297 .vesting_schedule_period_millis()
298 }
299
300 fn allow_auction_bids(&self) -> bool {
301 self.context.engine_config().allow_auction_bids()
302 }
303
304 fn should_compute_rewards(&self) -> bool {
305 self.context.engine_config().compute_rewards()
306 }
307}
308
309impl<R> MintProvider for Runtime<'_, R>
310where
311 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
312{
313 fn unbond(&mut self, unbond_kind: &UnbondKind, unbond_era: &UnbondEra) -> Result<(), Error> {
314 let is_delegator = unbond_kind.is_delegator();
315 let (purse, maybe_account_hash) = match unbond_kind {
316 UnbondKind::Validator(pk) | UnbondKind::DelegatedPublicKey(pk) => {
317 let account_hash = pk.to_account_hash();
318 let maybe_value = self
319 .context
320 .read_gs_unsafe(&Key::Account(account_hash))
321 .map_err(|exec_error| {
322 error!("MintProvider::unbond: {:?}", exec_error);
323 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
324 })?;
325
326 match maybe_value {
327 Some(StoredValue::Account(account)) => {
328 (account.main_purse(), Some(account_hash))
329 }
330 Some(StoredValue::CLValue(cl_value)) => {
331 let entity_key: Key = cl_value.into_t().map_err(|_| Error::CLValue)?;
332 match self.context.read_gs_unsafe(&entity_key) {
333 Ok(Some(StoredValue::AddressableEntity(entity))) => {
334 (entity.main_purse(), Some(account_hash))
335 }
336 Ok(Some(StoredValue::CLValue(_))) => {
337 return Err(Error::CLValue);
338 }
339 Ok(Some(_)) => {
340 return if is_delegator {
341 Err(Error::DelegatorNotFound)
342 } else {
343 Err(Error::ValidatorNotFound)
344 }
345 }
346 Ok(None) => {
347 return Err(Error::InvalidPublicKey);
348 }
349 Err(exec_error) => {
350 error!("MintProvider::unbond: {:?}", exec_error);
351 return Err(
352 <Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
353 );
354 }
355 }
356 }
357 Some(_) => return Err(Error::UnexpectedStoredValueVariant),
358 None => return Err(Error::InvalidPublicKey),
359 }
360 }
361 UnbondKind::DelegatedPurse(addr) => {
362 let purse = URef::new(*addr, AccessRights::READ_ADD_WRITE);
363 match self.balance(purse) {
364 Ok(Some(_)) => (purse, None),
365 Ok(None) => return Err(Error::MissingPurse),
366 Err(err) => {
367 error!("MintProvider::unbond delegated purse: {:?}", err);
368 return Err(Error::MintError);
369 }
370 }
371 }
372 };
373
374 self.mint_transfer_direct(
375 maybe_account_hash,
376 *unbond_era.bonding_purse(),
377 purse,
378 *unbond_era.amount(),
379 None,
380 )
381 .map_err(|_| Error::Transfer)?
382 .map_err(|_| Error::Transfer)?;
383 Ok(())
384 }
385
386 fn mint_transfer_direct(
390 &mut self,
391 to: Option<AccountHash>,
392 source: URef,
393 target: URef,
394 amount: U512,
395 id: Option<u64>,
396 ) -> Result<Result<(), mint::Error>, Error> {
397 let is_main_purse_transfer = self
398 .context
399 .runtime_footprint()
400 .borrow()
401 .main_purse()
402 .expect("didnt have purse")
403 .addr()
404 == source.addr();
405 let has_perms = is_main_purse_transfer
406 || (source.is_writeable() && self.context.validate_uref(&source).is_ok());
407 if !(has_perms || self.context.get_initiator() == PublicKey::System.to_account_hash()) {
408 return Err(Error::InvalidCaller);
409 }
410
411 let args_values = RuntimeArgs::try_new(|args| {
412 args.insert(mint::ARG_TO, to)?;
413 args.insert(mint::ARG_SOURCE, source)?;
414 args.insert(mint::ARG_TARGET, target)?;
415 args.insert(mint::ARG_AMOUNT, amount)?;
416 args.insert(mint::ARG_ID, id)?;
417 Ok(())
418 })
419 .map_err(|_| Error::CLValue)?;
420
421 let gas_counter = self.gas_counter();
422
423 self.context
424 .access_rights_extend(&[source, target.into_add()]);
425
426 let mint_hash = self.get_mint_hash().map_err(|exec_error| {
427 <Option<Error>>::from(exec_error).unwrap_or(Error::MissingValue)
428 })?;
429
430 let cl_value = self
431 .call_contract(mint_hash, mint::METHOD_TRANSFER, args_values)
432 .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::Transfer))?;
433
434 self.set_gas_counter(gas_counter);
435 cl_value.into_t().map_err(|_| Error::CLValue)
436 }
437
438 fn mint_into_existing_purse(
439 &mut self,
440 amount: U512,
441 existing_purse: URef,
442 ) -> Result<(), Error> {
443 if self.context.get_initiator() != PublicKey::System.to_account_hash() {
444 return Err(Error::InvalidCaller);
445 }
446
447 let args_values = RuntimeArgs::try_new(|args| {
448 args.insert(mint::ARG_AMOUNT, amount)?;
449 args.insert(mint::ARG_PURSE, existing_purse)?;
450 Ok(())
451 })
452 .map_err(|_| Error::CLValue)?;
453
454 let gas_counter = self.gas_counter();
455
456 let mint_hash = self.get_mint_hash().map_err(|exec_error| {
457 <Option<Error>>::from(exec_error).unwrap_or(Error::MissingValue)
458 })?;
459
460 let cl_value = self
461 .call_contract(
462 mint_hash,
463 mint::METHOD_MINT_INTO_EXISTING_PURSE,
464 args_values,
465 )
466 .map_err(|error| <Option<Error>>::from(error).unwrap_or(Error::MintError))?;
467 self.set_gas_counter(gas_counter);
468 cl_value
469 .into_t::<Result<(), mint::Error>>()
470 .map_err(|_| Error::CLValue)?
471 .map_err(|_| Error::MintError)
472 }
473
474 fn create_purse(&mut self) -> Result<URef, Error> {
475 Runtime::create_purse(self).map_err(|exec_error| {
476 <Option<Error>>::from(exec_error).unwrap_or(Error::CreatePurseFailed)
477 })
478 }
479
480 fn available_balance(&mut self, purse: URef) -> Result<Option<U512>, Error> {
481 Runtime::available_balance(self, purse)
482 .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::GetBalance))
483 }
484
485 fn read_base_round_reward(&mut self) -> Result<U512, Error> {
486 let mint_hash = self.get_mint_hash().map_err(|exec_error| {
487 <Option<Error>>::from(exec_error).unwrap_or(Error::MissingValue)
488 })?;
489 self.mint_read_base_round_reward(mint_hash)
490 .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::MintReward))
491 }
492
493 fn mint(&mut self, amount: U512) -> Result<URef, Error> {
494 let mint_hash = self.get_mint_hash().map_err(|exec_error| {
495 <Option<Error>>::from(exec_error).unwrap_or(Error::MissingValue)
496 })?;
497 self.mint_mint(mint_hash, amount)
498 .map_err(|exec_error| <Option<Error>>::from(exec_error).unwrap_or(Error::MintError))
499 }
500
501 fn reduce_total_supply(&mut self, amount: U512) -> Result<(), Error> {
502 let mint_hash = self.get_mint_hash().map_err(|exec_error| {
503 <Option<Error>>::from(exec_error).unwrap_or(Error::MissingValue)
504 })?;
505 self.mint_reduce_total_supply(mint_hash, amount)
506 .map_err(|exec_error| {
507 <Option<Error>>::from(exec_error).unwrap_or(Error::MintReduceTotalSupply)
508 })
509 }
510}
511
512impl<R> AccountProvider for Runtime<'_, R>
513where
514 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
515{
516 fn get_main_purse(&self) -> Result<URef, Error> {
517 match Runtime::context(self)
520 .runtime_footprint()
521 .borrow()
522 .main_purse()
523 {
524 None => {
525 debug!("runtime attempt to access non-existent main purse");
526 Err(Error::InvalidContext)
527 }
528 Some(purse) => Ok(purse),
529 }
530 }
531
532 fn set_main_purse(&mut self, purse: URef) {
534 Runtime::context(self)
535 .runtime_footprint()
536 .borrow_mut()
537 .set_main_purse(purse);
538 }
539}
540
541impl<R> Auction for Runtime<'_, R> where R: StateReader<Key, StoredValue, Error = GlobalStateError> {}