@@ -32,7 +32,8 @@ use ethereum_types::{U256, U512, H256, Address};
32
32
33
33
use vm:: {
34
34
self , ActionParams , ParamsType , ActionValue , CallType , MessageCallResult ,
35
- ContractCreateResult , CreateContractAddress , ReturnData , GasLeft , Schedule
35
+ ContractCreateResult , CreateContractAddress , ReturnData , GasLeft , Schedule ,
36
+ TrapKind , TrapError
36
37
} ;
37
38
38
39
use evm:: CostType ;
@@ -103,6 +104,7 @@ enum InstructionResult<Gas> {
103
104
apply : bool ,
104
105
} ,
105
106
StopExecution ,
107
+ Trap ( TrapKind ) ,
106
108
}
107
109
108
110
enum Never { }
@@ -161,6 +163,7 @@ pub enum InterpreterResult {
161
163
Done ( vm:: Result < GasLeft > ) ,
162
164
/// The VM can continue to run.
163
165
Continue ,
166
+ Trap ( TrapKind ) ,
164
167
}
165
168
166
169
impl From < vm:: Error > for InterpreterResult {
@@ -182,22 +185,89 @@ pub struct Interpreter<Cost: CostType> {
182
185
valid_jump_destinations : Option < Arc < BitSet > > ,
183
186
gasometer : Option < Gasometer < Cost > > ,
184
187
stack : VecStack < U256 > ,
188
+ resume_output_range : Option < ( U256 , U256 ) > ,
189
+ resume_result : Option < InstructionResult < Cost > > ,
190
+ last_stack_ret_len : usize ,
185
191
_type : PhantomData < Cost > ,
186
192
}
187
193
188
- impl < Cost : CostType > vm:: Vm for Interpreter < Cost > {
189
- fn exec ( & mut self , ext : & mut vm:: Ext ) -> vm:: Result < GasLeft > {
194
+ impl < Cost : ' static + CostType > vm:: Exec for Interpreter < Cost > {
195
+ fn exec ( mut self : Box < Self > , ext : & mut vm:: Ext ) -> vm:: ExecTrapResult < GasLeft > {
190
196
loop {
191
197
let result = self . step ( ext) ;
192
198
match result {
193
199
InterpreterResult :: Continue => { } ,
194
- InterpreterResult :: Done ( value) => return value,
200
+ InterpreterResult :: Done ( value) => return Ok ( value) ,
201
+ InterpreterResult :: Trap ( trap) => match trap {
202
+ TrapKind :: Call ( params) => {
203
+ return Err ( TrapError :: Call ( params, self ) ) ;
204
+ } ,
205
+ TrapKind :: Create ( params, address) => {
206
+ return Err ( TrapError :: Create ( params, address, self ) ) ;
207
+ } ,
208
+ } ,
195
209
InterpreterResult :: Stopped => panic ! ( "Attempted to execute an already stopped VM." )
196
210
}
197
211
}
198
212
}
199
213
}
200
214
215
+ impl < Cost : ' static + CostType > vm:: ResumeCall for Interpreter < Cost > {
216
+ fn resume_call ( mut self : Box < Self > , result : MessageCallResult ) -> Box < vm:: Exec > {
217
+ {
218
+ let this = & mut * self ;
219
+ let ( out_off, out_size) = this. resume_output_range . take ( ) . expect ( "Box<ResumeCall> is obtained from a call opcode; resume_output_range is always set after those opcodes are executed; qed" ) ;
220
+
221
+ match result {
222
+ MessageCallResult :: Success ( gas_left, data) => {
223
+ let output = this. mem . writeable_slice ( out_off, out_size) ;
224
+ let len = cmp:: min ( output. len ( ) , data. len ( ) ) ;
225
+ ( & mut output[ ..len] ) . copy_from_slice ( & data[ ..len] ) ;
226
+
227
+ this. return_data = data;
228
+ this. stack . push ( U256 :: one ( ) ) ;
229
+ this. resume_result = Some ( InstructionResult :: UnusedGas ( Cost :: from_u256 ( gas_left) . expect ( "Gas left cannot be greater than current one" ) ) ) ;
230
+ } ,
231
+ MessageCallResult :: Reverted ( gas_left, data) => {
232
+ let output = this. mem . writeable_slice ( out_off, out_size) ;
233
+ let len = cmp:: min ( output. len ( ) , data. len ( ) ) ;
234
+ ( & mut output[ ..len] ) . copy_from_slice ( & data[ ..len] ) ;
235
+
236
+ this. return_data = data;
237
+ this. stack . push ( U256 :: zero ( ) ) ;
238
+ this. resume_result = Some ( InstructionResult :: UnusedGas ( Cost :: from_u256 ( gas_left) . expect ( "Gas left cannot be greater than current one" ) ) ) ;
239
+ } ,
240
+ MessageCallResult :: Failed => {
241
+ this. stack . push ( U256 :: zero ( ) ) ;
242
+ this. resume_result = Some ( InstructionResult :: Ok ) ;
243
+ } ,
244
+ }
245
+ }
246
+ self
247
+ }
248
+ }
249
+
250
+ impl < Cost : ' static + CostType > vm:: ResumeCreate for Interpreter < Cost > {
251
+ fn resume_create ( mut self : Box < Self > , result : ContractCreateResult ) -> Box < vm:: Exec > {
252
+ match result {
253
+ ContractCreateResult :: Created ( address, gas_left) => {
254
+ self . stack . push ( address_to_u256 ( address) ) ;
255
+ self . resume_result = Some ( InstructionResult :: UnusedGas ( Cost :: from_u256 ( gas_left) . expect ( "Gas left cannot be greater." ) ) ) ;
256
+ } ,
257
+ ContractCreateResult :: Reverted ( gas_left, return_data) => {
258
+ self . stack . push ( U256 :: zero ( ) ) ;
259
+ self . return_data = return_data;
260
+ self . resume_result = Some ( InstructionResult :: UnusedGas ( Cost :: from_u256 ( gas_left) . expect ( "Gas left cannot be greater." ) ) ) ;
261
+ } ,
262
+ ContractCreateResult :: Failed => {
263
+ self . stack . push ( U256 :: zero ( ) ) ;
264
+ self . resume_result = Some ( InstructionResult :: Ok ) ;
265
+ } ,
266
+ }
267
+ self
268
+ }
269
+ }
270
+
201
271
impl < Cost : CostType > Interpreter < Cost > {
202
272
/// Create a new `Interpreter` instance with shared cache.
203
273
pub fn new ( mut params : ActionParams , cache : Arc < SharedCache > , schedule : & Schedule , depth : usize ) -> Interpreter < Cost > {
@@ -215,6 +285,9 @@ impl<Cost: CostType> Interpreter<Cost> {
215
285
do_trace : true ,
216
286
mem : Vec :: new ( ) ,
217
287
return_data : ReturnData :: empty ( ) ,
288
+ last_stack_ret_len : 0 ,
289
+ resume_output_range : None ,
290
+ resume_result : None ,
218
291
_type : PhantomData ,
219
292
}
220
293
}
@@ -244,50 +317,57 @@ impl<Cost: CostType> Interpreter<Cost> {
244
317
/// Inner helper function for step.
245
318
#[ inline( always) ]
246
319
fn step_inner ( & mut self , ext : & mut vm:: Ext ) -> Result < Never , InterpreterResult > {
247
- let opcode = self . reader . code [ self . reader . position ] ;
248
- let instruction = Instruction :: from_u8 ( opcode) ;
249
- self . reader . position += 1 ;
250
-
251
- // TODO: make compile-time removable if too much of a performance hit.
252
- self . do_trace = self . do_trace && ext. trace_next_instruction (
253
- self . reader . position - 1 , opcode, self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas . as_u256 ( ) ,
254
- ) ;
255
-
256
- let instruction = match instruction {
257
- Some ( i) => i,
258
- None => return Err ( InterpreterResult :: Done ( Err ( vm:: Error :: BadInstruction {
259
- instruction : opcode
260
- } ) ) ) ,
261
- } ;
320
+ let result = match self . resume_result . take ( ) {
321
+ Some ( result) => result,
322
+ None => {
323
+ let opcode = self . reader . code [ self . reader . position ] ;
324
+ let instruction = Instruction :: from_u8 ( opcode) ;
325
+ self . reader . position += 1 ;
326
+
327
+ // TODO: make compile-time removable if too much of a performance hit.
328
+ self . do_trace = self . do_trace && ext. trace_next_instruction (
329
+ self . reader . position - 1 , opcode, self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas . as_u256 ( ) ,
330
+ ) ;
262
331
263
- let info = instruction. info ( ) ;
264
- self . verify_instruction ( ext, instruction, info) ?;
332
+ let instruction = match instruction {
333
+ Some ( i) => i,
334
+ None => return Err ( InterpreterResult :: Done ( Err ( vm:: Error :: BadInstruction {
335
+ instruction : opcode
336
+ } ) ) ) ,
337
+ } ;
265
338
266
- // Calculate gas cost
267
- let requirements = self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . requirements ( ext, instruction, info, & self . stack , self . mem . size ( ) ) ?;
268
- if self . do_trace {
269
- ext. trace_prepare_execute ( self . reader . position - 1 , opcode, requirements. gas_cost . as_u256 ( ) ) ;
270
- }
339
+ let info = instruction. info ( ) ;
340
+ self . last_stack_ret_len = info. ret ;
341
+ self . verify_instruction ( ext, instruction, info) ?;
342
+
343
+ // Calculate gas cost
344
+ let requirements = self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . requirements ( ext, instruction, info, & self . stack , self . mem . size ( ) ) ?;
345
+ if self . do_trace {
346
+ ext. trace_prepare_execute ( self . reader . position - 1 , opcode, requirements. gas_cost . as_u256 ( ) , Self :: mem_written ( instruction, & self . stack ) , Self :: store_written ( instruction, & self . stack ) ) ;
347
+ }
271
348
272
- self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . verify_gas ( & requirements. gas_cost ) ?;
273
- self . mem . expand ( requirements. memory_required_size ) ;
274
- self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_mem_gas = requirements. memory_total_gas ;
275
- self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas = self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas - requirements. gas_cost ;
349
+ self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . verify_gas ( & requirements. gas_cost ) ?;
350
+ self . mem . expand ( requirements. memory_required_size ) ;
351
+ self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_mem_gas = requirements. memory_total_gas ;
352
+ self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas = self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas - requirements. gas_cost ;
276
353
277
- evm_debug ! ( { self . informant. before_instruction( self . reader. position, instruction, info, & self . gasometer. as_mut( ) . expect( GASOMETER_PROOF ) . current_gas, & self . stack) } ) ;
354
+ evm_debug ! ( { self . informant. before_instruction( self . reader. position, instruction, info, & self . gasometer. as_mut( ) . expect( GASOMETER_PROOF ) . current_gas, & self . stack) } ) ;
278
355
279
- let ( mem_written, store_written) = match self . do_trace {
280
- true => ( Self :: mem_written ( instruction, & self . stack ) , Self :: store_written ( instruction, & self . stack ) ) ,
281
- false => ( None , None ) ,
282
- } ;
356
+ // Execute instruction
357
+ let current_gas = self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas ;
358
+ let result = self . exec_instruction (
359
+ current_gas, ext, instruction, requirements. provide_gas
360
+ ) ?;
283
361
284
- // Execute instruction
285
- let current_gas = self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas ;
286
- let result = self . exec_instruction (
287
- current_gas , ext , instruction , requirements . provide_gas
288
- ) ? ;
362
+ evm_debug ! ( { self . informant . after_instruction ( instruction) } ) ;
363
+
364
+ result
365
+ } ,
366
+ } ;
289
367
290
- evm_debug ! ( { self . informant. after_instruction( instruction) } ) ;
368
+ if let InstructionResult :: Trap ( trap) = result {
369
+ return Err ( InterpreterResult :: Trap ( trap) ) ;
370
+ }
291
371
292
372
if let InstructionResult :: UnusedGas ( ref gas) = result {
293
373
self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas = self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas + * gas;
@@ -296,9 +376,8 @@ impl<Cost: CostType> Interpreter<Cost> {
296
376
if self . do_trace {
297
377
ext. trace_executed (
298
378
self . gasometer . as_mut ( ) . expect ( GASOMETER_PROOF ) . current_gas . as_u256 ( ) ,
299
- self . stack . peek_top ( info. ret ) ,
300
- mem_written. map ( |( o, s) | ( o, & ( self . mem [ o..o+s] ) ) ) ,
301
- store_written,
379
+ self . stack . peek_top ( self . last_stack_ret_len ) ,
380
+ & self . mem ,
302
381
) ;
303
382
}
304
383
@@ -451,21 +530,24 @@ impl<Cost: CostType> Interpreter<Cost> {
451
530
452
531
let contract_code = self . mem . read_slice ( init_off, init_size) ;
453
532
454
- let create_result = ext. create ( & create_gas. as_u256 ( ) , & endowment, contract_code, address_scheme) ;
533
+ let create_result = ext. create ( & create_gas. as_u256 ( ) , & endowment, contract_code, address_scheme, true ) ;
455
534
return match create_result {
456
- ContractCreateResult :: Created ( address, gas_left) => {
535
+ Ok ( ContractCreateResult :: Created ( address, gas_left) ) => {
457
536
self . stack . push ( address_to_u256 ( address) ) ;
458
537
Ok ( InstructionResult :: UnusedGas ( Cost :: from_u256 ( gas_left) . expect ( "Gas left cannot be greater." ) ) )
459
538
} ,
460
- ContractCreateResult :: Reverted ( gas_left, return_data) => {
539
+ Ok ( ContractCreateResult :: Reverted ( gas_left, return_data) ) => {
461
540
self . stack . push ( U256 :: zero ( ) ) ;
462
541
self . return_data = return_data;
463
542
Ok ( InstructionResult :: UnusedGas ( Cost :: from_u256 ( gas_left) . expect ( "Gas left cannot be greater." ) ) )
464
543
} ,
465
- ContractCreateResult :: Failed => {
544
+ Ok ( ContractCreateResult :: Failed ) => {
466
545
self . stack . push ( U256 :: zero ( ) ) ;
467
546
Ok ( InstructionResult :: Ok )
468
547
} ,
548
+ Err ( trap) => {
549
+ Ok ( InstructionResult :: Trap ( trap) )
550
+ } ,
469
551
} ;
470
552
} ,
471
553
instructions:: CALL | instructions:: CALLCODE | instructions:: DELEGATECALL | instructions:: STATICCALL => {
@@ -524,32 +606,37 @@ impl<Cost: CostType> Interpreter<Cost> {
524
606
525
607
let call_result = {
526
608
let input = self . mem . read_slice ( in_off, in_size) ;
527
- ext. call ( & call_gas. as_u256 ( ) , sender_address, receive_address, value, input, & code_address, call_type)
609
+ ext. call ( & call_gas. as_u256 ( ) , sender_address, receive_address, value, input, & code_address, call_type, true )
528
610
} ;
529
611
530
- let output = self . mem . writeable_slice ( out_off, out_size) ;
612
+ self . resume_output_range = Some ( ( out_off, out_size) ) ;
531
613
532
614
return match call_result {
533
- MessageCallResult :: Success ( gas_left, data) => {
615
+ Ok ( MessageCallResult :: Success ( gas_left, data) ) => {
616
+ let output = self . mem . writeable_slice ( out_off, out_size) ;
534
617
let len = cmp:: min ( output. len ( ) , data. len ( ) ) ;
535
618
( & mut output[ ..len] ) . copy_from_slice ( & data[ ..len] ) ;
536
619
537
620
self . stack . push ( U256 :: one ( ) ) ;
538
621
self . return_data = data;
539
622
Ok ( InstructionResult :: UnusedGas ( Cost :: from_u256 ( gas_left) . expect ( "Gas left cannot be greater than current one" ) ) )
540
623
} ,
541
- MessageCallResult :: Reverted ( gas_left, data) => {
624
+ Ok ( MessageCallResult :: Reverted ( gas_left, data) ) => {
625
+ let output = self . mem . writeable_slice ( out_off, out_size) ;
542
626
let len = cmp:: min ( output. len ( ) , data. len ( ) ) ;
543
627
( & mut output[ ..len] ) . copy_from_slice ( & data[ ..len] ) ;
544
628
545
629
self . stack . push ( U256 :: zero ( ) ) ;
546
630
self . return_data = data;
547
631
Ok ( InstructionResult :: UnusedGas ( Cost :: from_u256 ( gas_left) . expect ( "Gas left cannot be greater than current one" ) ) )
548
632
} ,
549
- MessageCallResult :: Failed => {
633
+ Ok ( MessageCallResult :: Failed ) => {
550
634
self . stack . push ( U256 :: zero ( ) ) ;
551
635
Ok ( InstructionResult :: Ok )
552
636
} ,
637
+ Err ( trap) => {
638
+ Ok ( InstructionResult :: Trap ( trap) )
639
+ } ,
553
640
} ;
554
641
} ,
555
642
instructions:: RETURN => {
@@ -1095,10 +1182,10 @@ mod tests {
1095
1182
use rustc_hex:: FromHex ;
1096
1183
use vmtype:: VMType ;
1097
1184
use factory:: Factory ;
1098
- use vm:: { self , Vm , ActionParams , ActionValue } ;
1185
+ use vm:: { self , Exec , ActionParams , ActionValue } ;
1099
1186
use vm:: tests:: { FakeExt , test_finalize} ;
1100
1187
1101
- fn interpreter ( params : ActionParams , ext : & vm:: Ext ) -> Box < Vm > {
1188
+ fn interpreter ( params : ActionParams , ext : & vm:: Ext ) -> Box < Exec > {
1102
1189
Factory :: new ( VMType :: Interpreter , 1 ) . create ( params, ext. schedule ( ) , ext. depth ( ) )
1103
1190
}
1104
1191
@@ -1118,7 +1205,7 @@ mod tests {
1118
1205
1119
1206
let gas_left = {
1120
1207
let mut vm = interpreter ( params, & ext) ;
1121
- test_finalize ( vm. exec ( & mut ext) ) . unwrap ( )
1208
+ test_finalize ( vm. exec ( & mut ext) . ok ( ) . unwrap ( ) ) . unwrap ( )
1122
1209
} ;
1123
1210
1124
1211
assert_eq ! ( ext. calls. len( ) , 1 ) ;
@@ -1140,7 +1227,7 @@ mod tests {
1140
1227
1141
1228
let err = {
1142
1229
let mut vm = interpreter ( params, & ext) ;
1143
- test_finalize ( vm. exec ( & mut ext) ) . err ( ) . unwrap ( )
1230
+ test_finalize ( vm. exec ( & mut ext) . ok ( ) . unwrap ( ) ) . err ( ) . unwrap ( )
1144
1231
} ;
1145
1232
1146
1233
assert_eq ! ( err, :: vm:: Error :: OutOfBounds ) ;
0 commit comments