use std::collections::HashMap;
use anyhow::Result;
use evmc_sys::evmc_call_kind;
use thiserror::Error;
use crate::types::Raw;
#[remain::sorted]
#[derive(Error, Debug, PartialEq)]
pub enum VmError {
#[error("argument out of range")]
ArgumentOutOfRange,
#[error("bad jump destination")]
BadJumpDestination,
#[error("call depth exceeded")]
CallDepthExceeded,
#[error("contract validation failure")]
ContractValidationFailure,
#[error("`{0}`")]
CustomizedError(String),
#[error("failure")]
Failure,
#[error("internal error")]
InternalError,
#[error("invalid instruction")]
InvalidInstruction,
#[error("invalid memory access")]
InvalidMemoryAccess,
#[error("out of gas")]
OutOfGas,
#[error("out of memory")]
OutOfMemory,
#[error("precompile failure")]
PrecompileFailure,
#[error("rejected")]
Rejected,
#[error("revert")]
Revert,
#[error("stack overflow")]
StackOverflow,
#[error("stack underflow")]
StackUnderflow,
#[error("static mode violation")]
StaticModeViolation,
#[error("undefined instruction")]
UndefinedInstruction,
#[error("there shoulbe be a caller(sender) for the message")]
UnknownCaller,
#[error("wasm trap")]
WasmTrap,
#[error("wasm unreachable instruction")]
WasmUnreachableInstruction,
}
#[cfg_attr(any(feature = "debug", test), derive(Debug))]
#[derive(Default)]
pub struct VMResult {
pub(crate) gas_left: i64,
pub output_data: Vec<u8>,
pub(crate) create_address: Option<Raw>,
}
#[cfg_attr(any(feature = "debug", test), derive(Debug))]
#[derive(PartialEq)]
pub enum Flags {
Default = 0,
Static = 1,
}
#[cfg_attr(any(feature = "debug", test), derive(Debug))]
pub struct VMMessage<'a> {
pub kind: evmc_call_kind,
pub flags: Flags,
pub depth: i32,
pub gas: i64,
pub destination: Raw,
pub sender: &'a Raw,
pub input_data: Option<&'a Vec<u8>>,
pub value: Raw,
pub code: Option<&'a Vec<u8>>,
pub create2_salt: Option<()>,
}
#[cfg_attr(any(feature = "debug", test), derive(Debug))]
pub struct VMMessageBuilder<'a> {
pub kind: evmc_call_kind,
pub flags: Flags,
pub depth: i32,
pub gas: i64,
pub destination: Option<&'a Raw>,
pub sender: Option<&'a Raw>,
pub input_data: Option<&'a Vec<u8>>,
pub value: Raw,
pub code: Option<&'a Vec<u8>>,
pub create2_salt: Option<()>,
}
impl<'a> VMMessageBuilder<'a> {
#[inline]
pub fn read_only(mut self) -> Self {
self.flags = Flags::Static;
self
}
#[inline]
pub fn destination(mut self, addr: &'a Raw) -> Self {
self.destination = Some(addr);
self
}
#[inline]
pub fn sender(mut self, addr: &'a Raw) -> Self {
self.sender = Some(addr);
self
}
#[inline]
pub fn build(self) -> Result<VMMessage<'a>> {
let VMMessageBuilder {
kind,
flags,
depth,
gas,
destination,
sender,
input_data,
value,
code,
create2_salt,
} = self;
if let Some(sender) = sender {
let destination = if let Some(destination) = destination {
*destination
} else {
Raw::from(0u32)
};
return Ok(VMMessage {
kind,
flags,
depth,
gas,
destination,
sender,
input_data,
value,
code,
create2_salt,
});
}
Err(VmError::UnknownCaller.into())
}
pub fn create2(self, _salt: ()) -> Self {
unimplemented!()
}
}
impl Default for VMMessageBuilder<'_> {
fn default() -> Self {
Self {
kind: evmc_call_kind::EVMC_CALL,
flags: Flags::Default,
depth: i32::MAX,
value: Raw::from(0u32),
gas: 0,
destination: None,
sender: None,
input_data: None,
code: None,
create2_salt: None,
}
}
}
pub trait RT {
fn execute(&mut self, msg: VMMessage) -> Result<VMResult>;
fn deploy(&mut self, msg: VMMessage) -> Result<()>;
fn get_storage(&self, account: &[u8; 20]) -> Option<&HashMap<[u8; 32], [u8; 32]>>;
}