multiversx_chain_vm/host/runtime/
runtime_instance_call_default.rs1use multiversx_chain_core::types::ReturnCode;
2use multiversx_chain_vm_executor::{BreakpointValue, InstanceCallResult, VMHooksEarlyExit};
3
4use crate::{
5 host::{
6 context::{GasUsed, TxFunctionName, TxResult},
7 vm_hooks::vh_early_exit::ASYNC_CALL_EARLY_EXIT_CODE,
8 },
9 vm_err_msg,
10};
11
12use super::{RuntimeInstanceCall, RuntimeInstanceCallLambda};
13
14pub struct RuntimeInstanceCallLambdaDefault;
18
19impl RuntimeInstanceCallLambda for RuntimeInstanceCallLambdaDefault {
20 fn call(self, instance_call: RuntimeInstanceCall<'_>) {
21 default_instance_call(instance_call);
22 }
23
24 fn override_function_name(&self) -> Option<TxFunctionName> {
25 None
26 }
27}
28
29fn default_instance_call(instance_call: RuntimeInstanceCall<'_>) {
30 if !instance_call.instance.has_function(instance_call.func_name) {
31 *instance_call.tx_context_ref.result_lock() = TxResult::from_function_not_found();
32 return;
33 }
34
35 let result = instance_call
36 .instance
37 .call(instance_call.func_name, instance_call.gas_limit);
38 let mut tx_result_ref = instance_call.tx_context_ref.result_lock();
39 if let Some(error_tx_result) = instance_call_error_result(result) {
40 *tx_result_ref = error_tx_result;
41 }
42
43 if tx_result_ref.result_status.is_success() {
44 let gas_used = instance_call
45 .instance
46 .get_points_used()
47 .expect("error retrieving gas used");
48 tx_result_ref.gas_used = GasUsed::SomeGas(gas_used);
49 } else {
50 tx_result_ref.gas_used =
51 GasUsed::AllGas(instance_call.tx_context_ref.tx_input_box.gas_limit);
52 }
53}
54
55fn instance_call_error_result(call_result: InstanceCallResult) -> Option<TxResult> {
56 match call_result {
57 InstanceCallResult::Ok => None,
58 InstanceCallResult::FunctionNotFound => Some(TxResult::from_function_not_found()),
59 InstanceCallResult::RuntimeError(error) => Some(TxResult::from_vm_error(error.to_string())),
60 InstanceCallResult::VMHooksEarlyExit(vm_hooks_early_exit) => {
61 vm_hooks_early_exit_result(vm_hooks_early_exit)
62 }
63 InstanceCallResult::Breakpoint(BreakpointValue::None) => {
64 Some(TxResult::from_vm_error("invalid breakpoint".to_string()))
65 }
66 InstanceCallResult::Breakpoint(BreakpointValue::OutOfGas) => Some(TxResult::from_error(
67 ReturnCode::OutOfGas,
68 vm_err_msg::NOT_ENOUGH_GAS,
69 )),
70 InstanceCallResult::Breakpoint(BreakpointValue::MemoryLimit) => {
71 Some(TxResult::from_vm_error("memory limit".to_string()))
72 }
73 }
74}
75
76fn vm_hooks_early_exit_result(vm_hooks_early_exit: VMHooksEarlyExit) -> Option<TxResult> {
77 if vm_hooks_early_exit.code == ASYNC_CALL_EARLY_EXIT_CODE {
78 None
79 } else {
80 Some(TxResult::from_error(
81 ReturnCode::from_u64(vm_hooks_early_exit.code).expect("invalid return code"),
82 vm_hooks_early_exit.message.into_owned(),
83 ))
84 }
85}