//! Just in time compiler execution environment. use common::*; use evmjit; use evm; /// Should be used to convert jit types to ethcore trait FromJit: Sized { fn from_jit(input: T) -> Self; } /// Should be used to covert ethcore types to jit trait IntoJit { fn into_jit(self) -> T; } impl<'a> FromJit<&'a evmjit::I256> for U256 { fn from_jit(input: &'a evmjit::I256) -> Self { unsafe { let mut res: U256 = mem::uninitialized(); ptr::copy(input.words.as_ptr(), res.0.as_mut_ptr(), 4); res } } } impl<'a> FromJit<&'a evmjit::I256> for H256 { fn from_jit(input: &'a evmjit::I256) -> Self { let u = U256::from_jit(input); H256::from(&u) } } impl<'a> FromJit<&'a evmjit::I256> for Address { fn from_jit(input: &'a evmjit::I256) -> Self { Address::from(H256::from_jit(input)) } } impl<'a> FromJit<&'a evmjit::H256> for H256 { fn from_jit(input: &'a evmjit::H256) -> Self { H256::from_jit(&evmjit::I256::from(input.clone())) } } impl<'a> FromJit<&'a evmjit::H256> for Address { fn from_jit(input: &'a evmjit::H256) -> Self { Address::from(H256::from_jit(input)) } } impl IntoJit for U256 { fn into_jit(self) -> evmjit::I256 { unsafe { let mut res: evmjit::I256 = mem::uninitialized(); ptr::copy(self.0.as_ptr(), res.words.as_mut_ptr(), 4); res } } } impl IntoJit for H256 { fn into_jit(self) -> evmjit::I256 { let mut ret = [0; 4]; for i in 0..self.bytes().len() { let rev = self.bytes().len() - 1 - i; let pos = rev / 8; ret[pos] += (self.bytes()[i] as u64) << ((rev % 8) * 8); } evmjit::I256 { words: ret } } } impl IntoJit for H256 { fn into_jit(self) -> evmjit::H256 { let i: evmjit::I256 = self.into_jit(); From::from(i) } } impl IntoJit for Address { fn into_jit(self) -> evmjit::I256 { H256::from(self).into_jit() } } impl IntoJit for Address { fn into_jit(self) -> evmjit::H256 { H256::from(self).into_jit() } } /// Externalities adapter. Maps callbacks from evmjit to externalities trait. /// /// Evmjit doesn't have to know about children execution failures. /// This adapter 'catches' them and moves upstream. struct ExtAdapter<'a> { ext: &'a mut evm::Ext, address: Address } impl<'a> ExtAdapter<'a> { fn new(ext: &'a mut evm::Ext, address: Address) -> Self { ExtAdapter { ext: ext, address: address } } } impl<'a> evmjit::Ext for ExtAdapter<'a> { fn sload(&self, key: *const evmjit::I256, out_value: *mut evmjit::I256) { unsafe { let i = H256::from_jit(&*key); let o = self.ext.storage_at(&i); *out_value = o.into_jit(); } } fn sstore(&mut self, key: *const evmjit::I256, value: *const evmjit::I256) { let key = unsafe { H256::from_jit(&*key) }; let value = unsafe { H256::from_jit(&*value) }; let old_value = self.ext.storage_at(&key); // if SSTORE nonzero -> zero, increment refund count if !old_value.is_zero() && value.is_zero() { self.ext.inc_sstore_clears(); } self.ext.set_storage(key, value); } fn balance(&self, address: *const evmjit::H256, out_value: *mut evmjit::I256) { unsafe { let a = Address::from_jit(&*address); let o = self.ext.balance(&a); *out_value = o.into_jit(); } } fn blockhash(&self, number: *const evmjit::I256, out_hash: *mut evmjit::H256) { unsafe { let n = U256::from_jit(&*number); let o = self.ext.blockhash(&n); *out_hash = o.into_jit(); } } fn create(&mut self, io_gas: *mut u64, value: *const evmjit::I256, init_beg: *const u8, init_size: u64, address: *mut evmjit::H256) { let gas = unsafe { U256::from(*io_gas) }; let value = unsafe { U256::from_jit(&*value) }; let code = unsafe { slice::from_raw_parts(init_beg, init_size as usize) }; // 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 { match self.ext.create(&gas, &value, code) { evm::ContractCreateResult::Created(new_address, gas_left) => unsafe { *address = new_address.into_jit(); *io_gas = gas_left.low_u64(); }, evm::ContractCreateResult::Failed => unsafe { *address = Address::new().into_jit(); *io_gas = 0; } } } else { unsafe { *address = Address::new().into_jit(); } } } fn call(&mut self, io_gas: *mut u64, call_gas: u64, sender_address: *const evmjit::H256, receive_address: *const evmjit::H256, 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) -> 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 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 { // it's a delegatecall... fix it better. value = None; } if !is_callcode && !self.ext.exists(&code_address) { gas_cost = gas_cost + U256::from(self.ext.schedule().call_new_account_gas); } 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); } if gas_cost > gas { unsafe { *io_gas = -1i64 as u64; return false; } } gas = gas - gas_cost; // check if balance is sufficient and we are not too deep 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; } } match self.ext.call( &call_gas, &sender_address, &receive_address, 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) }) { evm::MessageCallResult::Success(gas_left) => unsafe { *io_gas = (gas + gas_left).low_u64(); true }, evm::MessageCallResult::Failed => unsafe { *io_gas = gas.low_u64(); false } } } fn log(&mut self, beg: *const u8, size: u64, topic1: *const evmjit::H256, topic2: *const evmjit::H256, topic3: *const evmjit::H256, topic4: *const evmjit::H256) { unsafe { let mut topics = vec![]; if !topic1.is_null() { topics.push(H256::from_jit(&*topic1)); } if !topic2.is_null() { topics.push(H256::from_jit(&*topic2)); } if !topic3.is_null() { topics.push(H256::from_jit(&*topic3)); } if !topic4.is_null() { topics.push(H256::from_jit(&*topic4)); } let bytes_ref: &[u8] = slice::from_raw_parts(beg, size as usize); self.ext.log(topics, bytes_ref); } } fn extcode(&self, address: *const evmjit::H256, size: *mut u64) -> *const u8 { unsafe { let code = self.ext.extcode(&Address::from_jit(&*address)); *size = code.len() as u64; let ptr = code.as_ptr(); mem::forget(code); ptr } } } pub struct JitEvm; impl evm::Evm for JitEvm { fn exec(&self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result { // Dirty hack. This is unsafe, but we interact with ffi, so it's justified. let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, params.address.clone())) }; let mut ext_handle = evmjit::ExtHandle::new(ext_adapter); assert!(params.gas <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63"); assert!(params.gas_price <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63"); let call_data = params.data.unwrap_or_else(Vec::new); let code = params.code.unwrap_or_else(Vec::new); let mut data = evmjit::RuntimeDataHandle::new(); data.gas = params.gas.low_u64() as i64; data.gas_price = params.gas_price.low_u64() as i64; data.call_data = call_data.as_ptr(); data.call_data_size = call_data.len() as u64; mem::forget(call_data); data.code = code.as_ptr(); data.code_size = code.len() as u64; data.code_hash = code.sha3().into_jit(); mem::forget(code); data.address = params.address.into_jit(); data.caller = params.sender.into_jit(); data.origin = params.origin.into_jit(); match params.value { ActionValue::Transfer(val) => { data.transfer_value = val.into_jit(); data.apparent_value = U256::zero().into_jit(); }, ActionValue::Apparent(val) => { data.transfer_value = U256::zero().into_jit(); data.apparent_value = val.into_jit(); } }; 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(); data.gas_limit = ext.env_info().gas_limit.into_jit(); data.number = ext.env_info().number; // 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, schedule, &mut ext_handle) }; let res = context.exec(); match res { evmjit::ReturnCode::Stop => Ok(U256::from(context.gas_left())), evmjit::ReturnCode::Return => ext.ret(&U256::from(context.gas_left()), context.output_data()), evmjit::ReturnCode::Suicide => { ext.suicide(&Address::from_jit(&context.suicide_refund_address())); Ok(U256::from(context.gas_left())) }, evmjit::ReturnCode::OutOfGas => Err(evm::Error::OutOfGas), _err => Err(evm::Error::Internal) } } } #[test] fn test_to_and_from_u256() { let u = U256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap(); let j = u.into_jit(); let u2 = U256::from_jit(&j); assert_eq!(u, u2); } #[test] fn test_to_and_from_h256() { let h = H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap(); let j: ::evmjit::I256 = h.clone().into_jit(); let h2 = H256::from_jit(&j); assert_eq!(h, h2); let j: ::evmjit::H256 = h.clone().into_jit(); let h2 = H256::from_jit(&j); assert_eq!(h, h2); } #[test] fn test_to_and_from_address() { let a = Address::from_str("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").unwrap(); let j: ::evmjit::I256 = a.clone().into_jit(); let a2 = Address::from_jit(&j); assert_eq!(a, a2); let j: ::evmjit::H256 = a.clone().into_jit(); let a2 = Address::from_jit(&j); assert_eq!(a, a2); }