diff --git a/ethcore/src/evm/jit.rs b/ethcore/src/evm/jit.rs index e073a380d..6a6d7e5ff 100644 --- a/ethcore/src/evm/jit.rs +++ b/ethcore/src/evm/jit.rs @@ -174,28 +174,33 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { fn call(&mut self, io_gas: *mut u64, call_gas: u64, + sender_address: *const evmjit::H256, receive_address: *const evmjit::H256, - value: *const evmjit::I256, + code_address: *const evmjit::H256, + transfer_value: *const evmjit::I256, + _apparent_value: *const evmjit::I256, in_beg: *const u8, in_size: u64, out_beg: *mut u8, - out_size: u64, - code_address: *const evmjit::H256) -> bool { + out_size: u64) -> bool { let mut gas = unsafe { U256::from(*io_gas) }; let mut call_gas = U256::from(call_gas); let mut gas_cost = call_gas; + let sender_address = unsafe { Address::from_jit(&*sender_address) }; let receive_address = unsafe { Address::from_jit(&*receive_address) }; let code_address = unsafe { Address::from_jit(&*code_address) }; - let value = unsafe { U256::from_jit(&*value) }; + let transfer_value = unsafe { U256::from_jit(&*transfer_value) }; + let mut value = Some(transfer_value); // receive address and code address are the same in normal calls let is_callcode = receive_address != code_address; + if !is_callcode && !self.ext.exists(&code_address) { gas_cost = gas_cost + U256::from(self.ext.schedule().call_new_account_gas); } - if value > U256::zero() { + if transfer_value > U256::zero() { assert!(self.ext.schedule().call_value_transfer_gas > self.ext.schedule().call_stipend, "overflow possible"); gas_cost = gas_cost + U256::from(self.ext.schedule().call_value_transfer_gas); call_gas = call_gas + U256::from(self.ext.schedule().call_stipend); @@ -211,7 +216,7 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { gas = gas - gas_cost; // check if balance is sufficient and we are not too deep - if self.ext.balance(&self.address) < value || self.ext.depth() >= self.ext.schedule().max_depth { + if self.ext.balance(&self.address) < transfer_value || self.ext.depth() >= self.ext.schedule().max_depth { unsafe { *io_gas = (gas + call_gas).low_u64(); return false; @@ -220,9 +225,9 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { match self.ext.call( &call_gas, - &self.address, + &sender_address, &receive_address, - Some(value), + value, unsafe { slice::from_raw_parts(in_beg, in_size as usize) }, &code_address, unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) }) { @@ -305,10 +310,14 @@ impl evm::Evm for JitEvm { data.address = params.address.into_jit(); data.caller = params.sender.into_jit(); data.origin = params.origin.into_jit(); - data.call_value = match params.value { + data.transfer_value = match params.value { ActionValue::Transfer(val) => val.into_jit(), ActionValue::Apparent(val) => val.into_jit() }; + data.apparent_value = data.transfer_value; + + let mut schedule = evmjit::ScheduleHandle::new(); + schedule.have_delegate_call = ext.schedule().have_delegate_call; data.author = ext.env_info().author.clone().into_jit(); data.difficulty = ext.env_info().difficulty.into_jit(); @@ -317,7 +326,7 @@ impl evm::Evm for JitEvm { // don't really know why jit timestamp is int.. data.timestamp = ext.env_info().timestamp as i64; - let mut context = unsafe { evmjit::ContextHandle::new(data, &mut ext_handle) }; + let mut context = unsafe { evmjit::ContextHandle::new(data, schedule, &mut ext_handle) }; let res = context.exec(); match res { diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 0bc57433f..7b8e29d23 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -254,7 +254,7 @@ fn test_origin(factory: super::Factory) { assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681"); } -evm_test!{ignorejit => test_sender: test_sender_jit, test_sender_int} +evm_test!{test_sender: test_sender_jit, test_sender_int} fn test_sender(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); @@ -366,7 +366,7 @@ fn test_log_sender(factory: super::Factory) { assert_eq!(ext.logs[0].data, "ff00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap()); } -evm_test!{ignorejit => test_blockhash: test_blockhash_jit, test_blockhash_int} +evm_test!{test_blockhash: test_blockhash_jit, test_blockhash_int} fn test_blockhash(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "600040600055".from_hex().unwrap(); diff --git a/evmjit/Cargo.toml b/evmjit/Cargo.toml index aeebe60cf..ccd9cc718 100644 --- a/evmjit/Cargo.toml +++ b/evmjit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evmjit" -version = "0.1.0" +version = "0.9.0" authors = ["debris "] [lib] diff --git a/evmjit/src/lib.rs b/evmjit/src/lib.rs index a4381619b..9ee62863d 100644 --- a/evmjit/src/lib.rs +++ b/evmjit/src/lib.rs @@ -42,10 +42,10 @@ pub use self::ffi::JitReturnCode as ReturnCode; pub use self::ffi::JitI256 as I256; pub use self::ffi::JitH256 as H256; -/// Takes care of proper initialization and destruction of `RuntimeData`. +/// Takes care of proper initialization and destruction of `RuntimeData`. /// /// This handle must be used to create runtime data, -/// cause underneath it's a `C++` structure. Incombatible with rust +/// cause underneath it's a `C++` structure. Incompatible with rust /// structs. pub struct RuntimeDataHandle { runtime_data: *mut JitRuntimeData @@ -58,16 +58,6 @@ impl RuntimeDataHandle { runtime_data: unsafe { evmjit_create_runtime_data() } } } - - /// Returns immutable reference to runtime data. - pub fn runtime_data(&self) -> &JitRuntimeData { - unsafe { &*self.runtime_data } - } - - /// Returns mutable reference to runtime data. - pub fn mut_runtime_data(&mut self) -> &mut JitRuntimeData { - unsafe { &mut *self.runtime_data } - } } impl Drop for RuntimeDataHandle { @@ -80,13 +70,51 @@ impl Deref for RuntimeDataHandle { type Target = JitRuntimeData; fn deref(&self) -> &Self::Target { - self.runtime_data() + unsafe { &*self.runtime_data } } } impl DerefMut for RuntimeDataHandle { fn deref_mut(&mut self) -> &mut Self::Target { - self.mut_runtime_data() + unsafe { &mut *self.runtime_data } + } +} + +/// Takes care of proper initilization and destruction of `JitSchedule`. +/// +/// This handle must be used to jit schedule, +/// cause underneath it's a `C++` structure. Incompatible with rust +/// structs. +pub struct ScheduleHandle { + schedule: *mut JitSchedule +} + +impl ScheduleHandle { + /// Creates new `Schedule` handle. + pub fn new() -> Self { + ScheduleHandle { + schedule: unsafe { evmjit_create_schedule() } + } + } +} + +impl Drop for ScheduleHandle { + fn drop(&mut self) { + unsafe { evmjit_destroy_schedule(self.schedule) } + } +} + +impl Deref for ScheduleHandle { + type Target = JitSchedule; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.schedule } + } +} + +impl DerefMut for ScheduleHandle { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.schedule } } } @@ -98,6 +126,7 @@ impl DerefMut for RuntimeDataHandle { pub struct ContextHandle { context: *mut JitContext, data_handle: RuntimeDataHandle, + schedule_handle: ScheduleHandle } impl ContextHandle { @@ -107,19 +136,20 @@ impl ContextHandle { /// We also can't make ExtHandle a member of `ContextHandle` structure, /// cause this would be a move operation or it would require a template /// lifetime to a reference. Both solutions are not possible. - pub unsafe fn new(data_handle: RuntimeDataHandle, ext: &mut ExtHandle) -> Self { + pub unsafe fn new(data_handle: RuntimeDataHandle, schedule_handle: ScheduleHandle, ext: &mut ExtHandle) -> Self { let mut handle = ContextHandle { context: std::mem::uninitialized(), + schedule_handle: schedule_handle, data_handle: data_handle, }; - handle.context = evmjit_create_context(handle.data_handle.mut_runtime_data(), ext); + handle.context = evmjit_create_context(handle.data_handle.deref_mut(), ext); handle } /// Executes context. pub fn exec(&mut self) -> JitReturnCode { - unsafe { evmjit_exec(self.context) } + unsafe { evmjit_exec(self.context, self.schedule_handle.deref_mut()) } } /// Returns output data. @@ -162,13 +192,15 @@ pub trait Ext { fn call(&mut self, io_gas: *mut u64, call_gas: u64, + sender_address: *const JitH256, receive_address: *const JitH256, - value: *const JitI256, + code_address: *const JitH256, + transfer_value: *const JitI256, + apparent_value: *const JitI256, in_beg: *const u8, in_size: u64, out_beg: *mut u8, - out_size: u64, - code_address: *const JitH256) -> bool; + out_size: u64) -> bool; fn log(&mut self, beg: *const u8, @@ -292,7 +324,8 @@ pub mod ffi { pub address: JitI256, pub caller: JitI256, pub origin: JitI256, - pub call_value: JitI256, + pub transfer_value: JitI256, + pub apparent_value: JitI256, pub author: JitI256, pub difficulty: JitI256, pub gas_limit: JitI256, @@ -303,6 +336,13 @@ pub mod ffi { pub code_hash: JitI256 } + #[repr(C)] + #[derive(Debug)] + /// Configurable properties of git schedule. + pub struct JitSchedule { + pub have_delegate_call: bool + } + #[no_mangle] pub unsafe extern "C" fn env_sload(ext: *const ExtHandle, index: *const JitI256, out_value: *mut JitI256) { let ext = &*ext; @@ -342,15 +382,17 @@ pub mod ffi { pub unsafe extern "C" fn env_call(ext: *mut ExtHandle, io_gas: *mut u64, call_gas: u64, + sender_address: *const JitH256, receive_address: *const JitH256, - value: *const JitI256, + code_address: *const JitH256, + transfer_value: *const JitI256, + apparent_value: *const JitI256, in_beg: *const u8, in_size: u64, out_beg: *mut u8, - out_size: u64, - code_address: *const JitH256) -> bool { + out_size: u64) -> bool { let ext = &mut *ext; - ext.call(io_gas, call_gas, receive_address, value, in_beg, in_size, out_beg, out_size, code_address) + ext.call(io_gas, call_gas, sender_address, receive_address, code_address, transfer_value, apparent_value, in_beg, in_size, out_beg, out_size) } #[no_mangle] @@ -385,10 +427,12 @@ pub mod ffi { #[link(name="evmjit")] extern "C" { + pub fn evmjit_create_schedule() -> *mut JitSchedule; + pub fn evmjit_destroy_schedule(schedule: *mut JitSchedule); pub fn evmjit_create_runtime_data() -> *mut JitRuntimeData; pub fn evmjit_destroy_runtime_data(data: *mut JitRuntimeData); pub fn evmjit_destroy_context(context: *mut JitContext); - pub fn evmjit_exec(context: *mut JitContext) -> JitReturnCode; + pub fn evmjit_exec(context: *mut JitContext, schedule: *mut JitSchedule) -> JitReturnCode; } // ExtHandle is not a C type, so we need to allow "improper_ctypes" @@ -403,11 +447,13 @@ pub mod ffi { fn ffi_test() { unsafe { let data = evmjit_create_runtime_data(); + let schedule = evmjit_create_schedule(); let context = evmjit_create_context(data, &mut ExtHandle::empty()); - let code = evmjit_exec(context); + let code = evmjit_exec(context, schedule); assert_eq!(code, JitReturnCode::Stop); + evmjit_destroy_schedule(schedule); evmjit_destroy_runtime_data(data); evmjit_destroy_context(context); } @@ -416,7 +462,8 @@ fn ffi_test() { #[test] fn handle_test() { unsafe { - let mut context = ContextHandle::new(RuntimeDataHandle::new(), &mut ExtHandle::empty()); + let mut ext = ExtHandle::empty(); + let mut context = ContextHandle::new(RuntimeDataHandle::new(), ScheduleHandle::new(), &mut ext); assert_eq!(context.exec(), ReturnCode::Stop); } }