Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit 1e9aebb

Browse files
authored
Resumable EVM and heap-allocated callstack (#9360)
* Add new Vm trappable interface * Exec/Resume interface * Basic implementation of CallCreateExecutive * Implement resume_call and resume_create for executive * Move convertion to call/create result to separate function * Implement consume that converts resumable to non-resumable * Use consume for Executive::call/create * Resumable EVM * Implement tracing mode without needing subtracers * Implement vmtracer so it doesn't require extra structs for subtracing * Use the new tracing mode in executive * Fix most of the linting errors for cargo build * Add the concept of stack_depth * Add back crossbeam * Fix some test compile * Fix prefix address test * Fix evm crate tests * Fix wasm crate test compile * Fix wasm runner compile * Fix jsontests compile * Fix evmbin compile * Fix an issue with create nonce and better vm tracing interface * Fix linting * Fix evmbin compile * Fix unconfirmed_substate and static_flag * Fix an issue in create address logic * Fix top-level tracing * Handle builtin tracing * Fix suicide and reward tracing index stack * Fix an issue where trap conflicts with tracing * Fix an issue in parent step vm tracing * Fix revert tracing * Fix evmbin tests * Remove params clone * Fix TODO proofs * Fix jsontests compile * Fix evmbin merge issue * Fix wasm merge issue * Fix wasm test * Fix ethcore merge warnings * Fix evmbin compile * Better expect messages and add some trace::skip_one asserts
1 parent 61ec361 commit 1e9aebb

File tree

24 files changed

+1469
-808
lines changed

24 files changed

+1469
-808
lines changed

ethcore/evm/src/evm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl Finalize for Error {
6262
}
6363

6464
/// Cost calculation type. For low-gas usage we calculate costs using usize instead of U256
65-
pub trait CostType: Sized + From<usize> + Copy
65+
pub trait CostType: Sized + From<usize> + Copy + Send
6666
+ ops::Mul<Output=Self> + ops::Div<Output=Self> + ops::Add<Output=Self> +ops::Sub<Output=Self>
6767
+ ops::Shr<usize, Output=Self> + ops::Shl<usize, Output=Self>
6868
+ cmp::Ord + fmt::Debug {

ethcore/evm/src/factory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//! Evm factory.
1818
//!
1919
use std::sync::Arc;
20-
use vm::{Vm, Schedule};
20+
use vm::{Exec, Schedule};
2121
use ethereum_types::U256;
2222
use super::vm::ActionParams;
2323
use super::interpreter::SharedCache;
@@ -33,7 +33,7 @@ pub struct Factory {
3333
impl Factory {
3434
/// Create fresh instance of VM
3535
/// Might choose implementation depending on supplied gas.
36-
pub fn create(&self, params: ActionParams, schedule: &Schedule, depth: usize) -> Box<Vm> {
36+
pub fn create(&self, params: ActionParams, schedule: &Schedule, depth: usize) -> Box<Exec> {
3737
match self.evm {
3838
VMType::Interpreter => if Self::can_fit_in_usize(&params.gas) {
3939
Box::new(super::interpreter::Interpreter::<usize>::new(params, self.evm_cache.clone(), schedule, depth))

ethcore/evm/src/interpreter/mod.rs

Lines changed: 144 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ use ethereum_types::{U256, U512, H256, Address};
3232

3333
use vm::{
3434
self, ActionParams, ParamsType, ActionValue, CallType, MessageCallResult,
35-
ContractCreateResult, CreateContractAddress, ReturnData, GasLeft, Schedule
35+
ContractCreateResult, CreateContractAddress, ReturnData, GasLeft, Schedule,
36+
TrapKind, TrapError
3637
};
3738

3839
use evm::CostType;
@@ -103,6 +104,7 @@ enum InstructionResult<Gas> {
103104
apply: bool,
104105
},
105106
StopExecution,
107+
Trap(TrapKind),
106108
}
107109

108110
enum Never {}
@@ -161,6 +163,7 @@ pub enum InterpreterResult {
161163
Done(vm::Result<GasLeft>),
162164
/// The VM can continue to run.
163165
Continue,
166+
Trap(TrapKind),
164167
}
165168

166169
impl From<vm::Error> for InterpreterResult {
@@ -182,22 +185,89 @@ pub struct Interpreter<Cost: CostType> {
182185
valid_jump_destinations: Option<Arc<BitSet>>,
183186
gasometer: Option<Gasometer<Cost>>,
184187
stack: VecStack<U256>,
188+
resume_output_range: Option<(U256, U256)>,
189+
resume_result: Option<InstructionResult<Cost>>,
190+
last_stack_ret_len: usize,
185191
_type: PhantomData<Cost>,
186192
}
187193

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> {
190196
loop {
191197
let result = self.step(ext);
192198
match result {
193199
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+
},
195209
InterpreterResult::Stopped => panic!("Attempted to execute an already stopped VM.")
196210
}
197211
}
198212
}
199213
}
200214

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+
201271
impl<Cost: CostType> Interpreter<Cost> {
202272
/// Create a new `Interpreter` instance with shared cache.
203273
pub fn new(mut params: ActionParams, cache: Arc<SharedCache>, schedule: &Schedule, depth: usize) -> Interpreter<Cost> {
@@ -215,6 +285,9 @@ impl<Cost: CostType> Interpreter<Cost> {
215285
do_trace: true,
216286
mem: Vec::new(),
217287
return_data: ReturnData::empty(),
288+
last_stack_ret_len: 0,
289+
resume_output_range: None,
290+
resume_result: None,
218291
_type: PhantomData,
219292
}
220293
}
@@ -244,50 +317,57 @@ impl<Cost: CostType> Interpreter<Cost> {
244317
/// Inner helper function for step.
245318
#[inline(always)]
246319
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+
);
262331

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+
};
265338

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+
}
271348

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;
276353

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) });
278355

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+
)?;
283361

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+
};
289367

