Merge pull request #342 from ethcore/jit_homestead
evmjit homestead merge
This commit is contained in:
commit
a696430545
@ -174,28 +174,33 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
|
|||||||
fn call(&mut self,
|
fn call(&mut self,
|
||||||
io_gas: *mut u64,
|
io_gas: *mut u64,
|
||||||
call_gas: u64,
|
call_gas: u64,
|
||||||
|
sender_address: *const evmjit::H256,
|
||||||
receive_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_beg: *const u8,
|
||||||
in_size: u64,
|
in_size: u64,
|
||||||
out_beg: *mut u8,
|
out_beg: *mut u8,
|
||||||
out_size: u64,
|
out_size: u64) -> bool {
|
||||||
code_address: *const evmjit::H256) -> bool {
|
|
||||||
|
|
||||||
let mut gas = unsafe { U256::from(*io_gas) };
|
let mut gas = unsafe { U256::from(*io_gas) };
|
||||||
let mut call_gas = U256::from(call_gas);
|
let mut call_gas = U256::from(call_gas);
|
||||||
let mut gas_cost = 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 receive_address = unsafe { Address::from_jit(&*receive_address) };
|
||||||
let code_address = unsafe { Address::from_jit(&*code_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
|
// receive address and code address are the same in normal calls
|
||||||
let is_callcode = receive_address != code_address;
|
let is_callcode = receive_address != code_address;
|
||||||
|
|
||||||
if !is_callcode && !self.ext.exists(&code_address) {
|
if !is_callcode && !self.ext.exists(&code_address) {
|
||||||
gas_cost = gas_cost + U256::from(self.ext.schedule().call_new_account_gas);
|
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");
|
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);
|
gas_cost = gas_cost + U256::from(self.ext.schedule().call_value_transfer_gas);
|
||||||
call_gas = call_gas + U256::from(self.ext.schedule().call_stipend);
|
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;
|
gas = gas - gas_cost;
|
||||||
|
|
||||||
// check if balance is sufficient and we are not too deep
|
// 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 {
|
unsafe {
|
||||||
*io_gas = (gas + call_gas).low_u64();
|
*io_gas = (gas + call_gas).low_u64();
|
||||||
return false;
|
return false;
|
||||||
@ -220,9 +225,9 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
|
|||||||
|
|
||||||
match self.ext.call(
|
match self.ext.call(
|
||||||
&call_gas,
|
&call_gas,
|
||||||
&self.address,
|
&sender_address,
|
||||||
&receive_address,
|
&receive_address,
|
||||||
Some(value),
|
value,
|
||||||
unsafe { slice::from_raw_parts(in_beg, in_size as usize) },
|
unsafe { slice::from_raw_parts(in_beg, in_size as usize) },
|
||||||
&code_address,
|
&code_address,
|
||||||
unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) }) {
|
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.address = params.address.into_jit();
|
||||||
data.caller = params.sender.into_jit();
|
data.caller = params.sender.into_jit();
|
||||||
data.origin = params.origin.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::Transfer(val) => val.into_jit(),
|
||||||
ActionValue::Apparent(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.author = ext.env_info().author.clone().into_jit();
|
||||||
data.difficulty = ext.env_info().difficulty.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..
|
// don't really know why jit timestamp is int..
|
||||||
data.timestamp = ext.env_info().timestamp as i64;
|
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();
|
let res = context.exec();
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
|
@ -254,7 +254,7 @@ fn test_origin(factory: super::Factory) {
|
|||||||
assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681");
|
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) {
|
fn test_sender(factory: super::Factory) {
|
||||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||||
let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").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());
|
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) {
|
fn test_blockhash(factory: super::Factory) {
|
||||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||||
let code = "600040600055".from_hex().unwrap();
|
let code = "600040600055".from_hex().unwrap();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "evmjit"
|
name = "evmjit"
|
||||||
version = "0.1.0"
|
version = "0.9.0"
|
||||||
authors = ["debris <marek.kotewicz@gmail.com>"]
|
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@ -42,10 +42,10 @@ pub use self::ffi::JitReturnCode as ReturnCode;
|
|||||||
pub use self::ffi::JitI256 as I256;
|
pub use self::ffi::JitI256 as I256;
|
||||||
pub use self::ffi::JitH256 as H256;
|
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,
|
/// 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.
|
/// structs.
|
||||||
pub struct RuntimeDataHandle {
|
pub struct RuntimeDataHandle {
|
||||||
runtime_data: *mut JitRuntimeData
|
runtime_data: *mut JitRuntimeData
|
||||||
@ -58,16 +58,6 @@ impl RuntimeDataHandle {
|
|||||||
runtime_data: unsafe { evmjit_create_runtime_data() }
|
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 {
|
impl Drop for RuntimeDataHandle {
|
||||||
@ -80,13 +70,51 @@ impl Deref for RuntimeDataHandle {
|
|||||||
type Target = JitRuntimeData;
|
type Target = JitRuntimeData;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.runtime_data()
|
unsafe { &*self.runtime_data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for RuntimeDataHandle {
|
impl DerefMut for RuntimeDataHandle {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
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 {
|
pub struct ContextHandle {
|
||||||
context: *mut JitContext,
|
context: *mut JitContext,
|
||||||
data_handle: RuntimeDataHandle,
|
data_handle: RuntimeDataHandle,
|
||||||
|
schedule_handle: ScheduleHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextHandle {
|
impl ContextHandle {
|
||||||
@ -107,19 +136,20 @@ impl ContextHandle {
|
|||||||
/// We also can't make ExtHandle a member of `ContextHandle` structure,
|
/// We also can't make ExtHandle a member of `ContextHandle` structure,
|
||||||
/// cause this would be a move operation or it would require a template
|
/// cause this would be a move operation or it would require a template
|
||||||
/// lifetime to a reference. Both solutions are not possible.
|
/// 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 {
|
let mut handle = ContextHandle {
|
||||||
context: std::mem::uninitialized(),
|
context: std::mem::uninitialized(),
|
||||||
|
schedule_handle: schedule_handle,
|
||||||
data_handle: data_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
|
handle
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes context.
|
/// Executes context.
|
||||||
pub fn exec(&mut self) -> JitReturnCode {
|
pub fn exec(&mut self) -> JitReturnCode {
|
||||||
unsafe { evmjit_exec(self.context) }
|
unsafe { evmjit_exec(self.context, self.schedule_handle.deref_mut()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns output data.
|
/// Returns output data.
|
||||||
@ -162,13 +192,15 @@ pub trait Ext {
|
|||||||
fn call(&mut self,
|
fn call(&mut self,
|
||||||
io_gas: *mut u64,
|
io_gas: *mut u64,
|
||||||
call_gas: u64,
|
call_gas: u64,
|
||||||
|
sender_address: *const JitH256,
|
||||||
receive_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_beg: *const u8,
|
||||||
in_size: u64,
|
in_size: u64,
|
||||||
out_beg: *mut u8,
|
out_beg: *mut u8,
|
||||||
out_size: u64,
|
out_size: u64) -> bool;
|
||||||
code_address: *const JitH256) -> bool;
|
|
||||||
|
|
||||||
fn log(&mut self,
|
fn log(&mut self,
|
||||||
beg: *const u8,
|
beg: *const u8,
|
||||||
@ -292,7 +324,8 @@ pub mod ffi {
|
|||||||
pub address: JitI256,
|
pub address: JitI256,
|
||||||
pub caller: JitI256,
|
pub caller: JitI256,
|
||||||
pub origin: JitI256,
|
pub origin: JitI256,
|
||||||
pub call_value: JitI256,
|
pub transfer_value: JitI256,
|
||||||
|
pub apparent_value: JitI256,
|
||||||
pub author: JitI256,
|
pub author: JitI256,
|
||||||
pub difficulty: JitI256,
|
pub difficulty: JitI256,
|
||||||
pub gas_limit: JitI256,
|
pub gas_limit: JitI256,
|
||||||
@ -303,6 +336,13 @@ pub mod ffi {
|
|||||||
pub code_hash: JitI256
|
pub code_hash: JitI256
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Configurable properties of git schedule.
|
||||||
|
pub struct JitSchedule {
|
||||||
|
pub have_delegate_call: bool
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn env_sload(ext: *const ExtHandle, index: *const JitI256, out_value: *mut JitI256) {
|
pub unsafe extern "C" fn env_sload(ext: *const ExtHandle, index: *const JitI256, out_value: *mut JitI256) {
|
||||||
let ext = &*ext;
|
let ext = &*ext;
|
||||||
@ -342,15 +382,17 @@ pub mod ffi {
|
|||||||
pub unsafe extern "C" fn env_call(ext: *mut ExtHandle,
|
pub unsafe extern "C" fn env_call(ext: *mut ExtHandle,
|
||||||
io_gas: *mut u64,
|
io_gas: *mut u64,
|
||||||
call_gas: u64,
|
call_gas: u64,
|
||||||
|
sender_address: *const JitH256,
|
||||||
receive_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_beg: *const u8,
|
||||||
in_size: u64,
|
in_size: u64,
|
||||||
out_beg: *mut u8,
|
out_beg: *mut u8,
|
||||||
out_size: u64,
|
out_size: u64) -> bool {
|
||||||
code_address: *const JitH256) -> bool {
|
|
||||||
let ext = &mut *ext;
|
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]
|
#[no_mangle]
|
||||||
@ -385,10 +427,12 @@ pub mod ffi {
|
|||||||
|
|
||||||
#[link(name="evmjit")]
|
#[link(name="evmjit")]
|
||||||
extern "C" {
|
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_create_runtime_data() -> *mut JitRuntimeData;
|
||||||
pub fn evmjit_destroy_runtime_data(data: *mut JitRuntimeData);
|
pub fn evmjit_destroy_runtime_data(data: *mut JitRuntimeData);
|
||||||
pub fn evmjit_destroy_context(context: *mut JitContext);
|
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"
|
// ExtHandle is not a C type, so we need to allow "improper_ctypes"
|
||||||
@ -403,11 +447,13 @@ pub mod ffi {
|
|||||||
fn ffi_test() {
|
fn ffi_test() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = evmjit_create_runtime_data();
|
let data = evmjit_create_runtime_data();
|
||||||
|
let schedule = evmjit_create_schedule();
|
||||||
let context = evmjit_create_context(data, &mut ExtHandle::empty());
|
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);
|
assert_eq!(code, JitReturnCode::Stop);
|
||||||
|
|
||||||
|
evmjit_destroy_schedule(schedule);
|
||||||
evmjit_destroy_runtime_data(data);
|
evmjit_destroy_runtime_data(data);
|
||||||
evmjit_destroy_context(context);
|
evmjit_destroy_context(context);
|
||||||
}
|
}
|
||||||
@ -416,7 +462,8 @@ fn ffi_test() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn handle_test() {
|
fn handle_test() {
|
||||||
unsafe {
|
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);
|
assert_eq!(context.exec(), ReturnCode::Stop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user