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

Decouple virtual machines #6184

Merged
merged 7 commits into from
Aug 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ethcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ semver = "0.6"
stats = { path = "../util/stats" }
time = "0.1"
transient-hashmap = "0.4"
vm = { path = "vm" }
wasm = { path = "wasm" }

[dev-dependencies]
native-contracts = { path = "native_contracts", features = ["test_contracts"] }
Expand Down
1 change: 1 addition & 0 deletions ethcore/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ethjson = { path = "../../json" }
lazy_static = "0.2"
log = "0.3"
rlp = { path = "../../util/rlp" }
vm = { path = "../vm" }
parity-wasm = "0.12"
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }

Expand Down
2 changes: 1 addition & 1 deletion ethcore/evm/src/benches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern crate test;
use self::test::{Bencher, black_box};

use util::*;
use evm::action_params::ActionParams;
use vm::ActionParams;
use evm::{self, Factory, VMType};
use evm::tests::FakeExt;

Expand Down
147 changes: 2 additions & 145 deletions ethcore/evm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,142 +17,8 @@
//! Evm interface.

use std::{ops, cmp, fmt};
use util::{U128, U256, U512, trie};
use action_params::ActionParams;
use {Ext};

use super::wasm;

/// Evm errors.
#[derive(Debug, Clone, PartialEq)]
pub enum Error {
/// `OutOfGas` is returned when transaction execution runs out of gas.
/// The state should be reverted to the state from before the
/// transaction execution. But it does not mean that transaction
/// was invalid. Balance still should be transfered and nonce
/// should be increased.
OutOfGas,
/// `BadJumpDestination` is returned when execution tried to move
/// to position that wasn't marked with JUMPDEST instruction
BadJumpDestination {
/// Position the code tried to jump to.
destination: usize
},
/// `BadInstructions` is returned when given instruction is not supported
BadInstruction {
/// Unrecognized opcode
instruction: u8,
},
/// `StackUnderflow` when there is not enough stack elements to execute instruction
StackUnderflow {
/// Invoked instruction
instruction: &'static str,
/// How many stack elements was requested by instruction
wanted: usize,
/// How many elements were on stack
on_stack: usize
},
/// When execution would exceed defined Stack Limit
OutOfStack {
/// Invoked instruction
instruction: &'static str,
/// How many stack elements instruction wanted to push
wanted: usize,
/// What was the stack limit
limit: usize
},
/// Built-in contract failed on given input
BuiltIn(&'static str),
/// When execution tries to modify the state in static context
MutableCallInStaticContext,
/// Likely to cause consensus issues.
Internal(String),
/// Wasm runtime error
Wasm(String),
}

impl From<Box<trie::TrieError>> for Error {
fn from(err: Box<trie::TrieError>) -> Self {
Error::Internal(format!("Internal error: {}", err))
}
}

impl From<wasm::RuntimeError> for Error {
fn from(err: wasm::RuntimeError) -> Self {
Error::Wasm(format!("Runtime error: {:?}", err))
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
match *self {
OutOfGas => write!(f, "Out of gas"),
BadJumpDestination { destination } => write!(f, "Bad jump destination {:x}", destination),
BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction),
StackUnderflow { instruction, wanted, on_stack } => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack),
OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
Internal(ref msg) => write!(f, "Internal error: {}", msg),
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
Wasm(ref msg) => write!(f, "Internal error: {}", msg),
}
}
}

/// A specialized version of Result over EVM errors.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Return data buffer. Holds memory from a previous call and a slice into that memory.
#[derive(Debug)]
pub struct ReturnData {
mem: Vec<u8>,
offset: usize,
size: usize,
}

impl ::std::ops::Deref for ReturnData {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.mem[self.offset..self.offset + self.size]
}
}

impl ReturnData {
/// Create empty `ReturnData`.
pub fn empty() -> Self {
ReturnData {
mem: Vec::new(),
offset: 0,
size: 0,
}
}
/// Create `ReturnData` from give buffer and slice.
pub fn new(mem: Vec<u8>, offset: usize, size: usize) -> Self {
ReturnData {
mem: mem,
offset: offset,
size: size,
}
}
}

/// Gas Left: either it is a known value, or it needs to be computed by processing
/// a return instruction.
#[derive(Debug)]
pub enum GasLeft {
/// Known gas left
Known(U256),
/// Return or Revert instruction must be processed.
NeedsReturn {
/// Amount of gas left.
gas_left: U256,
/// Return data buffer.
data: ReturnData,
/// Apply or revert state changes on revert.
apply_state: bool
},
}
use util::{U128, U256, U512};
use vm::{Ext, Result, ReturnData, GasLeft, Error};

/// Finalization result. Gas Left: either it is a known value, or it needs to be computed by processing
/// a return instruction.
Expand Down Expand Up @@ -281,15 +147,6 @@ impl CostType for usize {
}
}

