From f56b89010d2ea5d3b2582b371d3692ad70b24e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 30 Jul 2016 15:38:44 +0200 Subject: [PATCH] Gas for mem optimization (#1768) * Optimizing mem_gas_cost calculations * Memoizing current mem gas cost * Optimizing jump destinations --- Cargo.lock | 14 ++++ ethcore/Cargo.toml | 18 ++-- ethcore/src/evm/evm.rs | 39 ++++----- ethcore/src/evm/ext.rs | 2 +- ethcore/src/evm/interpreter/gasometer.rs | 100 ++++++++++++----------- ethcore/src/evm/interpreter/mod.rs | 14 ++-- ethcore/src/evm/mod.rs | 1 + ethcore/src/evm/schedule.rs | 13 ++- ethcore/src/lib.rs | 1 + evmbin/Cargo.lock | 20 ++++- evmbin/src/ext.rs | 5 +- 11 files changed, 139 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3d026850..f226076f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,6 +77,19 @@ dependencies = [ "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bit-set" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit-vec" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "0.3.3" @@ -243,6 +256,7 @@ dependencies = [ name = "ethcore" version = "1.3.0" dependencies = [ + "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index dd2a1f91e..07fbccf55 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -17,23 +17,25 @@ env_logger = "0.3" rustc-serialize = "0.3" heapsize = "0.3" rust-crypto = "0.2.34" -time = "0.1" -ethcore-util = { path = "../util" } -evmjit = { path = "../evmjit", optional = true } -ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = { version = "0.0.79", optional = true} crossbeam = "0.2.9" lazy_static = "0.2" +bloomchain = "0.1" +rayon = "0.3.1" +semver = "0.2" +bit-set = "0.4" +time = "0.1" +evmjit = { path = "../evmjit", optional = true } +clippy = { version = "0.0.79", optional = true} +ethash = { path = "../ethash" } +ethcore-util = { path = "../util" } ethcore-devtools = { path = "../devtools" } ethjson = { path = "../json" } -bloomchain = "0.1" ethcore-ipc = { path = "../ipc/rpc" } -rayon = "0.3.1" ethstore = { path = "../ethstore" } -semver = "0.2" ethcore-ipc-nano = { path = "../ipc/nano" } + [dependencies.hyper] git = "https://github.com/ethcore/hyper" default-features = false diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index 77b57bf69..a40c03d1b 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -107,9 +107,9 @@ pub trait CostType: ops::Mul + ops::Div + ops::Add (Self, bool); /// Multiple with overflow fn overflow_mul(self, other: Self) -> (Self, bool); - /// Single-step full multiplication and division: `self*other/div` + /// Single-step full multiplication and shift: `(self*other) >> shr` /// Should not overflow on intermediate steps - fn overflow_mul_div(self, other: Self, div: Self) -> (Self, bool); + fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool); } impl CostType for U256 { @@ -133,14 +133,14 @@ impl CostType for U256 { Uint::overflowing_mul(self, other) } - fn overflow_mul_div(self, other: Self, div: Self) -> (Self, bool) { + fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool) { let x = self.full_mul(other); - let (U512(parts), o) = Uint::overflowing_div(x, U512::from(div)); + let U512(parts) = x; let overflow = (parts[4] | parts[5] | parts[6] | parts[7]) > 0; - + let U512(parts) = x >> shr; ( U256([parts[0], parts[1], parts[2], parts[3]]), - o | overflow + overflow ) } } @@ -169,11 +169,13 @@ impl CostType for usize { self.overflowing_mul(other) } - fn overflow_mul_div(self, other: Self, div: Self) -> (Self, bool) { + fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool) { let (c, o) = U128::from(self).overflowing_mul(U128::from(other)); - let (U128(parts), o1) = c.overflowing_div(U128::from(div)); + let U128(parts) = c; + let overflow = o | (parts[1] > 0); + let U128(parts) = c >> shr; let result = parts[0] as usize; - let overflow = o | o1 | (parts[1] > 0) | (parts[0] > result as u64); + let overflow = overflow | (parts[0] > result as u64); (result, overflow) } } @@ -189,13 +191,13 @@ pub trait Evm { #[test] -fn should_calculate_overflow_mul_div_without_overflow() { +fn should_calculate_overflow_mul_shr_without_overflow() { // given - let num = 10_000_000; + let num = 1048576; // when - let (res1, o1) = U256::from(num).overflow_mul_div(U256::from(num), U256::from(num)); - let (res2, o2) = num.overflow_mul_div(num, num); + let (res1, o1) = U256::from(num).overflow_mul_shr(U256::from(num), 20); + let (res2, o2) = num.overflow_mul_shr(num, 20); // then assert_eq!(res1, U256::from(num)); @@ -205,22 +207,21 @@ fn should_calculate_overflow_mul_div_without_overflow() { } #[test] -fn should_calculate_overflow_mul_div_with_overflow() { +fn should_calculate_overflow_mul_shr_with_overflow() { // given let max = ::std::u64::MAX; let num1 = U256([max, max, max, max]); let num2 = ::std::usize::MAX; // when - let (res1, o1) = num1.overflow_mul_div(num1, num1 - U256::from(2)); - let (res2, o2) = num2.overflow_mul_div(num2, num2 - 2); + let (res1, o1) = num1.overflow_mul_shr(num1, 256); + let (res2, o2) = num2.overflow_mul_shr(num2, 64); // then - // (x+2)^2/x = (x^2 + 4x + 4)/x = x + 4 + 4/x ~ (MAX-2) + 4 + 0 = 1 - assert_eq!(res2, 1); + assert_eq!(res2, num2 - 1); assert!(o2); - assert_eq!(res1, U256::from(1)); + assert_eq!(res1, !U256::zero() - U256::one()); assert!(o1); } diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index ffc1887de..9fb1625b7 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -18,8 +18,8 @@ use util::common::*; use evm::{self, Schedule}; -use types::executed::CallType; use env_info::*; +use types::executed::CallType; /// Result of externalities create function. pub enum ContractCreateResult { diff --git a/ethcore/src/evm/interpreter/gasometer.rs b/ethcore/src/evm/interpreter/gasometer.rs index 0fc349a27..ffa2c41a0 100644 --- a/ethcore/src/evm/interpreter/gasometer.rs +++ b/ethcore/src/evm/interpreter/gasometer.rs @@ -37,6 +37,7 @@ enum InstructionCost { pub struct Gasometer { pub current_gas: Gas, + pub current_mem_gas: Gas, } impl Gasometer { @@ -44,6 +45,7 @@ impl Gasometer { pub fn new(current_gas: Gas) -> Self { Gasometer { current_gas: current_gas, + current_mem_gas: Gas::from(0), } } @@ -62,7 +64,7 @@ impl Gasometer { info: &InstructionInfo, stack: &Stack, current_mem_size: usize, - ) -> evm::Result<(Gas, usize)> { + ) -> evm::Result<(Gas, Gas, usize)> { let schedule = ext.schedule(); let tier = instructions::get_tier_idx(info.tier); let default_gas = Gas::from(schedule.tier_step_gas[tier]); @@ -76,11 +78,11 @@ impl Gasometer { let newval = stack.peek(1); let val = U256::from(ext.storage_at(&address).as_slice()); - let gas = if U256::zero() == val && &U256::zero() != newval { + let gas = if val.is_zero() && !newval.is_zero() { schedule.sstore_set_gas } else { // Refund for below case is added when actually executing sstore - // !self.is_zero(&val) && self.is_zero(newval) + // !is_zero(&val) && is_zero(newval) schedule.sstore_reset_gas }; InstructionCost::Gas(Gas::from(gas)) @@ -89,25 +91,25 @@ impl Gasometer { InstructionCost::Gas(Gas::from(schedule.sload_gas)) }, instructions::MSTORE | instructions::MLOAD => { - InstructionCost::GasMem(default_gas, try!(self.mem_needed_const(stack.peek(0), 32))) + InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 32))) }, instructions::MSTORE8 => { - InstructionCost::GasMem(default_gas, try!(self.mem_needed_const(stack.peek(0), 1))) + InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 1))) }, instructions::RETURN => { - InstructionCost::GasMem(default_gas, try!(self.mem_needed(stack.peek(0), stack.peek(1)))) + InstructionCost::GasMem(default_gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) }, instructions::SHA3 => { let w = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(1))), 31)); let words = w >> 5; let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words); - InstructionCost::GasMem(gas, try!(self.mem_needed(stack.peek(0), stack.peek(1)))) + InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) }, instructions::CALLDATACOPY | instructions::CODECOPY => { - InstructionCost::GasMemCopy(default_gas, try!(self.mem_needed(stack.peek(0), stack.peek(2))), try!(Gas::from_u256(*stack.peek(2)))) + InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(0), stack.peek(2))), try!(Gas::from_u256(*stack.peek(2)))) }, instructions::EXTCODECOPY => { - InstructionCost::GasMemCopy(default_gas, try!(self.mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3)))) + InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3)))) }, instructions::LOG0...instructions::LOG4 => { let no_of_topics = instructions::get_log_topics(instruction); @@ -115,13 +117,13 @@ impl Gasometer { let data_gas = overflowing!(try!(Gas::from_u256(*stack.peek(1))).overflow_mul(Gas::from(schedule.log_data_gas))); let gas = overflowing!(data_gas.overflow_add(Gas::from(log_gas))); - InstructionCost::GasMem(gas, try!(self.mem_needed(stack.peek(0), stack.peek(1)))) + InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) }, instructions::CALL | instructions::CALLCODE => { let mut gas = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(0))), schedule.call_gas)); let mem = cmp::max( - try!(self.mem_needed(stack.peek(5), stack.peek(6))), - try!(self.mem_needed(stack.peek(3), stack.peek(4))) + try!(mem_needed(stack.peek(5), stack.peek(6))), + try!(mem_needed(stack.peek(3), stack.peek(4))) ); let address = u256_to_address(stack.peek(1)); @@ -130,7 +132,7 @@ impl Gasometer { gas = overflowing!(gas.overflow_add(Gas::from(schedule.call_new_account_gas))); }; - if stack.peek(2) > &U256::zero() { + if !stack.peek(2).is_zero() { gas = overflowing!(gas.overflow_add(Gas::from(schedule.call_value_transfer_gas))); }; @@ -139,14 +141,14 @@ impl Gasometer { instructions::DELEGATECALL => { let gas = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(0))), schedule.call_gas)); let mem = cmp::max( - try!(self.mem_needed(stack.peek(4), stack.peek(5))), - try!(self.mem_needed(stack.peek(2), stack.peek(3))) + try!(mem_needed(stack.peek(4), stack.peek(5))), + try!(mem_needed(stack.peek(2), stack.peek(3))) ); InstructionCost::GasMem(gas, mem) }, instructions::CREATE => { let gas = Gas::from(schedule.create_gas); - let mem = try!(self.mem_needed(stack.peek(1), stack.peek(2))); + let mem = try!(mem_needed(stack.peek(1), stack.peek(2))); InstructionCost::GasMem(gas, mem) }, instructions::EXP => { @@ -160,66 +162,65 @@ impl Gasometer { match cost { InstructionCost::Gas(gas) => { - Ok((gas, 0)) + Ok((gas, self.current_mem_gas, 0)) }, InstructionCost::GasMem(gas, mem_size) => { - let (mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size)); - let gas = overflowing!(gas.overflow_add(mem_gas)); - Ok((gas, new_mem_size)) + let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size)); + let gas = overflowing!(gas.overflow_add(mem_gas_cost)); + Ok((gas, new_mem_gas, new_mem_size)) }, InstructionCost::GasMemCopy(gas, mem_size, copy) => { - let (mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size)); - let copy = overflowing!(add_gas_usize(copy, 31)); - let copy_gas = Gas::from(schedule.copy_gas) * (copy / Gas::from(32 as usize)); + let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size)); + let copy = overflowing!(add_gas_usize(copy, 31)) >> 5; + let copy_gas = Gas::from(schedule.copy_gas) * copy; let gas = overflowing!(gas.overflow_add(copy_gas)); - let gas = overflowing!(gas.overflow_add(mem_gas)); - Ok((gas, new_mem_size)) + let gas = overflowing!(gas.overflow_add(mem_gas_cost)); + Ok((gas, new_mem_gas, new_mem_size)) } } } - fn is_zero(&self, val: &Gas) -> bool { - &Gas::from(0) == val - } - - fn mem_needed_const(&self, mem: &U256, add: usize) -> evm::Result { - Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add)))) - } - - fn mem_needed(&self, offset: &U256, size: &U256) -> evm::Result { - if self.is_zero(&try!(Gas::from_u256(*size))) { - return Ok(Gas::from(0)); - } - - Gas::from_u256(overflowing!(offset.overflowing_add(*size))) - } - - fn mem_gas_cost(&self, schedule: &evm::Schedule, current_mem_size: usize, mem_size: &Gas) -> evm::Result<(Gas, usize)> { + fn mem_gas_cost(&self, schedule: &evm::Schedule, current_mem_size: usize, mem_size: &Gas) -> evm::Result<(Gas, Gas, usize)> { let gas_for_mem = |mem_size: Gas| { let s = mem_size >> 5; // s * memory_gas + s * s / quad_coeff_div let a = overflowing!(s.overflow_mul(Gas::from(schedule.memory_gas))); // Calculate s*s/quad_coeff_div - let b = overflowing!(s.overflow_mul_div(s, Gas::from(schedule.quad_coeff_div))); + debug_assert_eq!(schedule.quad_coeff_div, 512); + let b = overflowing!(s.overflow_mul_shr(s, 9)); Ok(overflowing!(a.overflow_add(b))) }; let current_mem_size = Gas::from(current_mem_size); let req_mem_size_rounded = (overflowing!(mem_size.overflow_add(Gas::from(31 as usize))) >> 5) << 5; - let mem_gas_cost = if req_mem_size_rounded > current_mem_size { + let (mem_gas_cost, new_mem_gas) = if req_mem_size_rounded > current_mem_size { let new_mem_gas = try!(gas_for_mem(req_mem_size_rounded)); - let current_mem_gas = try!(gas_for_mem(current_mem_size)); - new_mem_gas - current_mem_gas + (new_mem_gas - self.current_mem_gas, new_mem_gas) } else { - Gas::from(0) + (Gas::from(0), self.current_mem_gas) }; - Ok((mem_gas_cost, req_mem_size_rounded.as_usize())) + Ok((mem_gas_cost, new_mem_gas, req_mem_size_rounded.as_usize())) } } + +#[inline] +fn mem_needed_const(mem: &U256, add: usize) -> evm::Result { + Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add)))) +} + +#[inline] +fn mem_needed(offset: &U256, size: &U256) -> evm::Result { + if size.is_zero() { + return Ok(Gas::from(0)); + } + + Gas::from_u256(overflowing!(offset.overflowing_add(*size))) +} + #[inline] fn add_gas_usize(value: Gas, num: usize) -> (Gas, bool) { value.overflow_add(Gas::from(num)) @@ -251,9 +252,10 @@ fn test_calculate_mem_cost() { let mem_size = 5; // when - let (mem_cost, mem_size) = gasometer.mem_gas_cost(&schedule, current_mem_size, &mem_size).unwrap(); + let (mem_cost, new_mem_gas, mem_size) = gasometer.mem_gas_cost(&schedule, current_mem_size, &mem_size).unwrap(); // then assert_eq!(mem_cost, 3); + assert_eq!(new_mem_gas, 3); assert_eq!(mem_size, 32); } diff --git a/ethcore/src/evm/interpreter/mod.rs b/ethcore/src/evm/interpreter/mod.rs index 84e416c15..8a3eae5b3 100644 --- a/ethcore/src/evm/interpreter/mod.rs +++ b/ethcore/src/evm/interpreter/mod.rs @@ -41,6 +41,7 @@ use common::*; use types::executed::CallType; use super::instructions::{self, Instruction, InstructionInfo}; use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType}; +use bit_set::BitSet; #[cfg(feature = "evm-debug")] fn color(instruction: Instruction, name: &'static str) -> String { @@ -115,12 +116,13 @@ impl evm::Evm for Interpreter { try!(self.verify_instruction(ext, instruction, &info, &stack)); // Calculate gas cost - let (gas_cost, mem_size) = try!(gasometer.get_gas_cost_mem(ext, instruction, &info, &stack, self.mem.size())); + let (gas_cost, mem_gas, mem_size) = try!(gasometer.get_gas_cost_mem(ext, instruction, &info, &stack, self.mem.size())); // TODO: make compile-time removable if too much of a performance hit. let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, &gas_cost.as_u256()); try!(gasometer.verify_gas(&gas_cost)); self.mem.expand(mem_size); + gasometer.current_mem_gas = mem_gas; gasometer.current_gas = gasometer.current_gas - gas_cost; evm_debug!({ @@ -540,10 +542,10 @@ impl Interpreter { } } - fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &HashSet) -> evm::Result { + fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &BitSet) -> evm::Result { let jump = jump_u.low_u64() as usize; - if valid_jump_destinations.contains(&jump) && jump_u < U256::from(!0 as usize) { + if valid_jump_destinations.contains(jump) && U256::from(jump) == jump_u { Ok(jump) } else { Err(evm::Error::BadJumpDestination { @@ -765,8 +767,8 @@ impl Interpreter { Ok(()) } - fn find_jump_destinations(&self, code: &[u8]) -> HashSet { - let mut jump_dests = HashSet::new(); + fn find_jump_destinations(&self, code: &[u8]) -> BitSet { + let mut jump_dests = BitSet::with_capacity(code.len()); let mut position = 0; while position < code.len() { @@ -818,5 +820,5 @@ fn test_find_jump_destinations() { let valid_jump_destinations = interpreter.find_jump_destinations(&code); // then - assert!(valid_jump_destinations.contains(&66)); + assert!(valid_jump_destinations.contains(66)); } diff --git a/ethcore/src/evm/mod.rs b/ethcore/src/evm/mod.rs index d0f379f24..bfead60c1 100644 --- a/ethcore/src/evm/mod.rs +++ b/ethcore/src/evm/mod.rs @@ -35,3 +35,4 @@ pub use self::evm::{Evm, Error, Finalize, GasLeft, Result, CostType}; pub use self::ext::{Ext, ContractCreateResult, MessageCallResult}; pub use self::factory::{Factory, VMType}; pub use self::schedule::Schedule; +pub use types::executed::CallType; diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index f82157239..e3e4e3b7b 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -125,7 +125,18 @@ impl Schedule { tx_create_gas: tcg, tx_data_zero_gas: 4, tx_data_non_zero_gas: 68, - copy_gas: 3, + copy_gas: 3, } } } + +#[test] +#[cfg(test)] +fn schedule_evm_assumptions() { + let s1 = Schedule::new_frontier(); + let s2 = Schedule::new_homestead(); + + // To optimize division we assume 2**9 for quad_coeff_div + assert_eq!(s1.quad_coeff_div, 512); + assert_eq!(s2.quad_coeff_div, 512); +} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 3c6f319a1..b65e22313 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -95,6 +95,7 @@ pub extern crate ethstore; extern crate semver; extern crate ethcore_ipc_nano as nanoipc; extern crate ethcore_devtools as devtools; +extern crate bit_set; #[cfg(feature = "jit" )] extern crate evmjit; diff --git a/evmbin/Cargo.lock b/evmbin/Cargo.lock index f135b3b0b..d97d262f2 100644 --- a/evmbin/Cargo.lock +++ b/evmbin/Cargo.lock @@ -47,6 +47,19 @@ dependencies = [ "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bit-set" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit-vec" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "0.3.3" @@ -168,6 +181,7 @@ dependencies = [ name = "ethcore" version = "1.3.0" dependencies = [ + "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -253,7 +267,7 @@ dependencies = [ "nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.4.5", + "rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -738,14 +752,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" version = "0.4.5" +source = "git+https://github.com/ethcore/rust-rocksdb#eadce7f74cfe92b99ce63a77af425b47857239b8" dependencies = [ "libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb-sys 0.3.0", + "rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)", ] [[package]] name = "rocksdb-sys" version = "0.3.0" +source = "git+https://github.com/ethcore/rust-rocksdb#eadce7f74cfe92b99ce63a77af425b47857239b8" dependencies = [ "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/evmbin/src/ext.rs b/evmbin/src/ext.rs index 0ea932279..d9a6932ba 100644 --- a/evmbin/src/ext.rs +++ b/evmbin/src/ext.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use util::{U256, H256, Address, Bytes, FixedHash}; use ethcore::client::EnvInfo; -use ethcore::evm::{self, Ext, ContractCreateResult, MessageCallResult, Schedule}; +use ethcore::evm::{self, Ext, ContractCreateResult, MessageCallResult, Schedule, CallType}; pub struct FakeExt { schedule: Schedule, @@ -67,7 +67,8 @@ impl Ext for FakeExt { _value: Option, _data: &[u8], _code_address: &Address, - _output: &mut [u8]) -> MessageCallResult { + _output: &mut [u8], + _call_type: CallType) -> MessageCallResult { unimplemented!(); }