1use move_binary_format::{
5 errors::{Location, VMError},
6 file_format::FunctionDefinitionIndex,
7};
8use move_core_types::{
9 resolver::MoveResolver,
10 vm_status::{StatusCode, StatusType},
11};
12use move_vm_runtime::move_vm::MoveVM;
13use sui_types::error::{ExecutionError, SuiError};
14use sui_types::execution_status::{ExecutionFailureStatus, MoveLocation, MoveLocationOpt};
15
16pub(crate) fn convert_vm_error<S: MoveResolver<Err = SuiError>>(
17 error: VMError,
18 vm: &MoveVM,
19 state_view: &S,
20) -> ExecutionError {
21 let kind = match (error.major_status(), error.sub_status(), error.location()) {
22 (StatusCode::EXECUTED, _, _) => {
23 debug_assert!(false, "VmError shouldn't ever report successful execution");
25 ExecutionFailureStatus::VMInvariantViolation
26 }
27 (StatusCode::ABORTED, None, _) => {
28 debug_assert!(false, "No abort code");
29 ExecutionFailureStatus::VMInvariantViolation
31 }
32 (StatusCode::ABORTED, Some(code), Location::Module(id)) => {
33 let offset = error.offsets().first().copied().map(|(f, i)| (f.0, i));
34 debug_assert!(offset.is_some(), "Move should set the location on aborts");
35 let (function, instruction) = offset.unwrap_or((0, 0));
36 let function_name = vm.load_module(id, state_view).ok().map(|module| {
37 let fdef = module.function_def_at(FunctionDefinitionIndex(function));
38 let fhandle = module.function_handle_at(fdef.function);
39 module.identifier_at(fhandle.name).to_string()
40 });
41 ExecutionFailureStatus::MoveAbort(
42 MoveLocation {
43 module: id.clone(),
44 function,
45 instruction,
46 function_name,
47 },
48 code,
49 )
50 }
51 (StatusCode::OUT_OF_GAS, _, _) => ExecutionFailureStatus::InsufficientGas,
52 (_, _, location) => match error.major_status().status_type() {
53 StatusType::Execution => {
54 debug_assert!(error.major_status() != StatusCode::ABORTED);
55 let location = match location {
56 Location::Module(id) => {
57 let offset = error.offsets().first().copied().map(|(f, i)| (f.0, i));
58 debug_assert!(
59 offset.is_some(),
60 "Move should set the location on all execution errors. Error {error}"
61 );
62 let (function, instruction) = offset.unwrap_or((0, 0));
63 let function_name = vm.load_module(id, state_view).ok().map(|module| {
64 let fdef = module.function_def_at(FunctionDefinitionIndex(function));
65 let fhandle = module.function_handle_at(fdef.function);
66 module.identifier_at(fhandle.name).to_string()
67 });
68 Some(MoveLocation {
69 module: id.clone(),
70 function,
71 instruction,
72 function_name,
73 })
74 }
75 _ => None,
76 };
77 ExecutionFailureStatus::MovePrimitiveRuntimeError(MoveLocationOpt(location))
78 }
79 StatusType::Validation
80 | StatusType::Verification
81 | StatusType::Deserialization
82 | StatusType::Unknown => ExecutionFailureStatus::VMVerificationOrDeserializationError,
83 StatusType::InvariantViolation => ExecutionFailureStatus::VMInvariantViolation,
84 },
85 };
86 ExecutionError::new_with_source(kind, error)
87}