multiversx_chain_vm/blockchain/state/
blockchain_state.rs1use num_bigint::BigUint;
2use num_traits::Zero;
3use std::{
4 collections::HashMap,
5 fmt::Debug,
6 ops::{Deref, DerefMut},
7 sync::Arc,
8};
9
10use crate::{
11 blockchain::reserved::STORAGE_REWARD_KEY, host::context::BlockchainUpdate, types::VMAddress,
12};
13
14use super::{AccountData, BlockConfig};
15
16#[derive(Default, Clone)]
17pub struct BlockchainState {
18 pub accounts: HashMap<VMAddress, AccountData>,
19 pub new_addresses: HashMap<(VMAddress, u64), VMAddress>,
20 pub block_config: BlockConfig,
21 pub new_token_identifiers: Vec<String>,
22}
23
24impl BlockchainState {
25 pub fn commit_updates(&mut self, updates: BlockchainUpdate) {
26 updates.apply(self);
27 }
28
29 pub fn account_exists(&self, address: &VMAddress) -> bool {
30 self.accounts.contains_key(address)
31 }
32
33 pub fn increase_account_nonce(&mut self, address: &VMAddress) {
34 let account = self.accounts.get_mut(address).unwrap_or_else(|| {
35 panic!(
36 "Account not found: {}",
37 &std::str::from_utf8(address.as_ref()).unwrap()
38 )
39 });
40 account.nonce += 1;
41 }
42
43 pub fn subtract_tx_gas(&mut self, address: &VMAddress, gas_limit: u64, gas_price: u64) {
44 let account = self.accounts.get_mut(address).unwrap_or_else(|| {
45 panic!(
46 "Account not found: {}",
47 &std::str::from_utf8(address.as_ref()).unwrap()
48 )
49 });
50 let gas_cost = BigUint::from(gas_limit) * BigUint::from(gas_price);
51 assert!(
52 account.egld_balance >= gas_cost,
53 "Not enough balance to pay gas upfront"
54 );
55 account.egld_balance -= &gas_cost;
56 }
57
58 pub fn increase_validator_reward(&mut self, address: &VMAddress, amount: &BigUint) {
59 let account = self.accounts.get_mut(address).unwrap_or_else(|| {
60 panic!(
61 "Account not found: {}",
62 &std::str::from_utf8(address.as_ref()).unwrap()
63 )
64 });
65 account.egld_balance += amount;
66 let mut storage_v_rew =
67 if let Some(old_storage_value) = account.storage.get(STORAGE_REWARD_KEY) {
68 BigUint::from_bytes_be(old_storage_value)
69 } else {
70 BigUint::zero()
71 };
72 storage_v_rew += amount;
73 account
74 .storage
75 .insert(STORAGE_REWARD_KEY.to_vec(), storage_v_rew.to_bytes_be());
76 }
77
78 pub fn put_new_token_identifier(&mut self, token_identifier: String) {
79 self.new_token_identifiers.push(token_identifier)
80 }
81
82 pub fn get_new_token_identifiers(&self) -> Vec<String> {
83 self.new_token_identifiers.clone()
84 }
85
86 pub fn update_new_token_identifiers(&mut self, token_identifiers: Vec<String>) {
87 self.new_token_identifiers = token_identifiers;
88 }
89}
90
91impl Debug for BlockchainState {
92 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
93 f.debug_struct("BlockchainState")
94 .field("accounts", &self.accounts)
95 .field("new_addresses", &self.new_addresses)
96 .field("block_config", &self.block_config)
97 .finish()
98 }
99}
100
101#[derive(Default, Clone)]
102pub struct BlockchainStateRef(Arc<BlockchainState>);
103
104impl BlockchainStateRef {
105 pub fn mut_state(&mut self) -> &mut BlockchainState {
106 Arc::get_mut(&mut self.0).expect("cannot change state, since object is currently shared")
107 }
108
109 pub fn get_arc(&self) -> Arc<BlockchainState> {
110 self.0.clone()
111 }
112}
113
114impl Deref for BlockchainStateRef {
115 type Target = BlockchainState;
116
117 fn deref(&self) -> &Self::Target {
118 self.0.deref()
119 }
120}
121
122impl DerefMut for BlockchainStateRef {
123 fn deref_mut(&mut self) -> &mut Self::Target {
124 Arc::get_mut(&mut self.0).expect("cannot change state, since object is currently shared")
125 }
126}