sui_adapter_latest/
error.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use move_binary_format::{
5    errors::{Location, VMError},
6    file_format::FunctionDefinitionIndex,
7};
8use move_core_types::{
9    language_storage::ModuleId,
10    vm_status::{StatusCode, StatusType},
11};
12use sui_types::error::ExecutionError;
13use sui_types::execution_status::{ExecutionFailureStatus, MoveLocation, MoveLocationOpt};
14
15pub(crate) fn convert_vm_error_impl(
16    error: VMError,
17    abort_module_id_relocation_fn: &impl Fn(&ModuleId) -> ModuleId,
18    function_name_resolution_fn: &impl Fn(&ModuleId, FunctionDefinitionIndex) -> Option<String>,
19) -> ExecutionError {
20    let kind = match (error.major_status(), error.sub_status(), error.location()) {
21        (StatusCode::EXECUTED, _, _) => {
22            // If we have an error the status probably shouldn't ever be Executed
23            debug_assert!(false, "VmError shouldn't ever report successful execution");
24            ExecutionFailureStatus::VMInvariantViolation
25        }
26        (StatusCode::ABORTED, None, _) => {
27            debug_assert!(false, "No abort code");
28            // this is a Move VM invariant violation, the code should always be there
29            ExecutionFailureStatus::VMInvariantViolation
30        }
31        (StatusCode::ABORTED, Some(code), Location::Module(id)) => {
32            let abort_location_id = abort_module_id_relocation_fn(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 = function_name_resolution_fn(id, FunctionDefinitionIndex(function));
37            ExecutionFailureStatus::MoveAbort(
38                MoveLocation {
39                    module: abort_location_id,
40                    function,
41                    instruction,
42                    function_name,
43                },
44                code,
45            )
46        }
47        (StatusCode::OUT_OF_GAS, _, _) => ExecutionFailureStatus::InsufficientGas,
48        (_, _, location) => match error.major_status().status_type() {
49            StatusType::Execution => {
50                debug_assert!(error.major_status() != StatusCode::ABORTED);
51                let location = match location {
52                    Location::Module(id) => {
53                        let offset = error.offsets().first().copied().map(|(f, i)| (f.0, i));
54                        debug_assert!(
55                            offset.is_some(),
56                            "Move should set the location on all execution errors. Error {error}"
57                        );
58                        let (function, instruction) = offset.unwrap_or((0, 0));
59                        let function_name =
60                            function_name_resolution_fn(id, FunctionDefinitionIndex(function));
61                        Some(MoveLocation {
62                            module: id.clone(),
63                            function,
64                            instruction,
65                            function_name,
66                        })
67                    }
68                    _ => None,
69                };
70                ExecutionFailureStatus::MovePrimitiveRuntimeError(MoveLocationOpt(location))
71            }
72            StatusType::Validation
73            | StatusType::Verification
74            | StatusType::Deserialization
75            | StatusType::Unknown => ExecutionFailureStatus::VMVerificationOrDeserializationError,
76            StatusType::InvariantViolation => ExecutionFailureStatus::VMInvariantViolation,
77        },
78    };
79    ExecutionError::new_with_source(kind, error)
80}