Skip to content

Commit

Permalink
Fix: explicit EVM call stack
Browse files Browse the repository at this point in the history
  • Loading branch information
birchmd committed Oct 26, 2022
1 parent 66d36f1 commit 01c502b
Show file tree
Hide file tree
Showing 9 changed files with 412 additions and 186 deletions.
87 changes: 87 additions & 0 deletions runtime/src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ mod macros;
mod system;

use crate::{CallScheme, ExitReason, Handler, Opcode, Runtime};
use alloc::vec::Vec;
use core::cmp::min;
use primitive_types::{H160, H256, U256};

pub enum Control<H: Handler> {
Continue,
Expand Down Expand Up @@ -59,3 +62,87 @@ pub fn eval<H: Handler>(state: &mut Runtime, opcode: Opcode, handler: &mut H) ->
_ => handle_other(state, opcode, handler),
}
}

pub fn finish_create(
runtime: &mut Runtime,
reason: ExitReason,
address: Option<H160>,
return_data: Vec<u8>,
) -> Result<(), ExitReason> {
runtime.return_data_buffer = return_data;
let create_address: H256 = address.map(|a| a.into()).unwrap_or_default();

match reason {
ExitReason::Succeed(_) => {
runtime.machine.stack_mut().push(create_address)?;
Ok(())
}
ExitReason::Revert(_) => {
runtime.machine.stack_mut().push(H256::default())?;
Ok(())
}
ExitReason::Error(_) => {
runtime.machine.stack_mut().push(H256::default())?;
Ok(())
}
ExitReason::Fatal(e) => {
runtime.machine.stack_mut().push(H256::default())?;
Err(e.into())
}
}
}

pub fn finish_call(
runtime: &mut Runtime,
out_len: U256,
out_offset: U256,
reason: ExitReason,
return_data: Vec<u8>,
) -> Result<(), ExitReason> {
runtime.return_data_buffer = return_data;
let target_len = min(out_len, U256::from(runtime.return_data_buffer.len()));

match reason {
ExitReason::Succeed(_) => {
match runtime.machine.memory_mut().copy_large(
out_offset,
U256::zero(),
target_len,
&runtime.return_data_buffer[..],
) {
Ok(()) => {
let mut value = H256::default();
U256::one().to_big_endian(&mut value[..]);
runtime.machine.stack_mut().push(value)?;
Ok(())
}
Err(_) => {
runtime.machine.stack_mut().push(H256::default())?;
Ok(())
}
}
}
ExitReason::Revert(_) => {
runtime.machine.stack_mut().push(H256::default())?;

let _ = runtime.machine.memory_mut().copy_large(
out_offset,
U256::zero(),
target_len,
&runtime.return_data_buffer[..],
);

Ok(())
}
ExitReason::Error(_) => {
runtime.machine.stack_mut().push(H256::default())?;

Ok(())
}
ExitReason::Fatal(e) => {
runtime.machine.stack_mut().push(H256::default())?;

Err(e.into())
}
}
}
82 changes: 11 additions & 71 deletions runtime/src/eval/system.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use super::Control;
use crate::{
CallScheme, Capture, Context, CreateScheme, ExitError, ExitFatal, ExitReason, ExitSucceed,
Handler, Runtime, Transfer,
CallScheme, Capture, Context, CreateScheme, ExitError, ExitFatal, ExitSucceed, Handler,
Runtime, Transfer,
};
use alloc::vec::Vec;
use core::cmp::min;
use primitive_types::{H256, U256};
use sha3::{Digest, Keccak256};

