zksync_node_api_server 0.1.0

ZKsync API server
use thiserror::Error;
use zksync_multivm::interface::{Halt, TxRevertReason};

#[derive(Debug, Error)]
pub(crate) enum SandboxExecutionError {
    #[error("Account validation failed: {0}")]
    AccountValidationFailed(String),
    #[error("Failed to charge fee: {0}")]
    FailedToChargeFee(String),
    #[error("Paymaster validation failed: {0}")]
    PaymasterValidationFailed(String),
    #[error("Pre-paymaster preparation failed: {0}")]
    PrePaymasterPreparationFailed(String),
    #[error("From is not an account")]
    FromIsNotAnAccount,
    #[error("Bootloader failure: {0}")]
    BootloaderFailure(String),
    #[error("Revert: {0}")]
    Revert(String, Vec<u8>),
    #[error("Failed to pay for the transaction: {0}")]
    FailedToPayForTransaction(String),
    #[error("Bootloader-based tx failed")]
    InnerTxError,
    #[error(
    "Virtual machine entered unexpected state. Please contact developers and provide transaction details \
        that caused this error. Error description: {0}"
    )]
    UnexpectedVMBehavior(String),
}

impl From<Halt> for SandboxExecutionError {
    fn from(value: Halt) -> Self {
        match value {
            Halt::FailedToChargeFee(reason) => Self::FailedToChargeFee(reason.to_string()),
            Halt::FromIsNotAnAccount => Self::FromIsNotAnAccount,
            Halt::InnerTxError => Self::InnerTxError,
            Halt::Unknown(reason) => Self::BootloaderFailure(reason.to_string()),
            Halt::ValidationFailed(reason) => Self::AccountValidationFailed(reason.to_string()),
            Halt::PaymasterValidationFailed(reason) => {
                Self::PaymasterValidationFailed(reason.to_string())
            }
            Halt::PrePaymasterPreparationFailed(reason) => {
                Self::PrePaymasterPreparationFailed(reason.to_string())
            }
            Halt::UnexpectedVMBehavior(reason) => Self::UnexpectedVMBehavior(reason),
            Halt::BootloaderOutOfGas => {
                Self::UnexpectedVMBehavior("bootloader is out of gas".to_string())
            }
            Halt::NotEnoughGasProvided => Self::UnexpectedVMBehavior(
                "The bootloader did not contain enough gas to execute the transaction".to_string(),
            ),
            revert_reason @ Halt::FailedToMarkFactoryDependencies(_) => {
                Self::Revert(revert_reason.to_string(), vec![])
            }
            Halt::PayForTxFailed(reason) => Self::FailedToPayForTransaction(reason.to_string()),
            Halt::TooBigGasLimit => Self::Revert(Halt::TooBigGasLimit.to_string(), vec![]),
            Halt::MissingInvocationLimitReached => Self::InnerTxError,
            Halt::VMPanic => Self::UnexpectedVMBehavior("VM panic".to_string()),
            Halt::FailedToSetL2Block(reason) => SandboxExecutionError::Revert(reason, vec![]),
            Halt::FailedToAppendTransactionToL2Block(reason) => {
                SandboxExecutionError::Revert(reason, vec![])
            }
            Halt::TracerCustom(reason) => SandboxExecutionError::Revert(reason, vec![]),
            Halt::ValidationOutOfGas => Self::AccountValidationFailed(
                "The validation of the transaction ran out of gas".to_string(),
            ),
            Halt::FailedToPublishCompressedBytecodes => {
                Self::UnexpectedVMBehavior("Failed to publish compressed bytecodes".to_string())
            }
        }
    }
}

impl From<TxRevertReason> for SandboxExecutionError {
    fn from(reason: TxRevertReason) -> Self {
        match reason {
            TxRevertReason::TxReverted(reason) => SandboxExecutionError::Revert(
                reason.to_user_friendly_string(),
                reason.encoded_data(),
            ),
            TxRevertReason::Halt(halt) => SandboxExecutionError::from(halt),
        }
    }
}