multiversx_chain_vm/host/context/
tx_context.rs1use crate::{
2 blockchain::{
3 state::{AccountData, AccountEsdt, BlockchainState},
4 VMConfigRef,
5 },
6 host::runtime::RuntimeRef,
7 types::{VMAddress, VMCodeMetadata},
8};
9use num_bigint::BigUint;
10use num_traits::Zero;
11use std::{
12 collections::HashMap,
13 sync::{Arc, Mutex, MutexGuard},
14};
15
16use super::{
17 BackTransfers, BlockchainRng, BlockchainUpdate, FailingExecutor, ManagedTypeContainer, TxCache,
18 TxInput, TxResult,
19};
20
21pub struct TxContext {
22 pub runtime_ref: RuntimeRef,
23 pub tx_input_box: Box<TxInput>,
24 pub tx_cache: Arc<TxCache>,
25 pub managed_types: Mutex<ManagedTypeContainer>,
26 pub back_transfers: Mutex<BackTransfers>,
27 pub tx_result_cell: Mutex<TxResult>,
28 pub b_rng: Mutex<BlockchainRng>,
29}
30
31impl TxContext {
32 pub fn new(runtime_ref: RuntimeRef, tx_input: TxInput, tx_cache: TxCache) -> Self {
33 let b_rng = Mutex::new(BlockchainRng::new(&tx_input, &tx_cache));
34 TxContext {
35 runtime_ref,
36 tx_input_box: Box::new(tx_input),
37 tx_cache: Arc::new(tx_cache),
38 managed_types: Mutex::new(ManagedTypeContainer::new()),
39 back_transfers: Mutex::default(),
40 tx_result_cell: Mutex::new(TxResult::empty()),
41 b_rng,
42 }
43 }
44
45 pub fn dummy() -> Self {
46 let tx_cache = TxCache::new(Arc::new(BlockchainState::default()));
47 let contract_address = VMAddress::from([b'c'; 32]);
48 tx_cache.insert_account(AccountData {
49 address: contract_address.clone(),
50 nonce: 0,
51 egld_balance: BigUint::zero(),
52 storage: HashMap::new(),
53 esdt: AccountEsdt::default(),
54 username: Vec::new(),
55 contract_path: None,
56 code_metadata: VMCodeMetadata::empty(),
57 contract_owner: None,
58 developer_rewards: BigUint::zero(),
59 });
60
61 let tx_input = TxInput {
62 from: contract_address.clone(),
63 to: contract_address,
64 tx_hash: b"dummy...........................".into(),
65 ..Default::default()
66 };
67
68 let b_rng = Mutex::new(BlockchainRng::new(&tx_input, &tx_cache));
69 let vm_ref = VMConfigRef::new();
70 TxContext {
71 runtime_ref: RuntimeRef::new(vm_ref, Box::new(FailingExecutor)),
72 tx_input_box: Box::new(tx_input),
73 tx_cache: Arc::new(tx_cache),
74 managed_types: Mutex::new(ManagedTypeContainer::new()),
75 back_transfers: Mutex::default(),
76 tx_result_cell: Mutex::new(TxResult::empty()),
77 b_rng,
78 }
79 }
80
81 pub fn input_ref(&self) -> &TxInput {
82 self.tx_input_box.as_ref()
83 }
84
85 pub fn blockchain_cache(&self) -> &TxCache {
86 &self.tx_cache
87 }
88
89 pub fn blockchain_cache_arc(&self) -> Arc<TxCache> {
90 self.tx_cache.clone()
91 }
92
93 pub fn blockchain_ref(&self) -> &BlockchainState {
94 self.tx_cache.blockchain_ref()
95 }
96
97 pub fn with_account<R, F>(&self, address: &VMAddress, f: F) -> R
98 where
99 F: FnOnce(&AccountData) -> R,
100 {
101 self.tx_cache.with_account(address, f)
102 }
103
104 pub fn with_account_or_else<R, F, Else>(&self, address: &VMAddress, f: F, or_else: Else) -> R
105 where
106 F: FnOnce(&AccountData) -> R,
107 Else: FnOnce() -> R,
108 {
109 self.tx_cache.with_account_or_else(address, f, or_else)
110 }
111
112 pub fn with_contract_account<R, F>(&self, f: F) -> R
113 where
114 F: FnOnce(&AccountData) -> R,
115 {
116 self.with_account(&self.tx_input_box.to, f)
117 }
118
119 pub fn with_account_mut<R, F>(&self, address: &VMAddress, f: F) -> R
120 where
121 F: FnOnce(&mut AccountData) -> R,
122 {
123 self.tx_cache.with_account_mut(address, f)
124 }
125
126 pub fn with_contract_account_mut<R, F>(&self, f: F) -> R
127 where
128 F: FnOnce(&mut AccountData) -> R,
129 {
130 self.with_account_mut(&self.tx_input_box.to, f)
131 }
132
133 pub fn m_types_lock(&self) -> MutexGuard<'_, ManagedTypeContainer> {
134 self.managed_types.lock().unwrap()
135 }
136
137 pub fn back_transfers_lock(&self) -> MutexGuard<'_, BackTransfers> {
138 self.back_transfers.lock().unwrap()
139 }
140
141 pub fn result_lock(&self) -> MutexGuard<'_, TxResult> {
142 self.tx_result_cell.lock().unwrap()
143 }
144
145 pub fn extract_result(&self) -> TxResult {
146 std::mem::replace(&mut *self.tx_result_cell.lock().unwrap(), TxResult::empty())
147 }
148
149 pub fn rng_lock(&self) -> MutexGuard<'_, BlockchainRng> {
150 self.b_rng.lock().unwrap()
151 }
152
153 pub fn create_new_contract(
154 &self,
155 new_address: &VMAddress,
156 contract_path: Vec<u8>,
157 code_metadata: VMCodeMetadata,
158 contract_owner: VMAddress,
159 ) {
160 assert!(
161 !self.tx_cache.blockchain_ref().account_exists(new_address),
162 "Account already exists at deploy address."
163 );
164
165 self.tx_cache.insert_account(AccountData {
166 address: new_address.clone(),
167 nonce: 0,
168 egld_balance: BigUint::zero(),
169 storage: HashMap::new(),
170 esdt: AccountEsdt::default(),
171 username: Vec::new(),
172 contract_path: Some(contract_path),
173 code_metadata,
174 contract_owner: Some(contract_owner),
175 developer_rewards: BigUint::zero(),
176 });
177 }
178
179 pub fn into_blockchain_updates(self) -> BlockchainUpdate {
180 let tx_cache = Arc::try_unwrap(self.tx_cache).unwrap();
181 tx_cache.into_blockchain_updates()
182 }
183
184 pub fn into_results(self) -> (TxResult, BlockchainUpdate) {
185 let tx_cache = Arc::try_unwrap(self.tx_cache).unwrap();
186 let tx_result = Mutex::into_inner(self.tx_result_cell).unwrap();
187 let blockchain_updates = tx_cache.into_blockchain_updates();
188 (tx_result, blockchain_updates)
189 }
190}
191
192impl std::fmt::Debug for TxContext {
193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194 f.debug_struct("TxContext")
195 .field("tx_input_box", &self.tx_input_box)
196 .field("tx_cache", &self.tx_cache)
197 .field("managed_types", &self.managed_types)
198 .field("tx_result_cell", &self.tx_result_cell)
199 .field("b_rng", &self.b_rng)
200 .finish()
201 }
202}