290-
evm_debug!({ self.informant.after_instruction(instruction) });
368+
if let InstructionResult::Trap(trap) = result {
369+
return Err(InterpreterResult::Trap(trap));
370+
}
291371

292372
if let InstructionResult::UnusedGas(ref gas) = result {
293373
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> {
296376
if self.do_trace {
297377
ext.trace_executed(
298378
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,
302381
);
303382
}
304383

@@ -451,21 +530,24 @@ impl<Cost: CostType> Interpreter<Cost> {
451530

452531
let contract_code = self.mem.read_slice(init_off, init_size);
453532

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);
455534
return match create_result {
456-
ContractCreateResult::Created(address, gas_left) => {
535+
Ok(ContractCreateResult::Created(address, gas_left)) => {
457536
self.stack.push(address_to_u256(address));
458537
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater.")))
459538
},
460-
ContractCreateResult::Reverted(gas_left, return_data) => {
539+
Ok(ContractCreateResult::Reverted(gas_left, return_data)) => {
461540
self.stack.push(U256::zero());
462541
self.return_data = return_data;
463542
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater.")))
464543
},
465-
ContractCreateResult::Failed => {
544+
Ok(ContractCreateResult::Failed) => {
466545
self.stack.push(U256::zero());
467546
Ok(InstructionResult::Ok)
468547
},
548+
Err(trap) => {
549+
Ok(InstructionResult::Trap(trap))
550+
},
469551
};
470552
},
471553
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {
@@ -524,32 +606,37 @@ impl<Cost: CostType> Interpreter<Cost> {
524606

525607
let call_result = {
526608
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)
528610
};
529611

530-
let output = self.mem.writeable_slice(out_off, out_size);
612+
self.resume_output_range = Some((out_off, out_size));
531613

532614
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);
534617
let len = cmp::min(output.len(), data.len());
535618
(&mut output[..len]).copy_from_slice(&data[..len]);
536619

537620
self.stack.push(U256::one());
538621
self.return_data = data;
539622
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one")))
540623
},
541-
MessageCallResult::Reverted(gas_left, data) => {
624+
Ok(MessageCallResult::Reverted(gas_left, data)) => {
625+
let output = self.mem.writeable_slice(out_off, out_size);
542626
let len = cmp::min(output.len(), data.len());
543627
(&mut output[..len]).copy_from_slice(&data[..len]);
544628

545629
self.stack.push(U256::zero());
546630
self.return_data = data;
547631
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one")))
548632
},
549-
MessageCallResult::Failed => {
633+
Ok(MessageCallResult::Failed) => {
550634
self.stack.push(U256::zero());
551635
Ok(InstructionResult::Ok)
552636
},
637+
Err(trap) => {
638+
Ok(InstructionResult::Trap(trap))
639+
},
553640
};
554641
},
555642
instructions::RETURN => {
@@ -1095,10 +1182,10 @@ mod tests {
10951182
use rustc_hex::FromHex;
10961183
use vmtype::VMType;
10971184
use factory::Factory;
1098-
use vm::{self, Vm, ActionParams, ActionValue};
1185+
use vm::{self, Exec, ActionParams, ActionValue};
10991186
use vm::tests::{FakeExt, test_finalize};
11001187

1101-
fn interpreter(params: ActionParams, ext: &vm::Ext) -> Box<Vm> {
1188+
fn interpreter(params: ActionParams, ext: &vm::Ext) -> Box<Exec> {
11021189
Factory::new(VMType::Interpreter, 1).create(params, ext.schedule(), ext.depth())
11031190
}
11041191

@@ -1118,7 +1205,7 @@ mod tests {
11181205

11191206
let gas_left = {
11201207
let mut vm = interpreter(params, &ext);
1121-
test_finalize(vm.exec(&mut ext)).unwrap()
1208+
test_finalize(vm.exec(&mut ext).ok().unwrap()).unwrap()
11221209
};
11231210

11241211
assert_eq!(ext.calls.len(), 1);
@@ -1140,7 +1227,7 @@ mod tests {
11401227

11411228
let err = {
11421229
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()
11441231
};
11451232

11461233
assert_eq!(err, ::vm::Error::OutOfBounds);

0 commit comments

Comments
 (0)