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 (mut tx_result, new_address, blockchain_updates) = execute_deploy(
28        tx_input.clone(),
29        contract_path.to_vec(),
30        code_metadata,
31        tx_cache,
32        runtime,
33        f,
34    );
35
36    if tx_result.result_status.is_success() {
37        blockchain_updates.apply(state);
38    }
39
40    // TODO: not sure if this is the best place to put this, investigate
41    tx_result.append_internal_vm_errors_event_log(&tx_input);
42
43    (new_address, tx_result)
44}
45
46/// Runs transaction and produces a `TxResult`.
47pub fn execute_deploy<F>(
48    mut tx_input: TxInput,
49    contract_path: Vec<u8>,
50    code_metadata: VMCodeMetadata,
51    tx_cache: TxCache,
52    runtime: &RuntimeRef,
53    f: F,
54) -> (TxResult, VMAddress, BlockchainUpdate)
55where
56    F: RuntimeInstanceCallLambda,
57{
58    let new_address = tx_cache.get_new_address(&tx_input.from);
59    tx_input.to = new_address.clone();
60    let tx_context = TxContext::new(runtime.clone(), tx_input, tx_cache);
61    let tx_input_ref = tx_context.input_ref();
62
63    if let Err(err) = tx_context
64        .tx_cache
65        .subtract_egld_balance(&tx_input_ref.from, &tx_input_ref.egld_value)
66    {
67        return (
68            TxResult::from_panic_obj(&err),
69            VMAddress::zero(),
70            BlockchainUpdate::empty(),
71        );
72    }
73    tx_context.create_new_contract(
74        &new_address,
75        contract_path,
76        code_metadata,
77        tx_input_ref.from.clone(),
78    );
79    tx_context
80        .tx_cache
81        .increase_egld_balance(&new_address, &tx_input_ref.egld_value);
82
83    let tx_context = runtime.execute(tx_context, f);
84
85    let (tx_result, blockchain_updates) = tx_context.into_results();
86    (tx_result, new_address, blockchain_updates)
87}