1use crate::{
2 global_state::{error::Error as GlobalStateReader, state::StateReader},
3 tracking_copy::{TrackingCopyEntityExt, TrackingCopyError, TrackingCopyExt},
4 AddressGenerator, TrackingCopy,
5};
6use casper_types::{
7 account::AccountHash, contracts::NamedKeys, Chainspec, ContextAccessRights, EntityAddr,
8 FeeHandling, Key, Phase, ProtocolVersion, PublicKey, RefundHandling, RuntimeFootprint,
9 StoredValue, TransactionHash, Transfer, URef, U512,
10};
11use num_rational::Ratio;
12use parking_lot::RwLock;
13use std::{cell::RefCell, collections::BTreeSet, rc::Rc, sync::Arc};
14use tracing::error;
15
16#[derive(Debug, Clone, PartialEq, Eq, Default)]
18pub struct Config {
19 transfer_config: TransferConfig,
20 fee_handling: FeeHandling,
21 refund_handling: RefundHandling,
22 vesting_schedule_period_millis: u64,
23 allow_auction_bids: bool,
24 compute_rewards: bool,
25 max_delegators_per_validator: u32,
26 minimum_bid_amount: u64,
27 minimum_delegation_amount: u64,
28 balance_hold_interval: u64,
29 include_credits: bool,
30 credit_cap: Ratio<U512>,
31 enable_addressable_entity: bool,
32 native_transfer_cost: u32,
33}
34
35impl Config {
36 #[allow(clippy::too_many_arguments)]
38 pub const fn new(
39 transfer_config: TransferConfig,
40 fee_handling: FeeHandling,
41 refund_handling: RefundHandling,
42 vesting_schedule_period_millis: u64,
43 allow_auction_bids: bool,
44 compute_rewards: bool,
45 max_delegators_per_validator: u32,
46 minimum_bid_amount: u64,
47 minimum_delegation_amount: u64,
48 balance_hold_interval: u64,
49 include_credits: bool,
50 credit_cap: Ratio<U512>,
51 enable_addressable_entity: bool,
52 native_transfer_cost: u32,
53 ) -> Self {
54 Config {
55 transfer_config,
56 fee_handling,
57 refund_handling,
58 vesting_schedule_period_millis,
59 allow_auction_bids,
60 compute_rewards,
61 max_delegators_per_validator,
62 minimum_bid_amount,
63 minimum_delegation_amount,
64 balance_hold_interval,
65 include_credits,
66 credit_cap,
67 enable_addressable_entity,
68 native_transfer_cost,
69 }
70 }
71
72 pub fn from_chainspec(chainspec: &Chainspec) -> Self {
74 let transfer_config = TransferConfig::from_chainspec(chainspec);
75 let fee_handling = chainspec.core_config.fee_handling;
76 let refund_handling = chainspec.core_config.refund_handling;
77 let vesting_schedule_period_millis = chainspec.core_config.vesting_schedule_period.millis();
78 let allow_auction_bids = chainspec.core_config.allow_auction_bids;
79 let compute_rewards = chainspec.core_config.compute_rewards;
80 let max_delegators_per_validator = chainspec.core_config.max_delegators_per_validator;
81 let minimum_bid_amount = chainspec.core_config.minimum_bid_amount;
82 let minimum_delegation_amount = chainspec.core_config.minimum_delegation_amount;
83 let balance_hold_interval = chainspec.core_config.gas_hold_interval.millis();
84 let include_credits = chainspec.core_config.fee_handling == FeeHandling::NoFee;
85 let credit_cap = Ratio::new_raw(
86 U512::from(*chainspec.core_config.validator_credit_cap.numer()),
87 U512::from(*chainspec.core_config.validator_credit_cap.denom()),
88 );
89 let enable_addressable_entity = chainspec.core_config.enable_addressable_entity;
90 let native_transfer_cost = chainspec.system_costs_config.mint_costs().transfer;
91 Config::new(
92 transfer_config,
93 fee_handling,
94 refund_handling,
95 vesting_schedule_period_millis,
96 allow_auction_bids,
97 compute_rewards,
98 max_delegators_per_validator,
99 minimum_bid_amount,
100 minimum_delegation_amount,
101 balance_hold_interval,
102 include_credits,
103 credit_cap,
104 enable_addressable_entity,
105 native_transfer_cost,
106 )
107 }
108
109 pub fn transfer_config(&self) -> &TransferConfig {
111 &self.transfer_config
112 }
113
114 pub fn fee_handling(&self) -> &FeeHandling {
116 &self.fee_handling
117 }
118
119 pub fn refund_handling(&self) -> &RefundHandling {
121 &self.refund_handling
122 }
123
124 pub fn vesting_schedule_period_millis(&self) -> u64 {
126 self.vesting_schedule_period_millis
127 }
128
129 pub fn allow_auction_bids(&self) -> bool {
131 self.allow_auction_bids
132 }
133
134 pub fn compute_rewards(&self) -> bool {
136 self.compute_rewards
137 }
138
139 pub fn max_delegators_per_validator(&self) -> u32 {
141 self.max_delegators_per_validator
142 }
143
144 pub fn minimum_bid_amount(&self) -> u64 {
146 self.minimum_bid_amount
147 }
148
149 pub fn minimum_delegation_amount(&self) -> u64 {
151 self.minimum_delegation_amount
152 }
153
154 pub fn balance_hold_interval(&self) -> u64 {
156 self.balance_hold_interval
157 }
158
159 pub fn include_credits(&self) -> bool {
161 self.include_credits
162 }
163
164 pub fn credit_cap(&self) -> Ratio<U512> {
166 self.credit_cap
167 }
168
169 pub fn enable_addressable_entity(&self) -> bool {
171 self.enable_addressable_entity
172 }
173
174 pub fn set_transfer_config(self, transfer_config: TransferConfig) -> Self {
176 Config {
177 transfer_config,
178 fee_handling: self.fee_handling,
179 refund_handling: self.refund_handling,
180 vesting_schedule_period_millis: self.vesting_schedule_period_millis,
181 max_delegators_per_validator: self.max_delegators_per_validator,
182 allow_auction_bids: self.allow_auction_bids,
183 minimum_bid_amount: self.minimum_bid_amount,
184 minimum_delegation_amount: self.minimum_delegation_amount,
185 compute_rewards: self.compute_rewards,
186 balance_hold_interval: self.balance_hold_interval,
187 include_credits: self.include_credits,
188 credit_cap: self.credit_cap,
189 enable_addressable_entity: self.enable_addressable_entity,
190 native_transfer_cost: self.native_transfer_cost,
191 }
192 }
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Default)]
197pub enum TransferConfig {
198 Administered {
201 administrative_accounts: BTreeSet<AccountHash>,
203 allow_unrestricted_transfers: bool,
206 },
207 #[default]
210 Unadministered,
211}
212
213impl TransferConfig {
214 pub fn new(
216 administrative_accounts: BTreeSet<AccountHash>,
217 allow_unrestricted_transfers: bool,
218 ) -> Self {
219 if administrative_accounts.is_empty() && allow_unrestricted_transfers {
220 TransferConfig::Unadministered
221 } else {
222 TransferConfig::Administered {
223 administrative_accounts,
224 allow_unrestricted_transfers,
225 }
226 }
227 }
228
229 pub fn from_chainspec(chainspec: &Chainspec) -> Self {
231 let administrative_accounts: BTreeSet<AccountHash> = chainspec
232 .core_config
233 .administrators
234 .iter()
235 .map(|x| x.to_account_hash())
236 .collect();
237 let allow_unrestricted_transfers = chainspec.core_config.allow_unrestricted_transfers;
238 if administrative_accounts.is_empty() && allow_unrestricted_transfers {
239 TransferConfig::Unadministered
240 } else {
241 TransferConfig::Administered {
242 administrative_accounts,
243 allow_unrestricted_transfers,
244 }
245 }
246 }
247
248 pub fn is_administrator(&self, account_hash: &AccountHash) -> bool {
250 match self {
251 TransferConfig::Administered {
252 administrative_accounts,
253 ..
254 } => administrative_accounts.contains(account_hash),
255 TransferConfig::Unadministered => false,
256 }
257 }
258
259 pub fn administrative_accounts(&self) -> BTreeSet<AccountHash> {
261 match self {
262 TransferConfig::Administered {
263 administrative_accounts,
264 ..
265 } => administrative_accounts.clone(),
266 TransferConfig::Unadministered => BTreeSet::default(),
267 }
268 }
269
270 pub fn allow_unrestricted_transfers(&self) -> bool {
272 match self {
273 TransferConfig::Administered {
274 allow_unrestricted_transfers,
275 ..
276 } => *allow_unrestricted_transfers,
277 TransferConfig::Unadministered => true,
278 }
279 }
280
281 pub fn enforce_transfer_restrictions(&self, account_hash: &AccountHash) -> bool {
283 !self.allow_unrestricted_transfers() && !self.is_administrator(account_hash)
284 }
285}
286
287pub enum Id {
289 Transaction(TransactionHash),
291 Seed(Vec<u8>),
293}
294
295impl Id {
296 pub fn seed(&self) -> Vec<u8> {
298 match self {
299 Id::Transaction(hash) => hash.digest().into_vec(),
300 Id::Seed(bytes) => bytes.clone(),
301 }
302 }
303}
304
305pub struct RuntimeNative<S> {
307 config: Config,
308
309 id: Id,
310 address_generator: Arc<RwLock<AddressGenerator>>,
311 protocol_version: ProtocolVersion,
312
313 tracking_copy: Rc<RefCell<TrackingCopy<S>>>,
314 address: AccountHash,
315 context_key: Key,
316 runtime_footprint: RuntimeFootprint,
317 access_rights: ContextAccessRights,
318 remaining_spending_limit: U512,
319 transfers: Vec<Transfer>,
320 phase: Phase,
321}
322
323impl<S> RuntimeNative<S>
324where
325 S: StateReader<Key, StoredValue, Error = GlobalStateReader>,
326{
327 #[allow(clippy::too_many_arguments)]
329 pub fn new(
330 config: Config,
331 protocol_version: ProtocolVersion,
332 id: Id,
333 address_generator: Arc<RwLock<AddressGenerator>>,
334 tracking_copy: Rc<RefCell<TrackingCopy<S>>>,
335 address: AccountHash,
336 context_key: Key,
337 runtime_footprint: RuntimeFootprint,
338 access_rights: ContextAccessRights,
339 remaining_spending_limit: U512,
340 phase: Phase,
341 ) -> Self {
342 let transfers = vec![];
343 RuntimeNative {
344 config,
345
346 id,
347 address_generator,
348 protocol_version,
349
350 tracking_copy,
351 address,
352 context_key,
353 runtime_footprint,
354 access_rights,
355 remaining_spending_limit,
356 transfers,
357 phase,
358 }
359 }
360
361 pub fn new_system_runtime(
363 config: Config,
364 protocol_version: ProtocolVersion,
365 id: Id,
366 address_generator: Arc<RwLock<AddressGenerator>>,
367 tracking_copy: Rc<RefCell<TrackingCopy<S>>>,
368 phase: Phase,
369 ) -> Result<Self, TrackingCopyError> {
370 let transfers = vec![];
371 let (entity_addr, runtime_footprint, access_rights) = tracking_copy
372 .borrow_mut()
373 .system_entity_runtime_footprint(protocol_version)?;
374 let address = PublicKey::System.to_account_hash();
375 let context_key = if config.enable_addressable_entity {
376 Key::AddressableEntity(entity_addr)
377 } else {
378 Key::Hash(entity_addr.value())
379 };
380 let remaining_spending_limit = U512::MAX; Ok(RuntimeNative {
382 config,
383 id,
384 address_generator,
385 protocol_version,
386
387 tracking_copy,
388 address,
389 context_key,
390 runtime_footprint,
391 access_rights,
392 remaining_spending_limit,
393 transfers,
394 phase,
395 })
396 }
397
398 pub fn new_system_contract_runtime(
400 config: Config,
401 protocol_version: ProtocolVersion,
402 id: Id,
403 address_generator: Arc<RwLock<AddressGenerator>>,
404 tracking_copy: Rc<RefCell<TrackingCopy<S>>>,
405 phase: Phase,
406 name: &str,
407 ) -> Result<Self, TrackingCopyError> {
408 let transfers = vec![];
409
410 let system_entity_registry = tracking_copy.borrow().get_system_entity_registry()?;
411 let hash = match system_entity_registry.get(name).copied() {
412 Some(hash) => hash,
413 None => {
414 error!("unexpected failure; system contract {} not found", name);
415 return Err(TrackingCopyError::MissingSystemContractHash(
416 name.to_string(),
417 ));
418 }
419 };
420 let context_key = if config.enable_addressable_entity {
421 Key::AddressableEntity(EntityAddr::System(hash))
422 } else {
423 Key::Hash(hash)
424 };
425 let runtime_footprint = tracking_copy
426 .borrow_mut()
427 .runtime_footprint_by_hash_addr(hash)?;
428 let access_rights = runtime_footprint.extract_access_rights(hash);
429 let address = PublicKey::System.to_account_hash();
430 let remaining_spending_limit = U512::MAX; Ok(RuntimeNative {
432 config,
433 id,
434 address_generator,
435 protocol_version,
436
437 tracking_copy,
438 address,
439 context_key,
440 runtime_footprint,
441 access_rights,
442 remaining_spending_limit,
443 transfers,
444 phase,
445 })
446 }
447
448 pub fn address_generator(&mut self) -> Arc<RwLock<AddressGenerator>> {
450 Arc::clone(&self.address_generator)
451 }
452
453 pub fn config(&self) -> &Config {
455 &self.config
456 }
457
458 pub fn transfer_config(&self) -> &TransferConfig {
460 &self.config.transfer_config
461 }
462
463 pub fn protocol_version(&self) -> ProtocolVersion {
465 self.protocol_version
466 }
467
468 pub fn tracking_copy(&self) -> Rc<RefCell<TrackingCopy<S>>> {
470 Rc::clone(&self.tracking_copy)
471 }
472
473 pub fn address(&self) -> AccountHash {
475 self.address
476 }
477
478 pub fn with_address(&mut self, account_hash: AccountHash) {
480 self.address = account_hash;
481 }
482
483 pub fn context_key(&self) -> &Key {
485 &self.context_key
486 }
487
488 pub fn runtime_footprint(&self) -> &RuntimeFootprint {
490 &self.runtime_footprint
491 }
492
493 pub fn runtime_footprint_mut(&mut self) -> &mut RuntimeFootprint {
495 &mut self.runtime_footprint
496 }
497
498 pub fn with_addressable_entity(&mut self, runtime_footprint: RuntimeFootprint) {
500 self.runtime_footprint = runtime_footprint;
501 }
502
503 pub fn named_keys(&self) -> &NamedKeys {
505 self.runtime_footprint().named_keys()
506 }
507
508 pub fn named_keys_mut(&mut self) -> &mut NamedKeys {
510 self.runtime_footprint.named_keys_mut()
511 }
512
513 pub fn access_rights(&self) -> &ContextAccessRights {
515 &self.access_rights
516 }
517
518 pub fn access_rights_mut(&mut self) -> &mut ContextAccessRights {
520 &mut self.access_rights
521 }
522
523 pub fn extend_access_rights(&mut self, urefs: &[URef]) {
525 self.access_rights.extend(urefs)
526 }
527
528 pub fn remaining_spending_limit(&self) -> U512 {
530 self.remaining_spending_limit
531 }
532
533 pub fn set_remaining_spending_limit(&mut self, remaining: U512) {
535 self.remaining_spending_limit = remaining;
536 }
537
538 pub fn transfers(&self) -> &Vec<Transfer> {
540 &self.transfers
541 }
542
543 pub fn push_transfer(&mut self, transfer: Transfer) {
545 self.transfers.push(transfer);
546 }
547
548 pub fn id(&self) -> &Id {
550 &self.id
551 }
552
553 pub fn phase(&self) -> Phase {
555 self.phase
556 }
557
558 pub fn vesting_schedule_period_millis(&self) -> u64 {
560 self.config.vesting_schedule_period_millis
561 }
562
563 pub fn allow_auction_bids(&self) -> bool {
565 self.config.allow_auction_bids
566 }
567
568 pub fn compute_rewards(&self) -> bool {
570 self.config.compute_rewards
571 }
572
573 pub fn into_transfers(self) -> Vec<Transfer> {
575 self.transfers
576 }
577
578 pub(crate) fn native_transfer_cost(&self) -> u32 {
579 self.config.native_transfer_cost
580 }
581}