This commit is contained in:
debris 2016-01-06 13:00:14 +01:00
parent ad43079fdc
commit 293bca363e
5 changed files with 210 additions and 25 deletions

View File

@ -125,11 +125,11 @@ pub trait Env {
fn log(&mut self, fn log(&mut self,
beg: *const u8, beg: *const u8,
size: *const u64, size: u64,
topic1: *const JitI256, topic1: *const JitH256,
topic2: *const JitI256, topic2: *const JitH256,
topic3: *const JitI256, topic3: *const JitH256,
topic4: *const JitI256); topic4: *const JitH256);
fn extcode(&self, address: *const JitH256, size: *mut u64) -> *const u8; fn extcode(&self, address: *const JitH256, size: *mut u64) -> *const u8;
} }
@ -222,6 +222,18 @@ pub mod ffi {
} }
} }
impl From<JitI256> for JitH256 {
fn from(mut i: JitI256) -> JitH256 {
unsafe {
{
let bytes: &mut [u8] = slice::from_raw_parts_mut(i.words.as_mut_ptr() as *mut u8, 32);
bytes.reverse();
}
mem::transmute(i)
}
}
}
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
/// Jit runtime data. /// Jit runtime data.
@ -350,11 +362,11 @@ pub mod ffi {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn env_log(env: *mut EnvHandle, pub unsafe extern "C" fn env_log(env: *mut EnvHandle,
beg: *const u8, beg: *const u8,
size: *const u64, size: u64,
topic1: *const JitI256, topic1: *const JitH256,
topic2: *const JitI256, topic2: *const JitH256,
topic3: *const JitI256, topic3: *const JitH256,
topic4: *const JitI256) { topic4: *const JitH256) {
let env = &mut *env; let env = &mut *env;
env.log(beg, size, topic1, topic2, topic3, topic4); env.log(beg, size, topic1, topic2, topic3, topic4);
} }
@ -403,4 +415,5 @@ fn hash_to_int() {
let h = H256 { words:[0x0123456789abcdef, 0, 0, 0] }; let h = H256 { words:[0x0123456789abcdef, 0, 0, 0] };
let i = I256::from(h); let i = I256::from(h);
assert_eq!([0u64, 0, 0, 0xefcdab8967452301], i.words); assert_eq!([0u64, 0, 0, 0xefcdab8967452301], i.words);
assert_eq!(H256::from(i).words, h.words);
} }

View File

@ -1,8 +1,30 @@
//! Contract execution environment. //! Contract execution environment.
use std::collections::HashSet;
use util::hash::*; use util::hash::*;
use util::uint::*; use util::uint::*;
use util::bytes::*;
use state::*; use state::*;
use evm::LogEntry;
struct SubState {
// any accounts that have suicided
suicides: HashSet<Address>,
// any logs
logs: Vec<LogEntry>,
// refund counter of SSTORE nonzero->zero
refunds: U256
}
impl SubState {
fn new() -> SubState {
SubState {
suicides: HashSet::new(),
logs: vec![],
refunds: U256::zero()
}
}
}
/// This structure represents contract execution environment. /// This structure represents contract execution environment.
/// It should be initalized with `State` and contract address. /// It should be initalized with `State` and contract address.
@ -22,7 +44,8 @@ use state::*;
/// ``` /// ```
pub struct Env { pub struct Env {
state: State, state: State,
address: Address address: Address,
substate: SubState
} }
impl Env { impl Env {
@ -30,7 +53,8 @@ impl Env {
pub fn new(state: State, address: Address) -> Env { pub fn new(state: State, address: Address) -> Env {
Env { Env {
state: state, state: state,
address: address address: address,
substate: SubState::new()
} }
} }
@ -70,14 +94,21 @@ impl Env {
self.state.code(address).unwrap_or(vec![]) self.state.code(address).unwrap_or(vec![])
} }
pub fn log(&self, _topics: &[H256], _data: &[u8]) { /// Creates log entry with given topics and data
unimplemented!(); pub fn log(&mut self, topics: Vec<H256>, data: Bytes) {
let address = self.address.clone();
self.substate.logs.push(LogEntry::new(address, topics, data));
} }
/// Drain state /// Returns state
// not sure if this is the best solution, but seems to be the easiest one, mk // not sure if this is the best solution, but seems to be the easiest one, mk
pub fn state(self) -> State { pub fn state(&self) -> &State {
self.state &self.state
}
/// Returns substate
pub fn logs(&self) -> &[LogEntry] {
&self.substate.logs
} }
} }

View File

