1+ use crate :: helpers:: Ctx ;
12use revm:: {
3+ context_interface:: context:: ContextError ,
24 interpreter:: {
3- CallInputs , CallOutcome , CreateInputs , CreateOutcome , EOFCreateInputs , Gas ,
4- InstructionResult , Interpreter , InterpreterResult , InterpreterTypes ,
5+ CallInputs , CallOutcome , CreateInputs , CreateOutcome , EOFCreateInputs , Interpreter ,
6+ InterpreterTypes ,
57 } ,
6- primitives:: Bytes ,
7- Inspector ,
8+ Database , Inspector ,
89} ;
910use std:: time:: { Duration , Instant } ;
1011
11- const CALL_TIMEOUT : CallOutcome = CallOutcome {
12- result : InterpreterResult {
13- result : InstructionResult :: CallTooDeep ,
14- output : Bytes :: new ( ) ,
15- gas : Gas :: new_spent ( 0 ) ,
16- } ,
17- memory_offset : 0 ..0 ,
18- } ;
19-
20- const CREATE_TIMEOUT : CreateOutcome = CreateOutcome {
21- result : InterpreterResult {
22- result : InstructionResult :: CallTooDeep ,
23- output : Bytes :: new ( ) ,
24- gas : Gas :: new_spent ( 0 ) ,
25- } ,
26- address : None ,
27- } ;
28-
2912/// A revm [`Inspector`] that limits wallclock time spent on execution.
3013///
3114/// This inspector will stop execution at the beginning and end of each
@@ -41,14 +24,8 @@ const CREATE_TIMEOUT: CreateOutcome = CreateOutcome {
4124/// - any invalid opcode
4225///
4326/// When execution is terminated by the timer, it will result in a
44- /// [`InstructionResult::CallTooDeep`]. This is somewhat unintutive. `revm`
45- /// uses the [`InstructionResult`] enum to represent possible outcomes of a
46- /// opcode. It requires that the inspector's outcome is a valid
47- /// [`InstructionResult`], but does not provide a way to represent a custom
48- /// outcome. This means that the inspector must overload an existing outcome.
49- /// `CallTooDeep` is used here because it is effectively unreachable in normal
50- /// `evm` execution due to [EIP-150] call gas forwarding rules, and therefore
51- /// overloading it is unlikely to cause issues.
27+ /// [`ContextError::Custom`], which will be propagated as an
28+ /// [`EVMError::Custom`] to the caller of the EVM interpreter.
5229///
5330/// ## Usage Note
5431///
@@ -63,6 +40,7 @@ const CREATE_TIMEOUT: CreateOutcome = CreateOutcome {
6340/// discarded.
6441///
6542/// [EIP-150]: https://eips.ethereum.org/EIPS/eip-150
43+ /// [`EVMError::Custom`]: revm::context::result::EVMError::Custom
6644#[ derive( Debug , Clone , Copy ) ]
6745pub struct TimeLimit {
6846 duration : Duration ,
@@ -93,63 +71,60 @@ impl TimeLimit {
9371 }
9472}
9573
96- impl < Ctx , Int : InterpreterTypes > Inspector < Ctx , Int > for TimeLimit {
97- fn initialize_interp ( & mut self , _interp : & mut Interpreter < Int > , _context : & mut Ctx ) {
74+ macro_rules! check_timeout {
75+ ( $self: ident, $ctx: ident) => {
76+ if $self. has_elapsed( ) {
77+ $ctx. error = Err ( ContextError :: Custom ( "timeout during evm execution" . to_string( ) ) ) ;
78+ }
79+ } ;
80+ }
81+
82+ impl < Db : Database , Int : InterpreterTypes > Inspector < Ctx < Db > , Int > for TimeLimit {
83+ fn initialize_interp ( & mut self , _interp : & mut Interpreter < Int > , _ctx : & mut Ctx < Db > ) {
9884 self . reset ( ) ;
9985 }
10086
101- fn call ( & mut self , _context : & mut Ctx , _inputs : & mut CallInputs ) -> Option < CallOutcome > {
102- if self . has_elapsed ( ) {
103- return Some ( CALL_TIMEOUT ) ;
104- }
87+ fn call ( & mut self , ctx : & mut Ctx < Db > , _inputs : & mut CallInputs ) -> Option < CallOutcome > {
88+ check_timeout ! ( self , ctx) ;
10589
10690 None
10791 }
10892
109- fn call_end ( & mut self , _context : & mut Ctx , _inputs : & CallInputs , outcome : & mut CallOutcome ) {
110- if self . has_elapsed ( ) {
111- * outcome = CALL_TIMEOUT ;
112- }
93+ fn call_end ( & mut self , ctx : & mut Ctx < Db > , _inputs : & CallInputs , _outcome : & mut CallOutcome ) {
94+ check_timeout ! ( self , ctx) ;
11395 }
11496
115- fn create ( & mut self , _context : & mut Ctx , _inputs : & mut CreateInputs ) -> Option < CreateOutcome > {
116- if self . has_elapsed ( ) {
117- return Some ( CREATE_TIMEOUT ) ;
118- }
97+ fn create ( & mut self , ctx : & mut Ctx < Db > , _inputs : & mut CreateInputs ) -> Option < CreateOutcome > {
98+ check_timeout ! ( self , ctx) ;
99+
119100 None
120101 }
121102
122103 fn create_end (
123104 & mut self ,
124- _context : & mut Ctx ,
105+ ctx : & mut Ctx < Db > ,
125106 _inputs : & CreateInputs ,
126- outcome : & mut CreateOutcome ,
107+ _outcome : & mut CreateOutcome ,
127108 ) {
128- if self . has_elapsed ( ) {
129- * outcome = CREATE_TIMEOUT ;
130- }
109+ check_timeout ! ( self , ctx) ;
131110 }
132111
133112 fn eofcreate (
134113 & mut self ,
135- _context : & mut Ctx ,
114+ ctx : & mut Ctx < Db > ,
136115 _inputs : & mut EOFCreateInputs ,
137116 ) -> Option < CreateOutcome > {
138- if self . has_elapsed ( ) {
139- return Some ( CREATE_TIMEOUT ) ;
140- }
117+ check_timeout ! ( self , ctx) ;
141118
142119 None
143120 }
144121
145122 fn eofcreate_end (
146123 & mut self ,
147- _context : & mut Ctx ,
124+ ctx : & mut Ctx < Db > ,
148125 _inputs : & EOFCreateInputs ,
149- outcome : & mut CreateOutcome ,
126+ _outcome : & mut CreateOutcome ,
150127 ) {
151- if self . has_elapsed ( ) {
152- * outcome = CREATE_TIMEOUT ;
153- }
128+ check_timeout ! ( self , ctx) ;
154129 }
155130}
0 commit comments