multiversx_chain_vm/host/execution/
exec_create.rs

1use crate::{
2    blockchain::state::BlockchainStateRef,
3    host::context::{BlockchainUpdate, TxCache, TxContext, TxInput, TxResult},
4    host::runtime::{RuntimeInstanceCallLambda, RuntimeRef},
5    types::{VMAddress, VMCodeMetadata},
6};
7
8/// Executes deploy transaction and commits changes back to the underlying blockchain state.
9pub fn commit_deploy<F>(
10    tx_input: TxInput,
11    contract_path: &[u8],
12    code_metadata: VMCodeMetadata,
13    state: &mut BlockchainStateRef,
14    runtime: &RuntimeRef,
15    f: F,
16) -> (VMAddress, TxResult)
17where
18    F: RuntimeInstanceCallLambda,
19{
20    // nonce gets increased irrespective of whether the tx fails or not
21    // must be done after computing the new address
22    state.increase_account_nonce(&tx_input.from);
23    state.subtract_tx_gas(&tx_input.from, tx_input.gas_limit, tx_input.gas_price);
24
25    let tx_cache = TxCache::new(state.get_arc());
26
27    let (tx_result, new_address, blockchain_updates) = execute_deploy(
28        tx_input,
29        contract_path.to_vec(),
30        code_metadata,
31        tx_cache,
32        runtime,
33        f,
34    );
35
36    blockchain_updates.apply(state);
37
38    (new_address, tx_result)
39}
40
41/// Runs transaction and produces a `TxResult`.
42pub fn execute_deploy<F>(
43    mut tx_input: TxInput,
44    contract_path: Vec<u8>,
45    code_metadata: VMCodeMetadata,
46    tx_cache: TxCache,
47    runtime: &RuntimeRef,
48    f: F,
49) -> (TxResult, VMAddress, BlockchainUpdate)
50where
51    F: RuntimeInstanceCallLambda,
52{
53    let new_address = tx_cache.get_new_address(&tx_input.from);
54    tx_input.to = new_address.clone();
55    let tx_context = TxContext::new(runtime.clone(), tx_input, tx_cache);
56    let tx_input_ref = tx_context.input_ref();
57
58    if let Err(err) = tx_context
59        .tx_cache
60        .subtract_egld_balance(&tx_input_ref.from, &tx_input_ref.egld_value)
61    {
62        return (
63            TxResult::from_panic_obj(&err),
64            VMAddress::zero(),
65            BlockchainUpdate::empty(),
66        );
67    }
68    tx_context.create_new_contract(
69        &new_address,
70        contract_path,
71        code_metadata,
72        tx_input_ref.from.clone(),
73    );
74    tx_context
75        .tx_cache
76        .increase_egld_balance(&new_address, &tx_input_ref.egld_value);
77
78    let tx_context = runtime.execute(tx_context, f);
79
80    let (tx_result, blockchain_updates) = tx_context.into_results();
81    (tx_result, new_address, blockchain_updates)
82}