/// Evm interface
pub trait Evm {
/// This function should be used to execute transaction.
///
/// It returns either an error, a known amount of gas left, or parameters to be used
/// to compute the final gas left.
fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result<GasLeft>;
}

#[cfg(test)]
mod tests {
use util::U256;
Expand Down
6 changes: 3 additions & 3 deletions ethcore/evm/src/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! Evm factory.
//!
use std::sync::Arc;
use evm::Evm;
use vm::Vm;
use util::U256;
use super::interpreter::SharedCache;
use super::vmtype::VMType;
Expand All @@ -33,7 +33,7 @@ impl Factory {
/// Create fresh instance of VM
/// Might choose implementation depending on supplied gas.
#[cfg(feature = "jit")]
pub fn create(&self, gas: U256) -> Box<Evm> {
pub fn create(&self, gas: U256) -> Box<Vm> {
match self.evm {
VMType::Jit => {
Box::new(super::jit::JitEvm::default())
Expand All @@ -49,7 +49,7 @@ impl Factory {
/// Create fresh instance of VM
/// Might choose implementation depending on supplied gas.
#[cfg(not(feature = "jit"))]
pub fn create(&self, gas: U256) -> Box<Evm> {
pub fn create(&self, gas: U256) -> Box<Vm> {
match self.evm {
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
Expand Down
22 changes: 11 additions & 11 deletions ethcore/evm/src/interpreter/gasometer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
use util::*;
use super::u256_to_address;

use {evm, ext};
use {evm, vm};
use instructions::{self, Instruction, InstructionInfo};
use interpreter::stack::Stack;
use schedule::Schedule;
use vm::Schedule;

macro_rules! overflowing {
($x: expr) => {{
let (v, overflow) = $x;
if overflow { return Err(evm::Error::OutOfGas); }
if overflow { return Err(vm::Error::OutOfGas); }
v
}}
}
Expand Down Expand Up @@ -59,16 +59,16 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
}
}

pub fn verify_gas(&self, gas_cost: &Gas) -> evm::Result<()> {
pub fn verify_gas(&self, gas_cost: &Gas) -> vm::Result<()> {
match &self.current_gas < gas_cost {
true => Err(evm::Error::OutOfGas),
true => Err(vm::Error::OutOfGas),
false => Ok(())
}
}

/// How much gas is provided to a CALL/CREATE, given that we need to deduct `needed` for this operation
/// and that we `requested` some.
pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option<U256>) -> evm::Result<Gas> {
pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option<U256>) -> vm::Result<Gas> {
// Try converting requested gas to `Gas` (`U256/u64`)
// but in EIP150 even if we request more we should never fail from OOG
let requested = requested.map(Gas::from_u256);
Expand Down Expand Up @@ -107,12 +107,12 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
/// it will be the amount of gas that the current context provides to the child context.
pub fn requirements(
&mut self,
ext: &ext::Ext,
ext: &vm::Ext,
instruction: Instruction,
info: &InstructionInfo,
stack: &Stack<U256>,
current_mem_size: usize,
) -> evm::Result<InstructionRequirements<Gas>> {
) -> vm::Result<InstructionRequirements<Gas>> {
let schedule = ext.schedule();
let tier = instructions::get_tier_idx(info.tier);
let default_gas = Gas::from(schedule.tier_step_gas[tier]);
Expand Down Expand Up @@ -291,7 +291,7 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
})
}

fn mem_gas_cost(&self, schedule: &Schedule, current_mem_size: usize, mem_size: &Gas) -> evm::Result<(Gas, Gas, usize)> {
fn mem_gas_cost(&self, schedule: &Schedule, current_mem_size: usize, mem_size: &Gas) -> vm::Result<(Gas, Gas, usize)> {
let gas_for_mem = |mem_size: Gas| {
let s = mem_size >> 5;
// s * memory_gas + s * s / quad_coeff_div
Expand Down Expand Up @@ -319,12 +319,12 @@ impl<Gas: evm::CostType> Gasometer<Gas> {


#[inline]
fn mem_needed_const<Gas: evm::CostType>(mem: &U256, add: usize) -> evm::Result<Gas> {
fn mem_needed_const<Gas: evm::CostType>(mem: &U256, add: usize) -> vm::Result<Gas> {
Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add))))
}

#[inline]
fn mem_needed<Gas: evm::CostType>(offset: &U256, size: &U256) -> evm::Result<Gas> {
fn mem_needed<Gas: evm::CostType>(offset: &U256, size: &U256) -> vm::Result<Gas> {
if size.is_zero() {
return Ok(Gas::from(0));
}
Expand Down
2 changes: 1 addition & 1 deletion ethcore/evm/src/interpreter/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

use util::U256;
use {ReturnData};
use vm::ReturnData;

const MAX_RETURN_WASTE_BYTES: usize = 16384;

Expand Down
Loading