@ -1,5 +1,6 @@
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::slice;
use evmjit; use evmjit;
use util::hash::*; use util::hash::*;
use util::uint::*; use util::uint::*;
@ -40,9 +41,15 @@ impl<'a> FromJit<&'a evmjit::I256> for Address {
} }
} }
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 { impl<'a> FromJit<&'a evmjit::H256> for Address {
fn from_jit(input: &'a evmjit::H256) -> Self { fn from_jit(input: &'a evmjit::H256) -> Self {
Address::from(H256::from_jit(&evmjit::I256::from(input.clone()))) Address::from(H256::from_jit(input))
} }
} }
@ -165,13 +172,34 @@ impl<'a> evmjit::Env for EnvAdapter<'a> {
} }
fn log(&mut self, fn log(&mut self,
_beg: *const u8, beg: *const u8,
_size: *const u64, size: u64,
_topic1: *const evmjit::I256, topic1: *const evmjit::H256,
_topic2: *const evmjit::I256, topic2: *const evmjit::H256,
_topic3: *const evmjit::I256, topic3: *const evmjit::H256,
_topic4: *const evmjit::I256) { topic4: *const evmjit::H256) {
unimplemented!();
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.env.log(topics, bytes_ref.to_vec());
}
} }
fn extcode(&self, address: *const evmjit::H256, size: *mut u64) -> *const u8 { fn extcode(&self, address: *const evmjit::H256, size: *mut u64) -> *const u8 {
@ -382,4 +410,53 @@ mod tests {
let state = env.state(); let state = env.state();
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0x10))); assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0x10)));
} }
#[test]
fn test_empty_log() {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let mut data = RuntimeData::new();
data.address = address.clone();
data.caller = address.clone();
data.gas = 0x174876e800;
data.code = "60006000a0".from_hex().unwrap();
let mut env = Env::new(State::new_temp(), address.clone());
let evm = JitEvm;
assert_eq!(evm.exec(data, &mut env), ReturnCode::Stop);
let logs = env.logs();
assert_eq!(logs.len(), 1);
let log = &logs[0];
assert_eq!(log.address(), &address);
assert_eq!(log.topics().len(), 0);
assert_eq!(log.bloom(), H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap());
}
#[test]
fn test_log_with_one_topic() {
// 60 ff - push ff
// 60 00 - push 00
// 53 - mstore
// 33 - caller
// 60 20 - push 20
// 60 00 - push 0
// a1 - log with 1 topic
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let mut data = RuntimeData::new();
data.address = address.clone();
data.caller = address.clone();
data.gas = 0x174876e800;
data.code = "60ff6000533360206000a1".from_hex().unwrap();
let mut env = Env::new(State::new_temp(), address.clone());
let evm = JitEvm;
assert_eq!(evm.exec(data, &mut env), ReturnCode::Stop);
let logs = env.logs();
assert_eq!(logs.len(), 1);
let log = &logs[0];
assert_eq!(log.address(), &address);
assert_eq!(log.topics().len(), 1);
let topic = &log.topics()[0];
assert_eq!(topic, &H256::from(address.clone()));
}
} }

62
src/evm/logentry.rs Normal file
View File

@ -0,0 +1,62 @@
use util::hash::*;
use util::bytes::*;
use util::sha3::*;
/// Data sturcture used to represent Evm log entry.
pub struct LogEntry {
address: Address,
topics: Vec<H256>,
data: Bytes
}
impl LogEntry {
/// This function should be called to create new log entry.
pub fn new(address: Address, topics: Vec<H256>, data: Bytes) -> LogEntry {
LogEntry {
address: address,
topics: topics,
data: data
}
}
/// Returns reference to address.
pub fn address(&self) -> &Address {
&self.address
}
/// Returns reference to topics.
pub fn topics(&self) -> &[H256] {
&self.topics
}
/// Returns reference to data.
pub fn data(&self) -> &Bytes {
&self.data
}
/// Returns log bloom of given log entry.
pub fn bloom(&self) -> H2048 {
let mut bloom = H2048::new();
bloom.shift_bloom(&self.address.sha3());
for topic in self.topics.iter() {
bloom.shift_bloom(&topic.sha3());
}
bloom
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use util::hash::*;
use util::bytes::*;
use evm::LogEntry;
#[test]
fn test_empty_log_bloom() {
let bloom = H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let log = LogEntry::new(address, vec![], vec![]);
assert_eq!(log.bloom(), bloom);
}
}

View File

@ -4,9 +4,11 @@ pub mod env;
pub mod runtime_data; pub mod runtime_data;
pub mod evm; pub mod evm;
pub mod vmfactory; pub mod vmfactory;
pub mod logentry;
#[cfg(feature = "jit" )] #[cfg(feature = "jit" )]
mod jit; mod jit;
pub use self::evm::{Evm, ReturnCode}; pub use self::evm::{Evm, ReturnCode};
pub use self::env::Env; pub use self::env::Env;
pub use self::runtime_data::RuntimeData; pub use self::runtime_data::RuntimeData;
pub use self::logentry::LogEntry;