evm logs
This commit is contained in:
parent
ad43079fdc
commit
293bca363e
@ -125,11 +125,11 @@ pub trait Env {
|
||||
|
||||
fn log(&mut self,
|
||||
beg: *const u8,
|
||||
size: *const u64,
|
||||
topic1: *const JitI256,
|
||||
topic2: *const JitI256,
|
||||
topic3: *const JitI256,
|
||||
topic4: *const JitI256);
|
||||
size: u64,
|
||||
topic1: *const JitH256,
|
||||
topic2: *const JitH256,
|
||||
topic3: *const JitH256,
|
||||
topic4: *const JitH256);
|
||||
|
||||
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)]
|
||||
#[derive(Debug)]
|
||||
/// Jit runtime data.
|
||||
@ -350,11 +362,11 @@ pub mod ffi {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn env_log(env: *mut EnvHandle,
|
||||
beg: *const u8,
|
||||
size: *const u64,
|
||||
topic1: *const JitI256,
|
||||
topic2: *const JitI256,
|
||||
topic3: *const JitI256,
|
||||
topic4: *const JitI256) {
|
||||
size: u64,
|
||||
topic1: *const JitH256,
|
||||
topic2: *const JitH256,
|
||||
topic3: *const JitH256,
|
||||
topic4: *const JitH256) {
|
||||
let env = &mut *env;
|
||||
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 i = I256::from(h);
|
||||
assert_eq!([0u64, 0, 0, 0xefcdab8967452301], i.words);
|
||||
assert_eq!(H256::from(i).words, h.words);
|
||||
}
|
||||
|
@ -1,8 +1,30 @@
|
||||
//! Contract execution environment.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use util::hash::*;
|
||||
use util::uint::*;
|
||||
use util::bytes::*;
|
||||
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.
|
||||
/// It should be initalized with `State` and contract address.
|
||||
@ -22,7 +44,8 @@ use state::*;
|
||||
/// ```
|
||||
pub struct Env {
|
||||
state: State,
|
||||
address: Address
|
||||
address: Address,
|
||||
substate: SubState
|
||||
}
|
||||
|
||||
impl Env {
|
||||
@ -30,7 +53,8 @@ impl Env {
|
||||
pub fn new(state: State, address: Address) -> Env {
|
||||
Env {
|
||||
state: state,
|
||||
address: address
|
||||
address: address,
|
||||
substate: SubState::new()
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,14 +94,21 @@ impl Env {
|
||||
self.state.code(address).unwrap_or(vec![])
|
||||
}
|
||||
|
||||
pub fn log(&self, _topics: &[H256], _data: &[u8]) {
|
||||
unimplemented!();
|
||||
/// Creates log entry with given topics and data
|
||||
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
|
||||
pub fn state(self) -> State {
|
||||
self.state
|
||||
pub fn state(&self) -> &State {
|
||||
&self.state
|
||||
}
|
||||
|
||||
/// Returns substate
|
||||
pub fn logs(&self) -> &[LogEntry] {
|
||||
&self.substate.logs
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use evmjit;
|
||||
use util::hash::*;
|
||||
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 {
|
||||
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,
|
||||
_beg: *const u8,
|
||||
_size: *const u64,
|
||||
_topic1: *const evmjit::I256,
|
||||
_topic2: *const evmjit::I256,
|
||||
_topic3: *const evmjit::I256,
|
||||
_topic4: *const evmjit::I256) {
|
||||
unimplemented!();
|
||||
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.env.log(topics, bytes_ref.to_vec());
|
||||
}
|
||||
}
|
||||
|
||||
fn extcode(&self, address: *const evmjit::H256, size: *mut u64) -> *const u8 {
|
||||
@ -382,4 +410,53 @@ mod tests {
|
||||
let state = env.state();
|
||||
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
62
src/evm/logentry.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -4,9 +4,11 @@ pub mod env;
|
||||
pub mod runtime_data;
|
||||
pub mod evm;
|
||||
pub mod vmfactory;
|
||||
pub mod logentry;
|
||||
#[cfg(feature = "jit" )]
|
||||
mod jit;
|
||||
|
||||
pub use self::evm::{Evm, ReturnCode};
|
||||
pub use self::env::Env;
|
||||
pub use self::runtime_data::RuntimeData;
|
||||
pub use self::logentry::LogEntry;
|
||||
|
Loading…
Reference in New Issue
Block a user