multiversx_chain_vm/host/vm_hooks/
vh_handler.rs

1mod vh_blockchain;
2mod vh_call_value;
3mod vh_crypto;
4mod vh_endpoint_arg;
5mod vh_endpoint_finish;
6mod vh_error;
7mod vh_log;
8mod vh_managed_types;
9mod vh_send;
10mod vh_storage;
11
12use multiversx_chain_vm_executor::VMHooksEarlyExit;
13
14use crate::{blockchain::state::AccountData, host::context::TxErrorTrace, schedule::GasSchedule};
15
16use super::VMHooksContext;
17
18/// Defines all methods that can handle VM hooks. They are spread out over several files.
19#[derive(Debug)]
20pub struct VMHooksHandler<C: VMHooksContext> {
21    pub(crate) context: C,
22}
23
24impl<C: VMHooksContext> VMHooksHandler<C> {
25    pub fn new(context: C) -> Self {
26        VMHooksHandler { context }
27    }
28
29    /// Reference to the gas schedule. Provided for convenience.
30    fn gas_schedule(&self) -> &GasSchedule {
31        self.context.gas_schedule()
32    }
33
34    /// Consume amount of gas. Provided for convenience.
35    fn use_gas(&mut self, gas: u64) -> Result<(), VMHooksEarlyExit> {
36        self.context.use_gas(gas)
37    }
38
39    /// Shortcut for consuming gas for data copies, based on copied data length.
40    fn use_gas_for_data_copy(&mut self, num_bytes_copied: usize) -> Result<(), VMHooksEarlyExit> {
41        self.context.use_gas(
42            num_bytes_copied as u64
43                * self
44                    .context
45                    .gas_schedule()
46                    .base_operation_cost
47                    .data_copy_per_byte,
48        )
49    }
50
51    /// For ownership reasons, needs to return a clone.
52    ///
53    /// Can be optimized, but is not a priority right now.
54    fn current_account_data(&self) -> AccountData {
55        self.context
56            .account_data(&self.context.input_ref().to)
57            .expect("missing current account")
58    }
59
60    /// Logs an error, in 2 ways:
61    /// - in the `error_trace` field of the `TxResult`,
62    /// - in the standard log, at info level.
63    ///
64    /// TODO: call from more places in the codebase, similar to the Go VM.
65    ///
66    /// TODO: consider re-design in both Go and Rust VM,
67    /// the current implementation is very implementation-dependent.
68    fn error_trace(&mut self, trace_message: &str) {
69        let func_name = self.context.input_ref().func_name.clone();
70
71        log::info!("Error in {func_name}: {trace_message}");
72
73        let mut tx_result = self.context.result_lock();
74        tx_result.error_trace.push(TxErrorTrace {
75            function_name: func_name,
76            error_trace_message: trace_message.to_string(),
77            additional_info: Vec::new(),
78        });
79    }
80}