use crate::helpers::Ctx;
use revm::{
context_interface::context::ContextError,
interpreter::{
CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterTypes,
},
Database, Inspector,
};
use std::time::{Duration, Instant};
#[derive(Debug, Clone, Copy)]
pub struct TimeLimit {
duration: Duration,
execution_start: Instant,
}
impl TimeLimit {
pub fn new(duration: Duration) -> Self {
Self { duration, execution_start: Instant::now() }
}
pub fn has_elapsed(&self) -> bool {
self.execution_start.elapsed() >= self.duration
}
pub fn reset(&mut self) {
self.execution_start = Instant::now();
}
pub fn elapsed(&self) -> Duration {
self.execution_start.elapsed()
}
}
macro_rules! check_timeout {
($self:ident, $ctx:ident) => {
if $self.has_elapsed() {
$ctx.error = Err(ContextError::Custom("timeout during evm execution".to_string()));
}
};
}
impl<Db: Database, Int: InterpreterTypes> Inspector<Ctx<Db>, Int> for TimeLimit {
fn initialize_interp(&mut self, _interp: &mut Interpreter<Int>, _ctx: &mut Ctx<Db>) {
self.reset();
}
fn call(&mut self, ctx: &mut Ctx<Db>, _inputs: &mut CallInputs) -> Option<CallOutcome> {
check_timeout!(self, ctx);
None
}
fn call_end(&mut self, ctx: &mut Ctx<Db>, _inputs: &CallInputs, _outcome: &mut CallOutcome) {
check_timeout!(self, ctx);
}
fn create(&mut self, ctx: &mut Ctx<Db>, _inputs: &mut CreateInputs) -> Option<CreateOutcome> {
check_timeout!(self, ctx);
None
}
fn create_end(
&mut self,
ctx: &mut Ctx<Db>,
_inputs: &CreateInputs,
_outcome: &mut CreateOutcome,
) {
check_timeout!(self, ctx);
}
}