use crate::logging::AdapterLogSchema;
use aptos_logger::prelude::*;
use aptos_types::account_config::ChainSpecificAccountInfo;
use move_deps::{
move_binary_format::errors::VMError,
move_core_types::vm_status::{StatusCode, VMStatus},
};
pub const EACCOUNT_FROZEN: u64 = 1000; pub const EBAD_ACCOUNT_AUTHENTICATION_KEY: u64 = 1001; pub const ESEQUENCE_NUMBER_TOO_OLD: u64 = 1002; pub const ESEQUENCE_NUMBER_TOO_NEW: u64 = 1003; pub const EACCOUNT_DOES_NOT_EXIST: u64 = 1004; pub const ECANT_PAY_GAS_DEPOSIT: u64 = 1005; pub const ETRANSACTION_EXPIRED: u64 = 1006; pub const EBAD_CHAIN_ID: u64 = 1007; pub const ESCRIPT_NOT_ALLOWED: u64 = 1008;
pub const EMODULE_NOT_ALLOWED: u64 = 1009;
pub const EINVALID_WRITESET_SENDER: u64 = 1010; pub const ESEQUENCE_NUMBER_TOO_BIG: u64 = 1011;
pub const EBAD_TRANSACTION_FEE_CURRENCY: u64 = 1012;
pub const ESECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH: u64 = 1013;
pub const ESEQ_NONCE_NONCE_INVALID: u64 = 1014;
const INVALID_STATE: u8 = 3;
const INVALID_ARGUMENT: u8 = 1;
const LIMIT_EXCEEDED: u8 = 2;
fn error_split(code: u64) -> (u8, u64) {
let reason = code & 0xffff;
let category = ((code >> 16) & 0xff) as u8;
(category, reason)
}
pub fn convert_prologue_error(
chain_specific_info: &ChainSpecificAccountInfo,
error: VMError,
log_context: &AdapterLogSchema,
) -> Result<(), VMStatus> {
let status = error.into_vm_status();
Err(match status {
VMStatus::Executed => VMStatus::Executed,
VMStatus::MoveAbort(location, code)
if !chain_specific_info.is_account_module_abort(&location) =>
{
let (category, reason) = error_split(code);
log_context.alert();
error!(
*log_context,
"[aptos_vm] Unexpected prologue Move abort: {:?}::{:?} (Category: {:?} Reason: {:?})",
location, code, category, reason,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
VMStatus::MoveAbort(location, code) => {
let new_major_status = match error_split(code) {
(INVALID_STATE, EACCOUNT_FROZEN) => StatusCode::SENDING_ACCOUNT_FROZEN,
(INVALID_ARGUMENT, EBAD_ACCOUNT_AUTHENTICATION_KEY) => StatusCode::INVALID_AUTH_KEY,
(INVALID_ARGUMENT, ESEQUENCE_NUMBER_TOO_OLD) => StatusCode::SEQUENCE_NUMBER_TOO_OLD,
(INVALID_ARGUMENT, ESEQUENCE_NUMBER_TOO_NEW) => StatusCode::SEQUENCE_NUMBER_TOO_NEW,
(INVALID_ARGUMENT, EACCOUNT_DOES_NOT_EXIST) => {
StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST
}
(INVALID_ARGUMENT, ECANT_PAY_GAS_DEPOSIT) => {
StatusCode::INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE
}
(INVALID_ARGUMENT, ETRANSACTION_EXPIRED) => StatusCode::TRANSACTION_EXPIRED,
(INVALID_ARGUMENT, EBAD_CHAIN_ID) => StatusCode::BAD_CHAIN_ID,
(INVALID_STATE, ESCRIPT_NOT_ALLOWED) => StatusCode::UNKNOWN_SCRIPT,
(INVALID_STATE, EMODULE_NOT_ALLOWED) => StatusCode::INVALID_MODULE_PUBLISHER,
(INVALID_ARGUMENT, EINVALID_WRITESET_SENDER) => StatusCode::REJECTED_WRITE_SET,
(LIMIT_EXCEEDED, ESEQUENCE_NUMBER_TOO_BIG) => StatusCode::SEQUENCE_NUMBER_TOO_BIG,
(INVALID_ARGUMENT, EBAD_TRANSACTION_FEE_CURRENCY) => {
StatusCode::BAD_TRANSACTION_FEE_CURRENCY
}
(INVALID_ARGUMENT, ESECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH) => {
StatusCode::SECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH
}
(INVALID_ARGUMENT, ESEQ_NONCE_NONCE_INVALID) => StatusCode::SEQUENCE_NONCE_INVALID,
(category, reason) => {
log_context.alert();
error!(
*log_context,
"[aptos_vm] Unexpected prologue Move abort: {:?}::{:?} (Category: {:?} Reason: {:?})",
location, code, category, reason,
);
return Err(VMStatus::Error(
StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION,
));
}
};
VMStatus::Error(new_major_status)
}
status @ VMStatus::ExecutionFailure { .. } | status @ VMStatus::Error(_) => {
log_context.alert();
error!(
*log_context,
"[aptos_vm] Unexpected prologue error: {:?}", status
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
})
}
pub fn convert_epilogue_error(
chain_specific_info: &ChainSpecificAccountInfo,
error: VMError,
log_context: &AdapterLogSchema,
) -> Result<(), VMStatus> {
let status = error.into_vm_status();
Err(match status {
VMStatus::Executed => VMStatus::Executed,
VMStatus::MoveAbort(location, code)
if !chain_specific_info.is_account_module_abort(&location) =>
{
let (category, reason) = error_split(code);
log_context.alert();
error!(
*log_context,
"[aptos_vm] Unexpected success epilogue Move abort: {:?}::{:?} (Category: {:?} Reason: {:?})",
location, code, category, reason,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
VMStatus::MoveAbort(location, code) => match error_split(code) {
(LIMIT_EXCEEDED, ECANT_PAY_GAS_DEPOSIT) => VMStatus::MoveAbort(location, code),
(category, reason) => {
log_context.alert();
error!(
*log_context,
"[aptos_vm] Unexpected success epilogue Move abort: {:?}::{:?} (Category: {:?} Reason: {:?})",
location, code, category, reason,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
},
status => {
log_context.alert();
error!(
*log_context,
"[aptos_vm] Unexpected success epilogue error: {:?}", status,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
})
}
pub fn expect_only_successful_execution(
error: VMError,
function_name: &str,
log_context: &AdapterLogSchema,
) -> Result<(), VMStatus> {
let status = error.into_vm_status();
Err(match status {
VMStatus::Executed => VMStatus::Executed,
status => {
log_context.alert();
error!(
*log_context,
"[aptos_vm] Unexpected error from known Move function, '{}'. Error: {:?}",
function_name,
status,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
})
}