evm logs
This commit is contained in:
parent
ad43079fdc
commit
293bca363e
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
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 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;
|
||||||
|
Loading…
Reference in New Issue
Block a user