Expand Down Expand Up @@ -297,32 +296,12 @@ pub fn create<H: Handler>(runtime: &mut Runtime, is_create2: bool, handler: &mut

match handler.create(runtime.context.address, scheme, value, code, None) {
Capture::Exit((reason, address, return_data)) => {
runtime.return_data_buffer = return_data;
let create_address: H256 = address.map(|a| a.into()).unwrap_or_default();

match reason {
ExitReason::Succeed(_) => {
push!(runtime, create_address);
Control::Continue
}
ExitReason::Revert(_) => {
push!(runtime, H256::default());
Control::Continue
}
ExitReason::Error(_) => {
push!(runtime, H256::default());
Control::Continue
}
ExitReason::Fatal(e) => {
push!(runtime, H256::default());
Control::Exit(e.into())
}
match super::finish_create(runtime, reason, address, return_data) {
Ok(()) => Control::Continue,
Err(e) => Control::Exit(e),
}
}
Capture::Trap(interrupt) => {
push!(runtime, H256::default());
Control::CreateInterrupt(interrupt)
}
Capture::Trap(interrupt) => Control::CreateInterrupt(interrupt),
}
}

Expand Down Expand Up @@ -408,53 +387,14 @@ pub fn call<H: Handler>(runtime: &mut Runtime, scheme: CallScheme, handler: &mut
context,
) {
Capture::Exit((reason, return_data)) => {
runtime.return_data_buffer = return_data;
let target_len = min(out_len, U256::from(runtime.return_data_buffer.len()));

match reason {
ExitReason::Succeed(_) => {
match runtime.machine.memory_mut().copy_large(
out_offset,
U256::zero(),
target_len,
&runtime.return_data_buffer[..],
) {
Ok(()) => {
push_u256!(runtime, U256::one());
Control::Continue
}
Err(_) => {
push_u256!(runtime, U256::zero());
Control::Continue
}
}
}
ExitReason::Revert(_) => {
push_u256!(runtime, U256::zero());

let _ = runtime.machine.memory_mut().copy_large(
out_offset,
U256::zero(),
target_len,
&runtime.return_data_buffer[..],
);

Control::Continue
}
ExitReason::Error(_) => {
push_u256!(runtime, U256::zero());

Control::Continue
}
ExitReason::Fatal(e) => {
push_u256!(runtime, U256::zero());

Control::Exit(e.into())
}
match super::finish_call(runtime, out_len, out_offset, reason, return_data) {
Ok(()) => Control::Continue,
Err(e) => Control::Exit(e),
}
}
Capture::Trap(interrupt) => {
push!(runtime, H256::default());
runtime.return_data_len = out_len;
runtime.return_dat_offset = out_offset;
Control::CallInterrupt(interrupt)
}
}
Expand Down
28 changes: 5 additions & 23 deletions runtime/src/interrupt.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{ExitFatal, Handler, Runtime};
use crate::{Handler, Runtime};

/// Interrupt resolution.
pub enum Resolve<'a, 'config, H: Handler> {
Expand All @@ -10,40 +10,22 @@ pub enum Resolve<'a, 'config, H: Handler> {

/// Create interrupt resolution.
pub struct ResolveCreate<'a, 'config> {
runtime: &'a mut Runtime<'config>,
_runtime: &'a mut Runtime<'config>,
}

impl<'a, 'config> ResolveCreate<'a, 'config> {
pub(crate) fn new(runtime: &'a mut Runtime<'config>) -> Self {
Self { runtime }
}
}

impl<'a, 'config> Drop for ResolveCreate<'a, 'config> {
fn drop(&mut self) {
self.runtime.status = Err(ExitFatal::UnhandledInterrupt.into());
self.runtime
.machine
.exit(ExitFatal::UnhandledInterrupt.into());
Self { _runtime: runtime }
}
}

/// Call interrupt resolution.
pub struct ResolveCall<'a, 'config> {
runtime: &'a mut Runtime<'config>,
_runtime: &'a mut Runtime<'config>,
}

impl<'a, 'config> ResolveCall<'a, 'config> {
pub(crate) fn new(runtime: &'a mut Runtime<'config>) -> Self {
Self { runtime }
}
}

impl<'a, 'config> Drop for ResolveCall<'a, 'config> {
fn drop(&mut self) {
self.runtime.status = Err(ExitFatal::UnhandledInterrupt.into());
self.runtime
.machine
.exit(ExitFatal::UnhandledInterrupt.into());
Self { _runtime: runtime }
}
}
28 changes: 28 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub use crate::interrupt::{Resolve, ResolveCall, ResolveCreate};

use alloc::rc::Rc;
use alloc::vec::Vec;
use primitive_types::{H160, U256};

macro_rules! step {
( $self:expr, $handler:expr, $return:tt $($err:path)?; $($ok:path)? ) => ({
Expand Down Expand Up @@ -110,6 +111,8 @@ pub struct Runtime<'config> {
machine: Machine,
status: Result<(), ExitReason>,
return_data_buffer: Vec<u8>,
return_data_len: U256,
return_dat_offset: U256,
context: Context,
_config: &'config Config,
}
Expand All @@ -126,6 +129,8 @@ impl<'config> Runtime<'config> {
machine: Machine::new(code, data, config.stack_limit, config.memory_limit),
status: Ok(()),
return_data_buffer: Vec::new(),
return_data_len: U256::zero(),
return_dat_offset: U256::zero(),
context,
_config: config,
}
Expand Down Expand Up @@ -158,6 +163,29 @@ impl<'config> Runtime<'config> {
step!(self, handler, return;)
}
}

pub fn finish_create(
&mut self,
reason: ExitReason,
address: Option<H160>,
return_data: Vec<u8>,
) -> Result<(), ExitReason> {
eval::finish_create(self, reason, address, return_data)
}

pub fn finish_call(
&mut self,
reason: ExitReason,
return_data: Vec<u8>,
) -> Result<(), ExitReason> {
eval::finish_call(
self,
self.return_data_len,
self.return_dat_offset,
reason,
return_data,
)
}
}

/// Runtime configuration.
Expand Down
Loading

0 comments on commit 01c502b

Please sign in to comment.