multiversx_chain_vm/blockchain/state/
blockchain_state.rs

1use 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}