parent
80afb78c7f
commit
0dcdaa7a2a
@ -43,6 +43,8 @@ impl ActionValue {
|
||||
pub struct ActionParams {
|
||||
/// Address of currently executed code.
|
||||
pub code_address: Address,
|
||||
/// Hash of currently executed code.
|
||||
pub code_hash: H256,
|
||||
/// Receive address. Usually equal to code_address,
|
||||
/// except when called using CALLCODE.
|
||||
pub address: Address,
|
||||
@ -57,7 +59,7 @@ pub struct ActionParams {
|
||||
/// Transaction value.
|
||||
pub value: ActionValue,
|
||||
/// Code being executed.
|
||||
pub code: Option<Bytes>,
|
||||
pub code: Option<Arc<Bytes>>,
|
||||
/// Input data.
|
||||
pub data: Option<Bytes>,
|
||||
/// Type of call
|
||||
@ -70,6 +72,7 @@ impl Default for ActionParams {
|
||||
fn default() -> ActionParams {
|
||||
ActionParams {
|
||||
code_address: Address::new(),
|
||||
code_hash: SHA3_EMPTY,
|
||||
address: Address::new(),
|
||||
sender: Address::new(),
|
||||
origin: Address::new(),
|
||||
@ -88,10 +91,11 @@ impl From<ethjson::vm::Transaction> for ActionParams {
|
||||
let address: Address = t.address.into();
|
||||
ActionParams {
|
||||
code_address: Address::new(),
|
||||
code_hash: (&*t.code).sha3(),
|
||||
address: address,
|
||||
sender: t.sender.into(),
|
||||
origin: t.origin.into(),
|
||||
code: Some(t.code.into()),
|
||||
code: Some(Arc::new(t.code.into())),
|
||||
data: Some(t.data.into()),
|
||||
gas: t.gas.into(),
|
||||
gas_price: t.gas_price.into(),
|
||||
|
@ -831,7 +831,7 @@ impl BlockChainClient for Client {
|
||||
}
|
||||
|
||||
fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>> {
|
||||
self.state_at(id).map(|s| s.code(address))
|
||||
self.state_at(id).map(|s| s.code(address).map(|c| (*c).clone()))
|
||||
}
|
||||
|
||||
fn balance(&self, address: &Address, id: BlockID) -> Option<U256> {
|
||||
|
@ -81,7 +81,7 @@ pub trait Ext {
|
||||
) -> MessageCallResult;
|
||||
|
||||
/// Returns code at given address
|
||||
fn extcode(&self, address: &Address) -> Bytes;
|
||||
fn extcode(&self, address: &Address) -> Arc<Bytes>;
|
||||
|
||||
/// Returns code size at given address
|
||||
fn extcodesize(&self, address: &Address) -> usize;
|
||||
|
@ -18,8 +18,10 @@
|
||||
//!
|
||||
//! TODO: consider spliting it into two separate files.
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use evm::Evm;
|
||||
use util::{U256, Uint};
|
||||
use super::interpreter::SharedCache;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
/// Type of EVM to use.
|
||||
@ -82,7 +84,8 @@ impl VMType {
|
||||
/// Evm factory. Creates appropriate Evm.
|
||||
#[derive(Clone)]
|
||||
pub struct Factory {
|
||||
evm: VMType
|
||||
evm: VMType,
|
||||
evm_cache: Arc<SharedCache>,
|
||||
}
|
||||
|
||||
impl Factory {
|
||||
@ -95,9 +98,9 @@ impl Factory {
|
||||
Box::new(super::jit::JitEvm::default())
|
||||
},
|
||||
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
|
||||
Box::new(super::interpreter::Interpreter::<usize>::default())
|
||||
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
|
||||
} else {
|
||||
Box::new(super::interpreter::Interpreter::<U256>::default())
|
||||
Box::new(super::interpreter::Interpreter::<U256>::new(self.evm_cache.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,9 +111,9 @@ impl Factory {
|
||||
pub fn create(&self, gas: U256) -> Box<Evm> {
|
||||
match self.evm {
|
||||
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
|
||||
Box::new(super::interpreter::Interpreter::<usize>::default())
|
||||
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
|
||||
} else {
|
||||
Box::new(super::interpreter::Interpreter::<U256>::default())
|
||||
Box::new(super::interpreter::Interpreter::<U256>::new(self.evm_cache.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,7 +121,8 @@ impl Factory {
|
||||
/// Create new instance of specific `VMType` factory
|
||||
pub fn new(evm: VMType) -> Self {
|
||||
Factory {
|
||||
evm: evm
|
||||
evm: evm,
|
||||
evm_cache: Arc::new(SharedCache::default()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +136,8 @@ impl Default for Factory {
|
||||
#[cfg(all(feature = "jit", not(test)))]
|
||||
fn default() -> Factory {
|
||||
Factory {
|
||||
evm: VMType::Jit
|
||||
evm: VMType::Jit,
|
||||
evm_cache: Arc::new(SharedCache::default()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +145,8 @@ impl Default for Factory {
|
||||
#[cfg(any(not(feature = "jit"), test))]
|
||||
fn default() -> Factory {
|
||||
Factory {
|
||||
evm: VMType::Interpreter
|
||||
evm: VMType::Interpreter,
|
||||
evm_cache: Arc::new(SharedCache::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,10 +31,12 @@ macro_rules! evm_debug {
|
||||
mod gasometer;
|
||||
mod stack;
|
||||
mod memory;
|
||||
mod shared_cache;
|
||||
|
||||
use self::gasometer::Gasometer;
|
||||
use self::stack::{Stack, VecStack};
|
||||
use self::memory::Memory;
|
||||
pub use self::shared_cache::SharedCache;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use common::*;
|
||||
@ -98,9 +100,9 @@ enum InstructionResult<Gas> {
|
||||
|
||||
|
||||
/// Intepreter EVM implementation
|
||||
#[derive(Default)]
|
||||
pub struct Interpreter<Cost: CostType> {
|
||||
mem: Vec<u8>,
|
||||
cache: Arc<SharedCache>,
|
||||
_type: PhantomData<Cost>,
|
||||
}
|
||||
|
||||
@ -109,7 +111,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
||||
self.mem.clear();
|
||||
|
||||
let code = ¶ms.code.as_ref().unwrap();
|
||||
let valid_jump_destinations = self.find_jump_destinations(code);
|
||||
let valid_jump_destinations = self.cache.jump_destinations(¶ms.code_hash, code);
|
||||
|
||||
let mut gasometer = Gasometer::<Cost>::new(try!(Cost::from_u256(params.gas)));
|
||||
let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero());
|
||||
@ -188,6 +190,14 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
||||
}
|
||||
|
||||
impl<Cost: CostType> Interpreter<Cost> {
|
||||
/// Create a new `Interpreter` instance with shared cache.
|
||||
pub fn new(cache: Arc<SharedCache>) -> Interpreter<Cost> {
|
||||
Interpreter {
|
||||
mem: Vec::new(),
|
||||
cache: cache,
|
||||
_type: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_instruction(&self, ext: &evm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack<U256>) -> evm::Result<()> {
|
||||
let schedule = ext.schedule();
|
||||
@ -486,10 +496,10 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
stack.push(U256::from(len));
|
||||
},
|
||||
instructions::CALLDATACOPY => {
|
||||
self.copy_data_to_memory(stack, ¶ms.data.clone().unwrap_or_else(|| vec![]));
|
||||
self.copy_data_to_memory(stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
|
||||
},
|
||||
instructions::CODECOPY => {
|
||||
self.copy_data_to_memory(stack, ¶ms.code.clone().unwrap_or_else(|| vec![]));
|
||||
self.copy_data_to_memory(stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8]));
|
||||
},
|
||||
instructions::EXTCODECOPY => {
|
||||
let address = u256_to_address(&stack.pop_back());
|
||||
@ -790,23 +800,6 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_jump_destinations(&self, code: &[u8]) -> BitSet {
|
||||
let mut jump_dests = BitSet::with_capacity(code.len());
|
||||
let mut position = 0;
|
||||
|
||||
while position < code.len() {
|
||||
let instruction = code[position];
|
||||
|
||||
if instruction == instructions::JUMPDEST {
|
||||
jump_dests.insert(position);
|
||||
} else if instructions::is_push(instruction) {
|
||||
position += instructions::get_push_bytes(instruction);
|
||||
}
|
||||
position += 1;
|
||||
}
|
||||
|
||||
jump_dests
|
||||
}
|
||||
}
|
||||
|
||||
fn get_and_reset_sign(value: U256) -> (U256, bool) {
|
||||
@ -833,15 +826,3 @@ fn address_to_u256(value: Address) -> U256 {
|
||||
U256::from(&*H256::from(value))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_jump_destinations() {
|
||||
// given
|
||||
let interpreter = Interpreter::<U256>::default();
|
||||
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b01600055".from_hex().unwrap();
|
||||
|
||||
// when
|
||||
let valid_jump_destinations = interpreter.find_jump_destinations(&code);
|
||||
|
||||
// then
|
||||
assert!(valid_jump_destinations.contains(66));
|
||||
}
|
||||
|
84
ethcore/src/evm/interpreter/shared_cache.rs
Normal file
84
ethcore/src/evm/interpreter/shared_cache.rs
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::Arc;
|
||||
use lru_cache::LruCache;
|
||||
use util::{H256, Mutex};
|
||||
use util::sha3::*;
|
||||
use bit_set::BitSet;
|
||||
use super::super::instructions;
|
||||
|
||||
const CACHE_CODE_ITEMS: usize = 4096;
|
||||
|
||||
/// GLobal cache for EVM interpreter
|
||||
pub struct SharedCache {
|
||||
jump_destinations: Mutex<LruCache<H256, Arc<BitSet>>>
|
||||
}
|
||||
|
||||
impl SharedCache {
|
||||
/// Get jump destincations bitmap for a contract.
|
||||
pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc<BitSet> {
|
||||
if code_hash == &SHA3_EMPTY {
|
||||
return Self::find_jump_destinations(code);
|
||||
}
|
||||
if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) {
|
||||
return d.clone();
|
||||
}
|
||||
|
||||
let d = Self::find_jump_destinations(code);
|
||||
self.jump_destinations.lock().insert(code_hash.clone(), d.clone());
|
||||
d
|
||||
}
|
||||
|
||||
fn find_jump_destinations(code: &[u8]) -> Arc<BitSet> {
|
||||
let mut jump_dests = BitSet::with_capacity(code.len());
|
||||
let mut position = 0;
|
||||
|
||||
while position < code.len() {
|
||||
let instruction = code[position];
|
||||
|
||||
if instruction == instructions::JUMPDEST {
|
||||
jump_dests.insert(position);
|
||||
} else if instructions::is_push(instruction) {
|
||||
position += instructions::get_push_bytes(instruction);
|
||||
}
|
||||
position += 1;
|
||||
}
|
||||
Arc::new(jump_dests)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SharedCache {
|
||||
fn default() -> SharedCache {
|
||||
SharedCache {
|
||||
jump_destinations: Mutex::new(LruCache::new(CACHE_CODE_ITEMS)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_find_jump_destinations() {
|
||||
use util::FromHex;
|
||||
// given
|
||||
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b01600055".from_hex().unwrap();
|
||||
|
||||
// when
|
||||
let valid_jump_destinations = SharedCache::find_jump_destinations(&code);
|
||||
|
||||
// then
|
||||
assert!(valid_jump_destinations.contains(66));
|
||||
}
|
@ -49,7 +49,7 @@ pub struct FakeExt {
|
||||
depth: usize,
|
||||
store: HashMap<H256, H256>,
|
||||
blockhashes: HashMap<U256, H256>,
|
||||
codes: HashMap<Address, Bytes>,
|
||||
codes: HashMap<Address, Arc<Bytes>>,
|
||||
logs: Vec<FakeLogEntry>,
|
||||
_suicides: HashSet<Address>,
|
||||
info: EnvInfo,
|
||||
@ -136,8 +136,8 @@ impl Ext for FakeExt {
|
||||
MessageCallResult::Success(*gas)
|
||||
}
|
||||
|
||||
fn extcode(&self, address: &Address) -> Bytes {
|
||||
self.codes.get(address).unwrap_or(&Bytes::new()).clone()
|
||||
fn extcode(&self, address: &Address) -> Arc<Bytes> {
|
||||
self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()
|
||||
}
|
||||
|
||||
fn extcodesize(&self, address: &Address) -> usize {
|
||||
@ -184,11 +184,11 @@ fn test_stack_underflow() {
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let err = {
|
||||
let mut vm : Box<evm::Evm> = Box::new(super::interpreter::Interpreter::<usize>::default());
|
||||
let mut vm : Box<evm::Evm> = Box::new(super::interpreter::Interpreter::<usize>::new(Arc::new(super::interpreter::SharedCache::default())));
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap_err()
|
||||
};
|
||||
|
||||
@ -211,7 +211,7 @@ fn test_add(factory: super::Factory) {
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -231,7 +231,7 @@ fn test_sha3(factory: super::Factory) {
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -251,7 +251,7 @@ fn test_address(factory: super::Factory) {
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -273,7 +273,7 @@ fn test_origin(factory: super::Factory) {
|
||||
params.address = address.clone();
|
||||
params.origin = origin.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -295,7 +295,7 @@ fn test_sender(factory: super::Factory) {
|
||||
params.address = address.clone();
|
||||
params.sender = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -329,9 +329,9 @@ fn test_extcodecopy(factory: super::Factory) {
|
||||
params.address = address.clone();
|
||||
params.sender = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
ext.codes.insert(sender, sender_code);
|
||||
ext.codes.insert(sender, Arc::new(sender_code));
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
@ -350,7 +350,7 @@ fn test_log_empty(factory: super::Factory) {
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -382,7 +382,7 @@ fn test_log_sender(factory: super::Factory) {
|
||||
params.address = address.clone();
|
||||
params.sender = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -406,7 +406,7 @@ fn test_blockhash(factory: super::Factory) {
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
ext.blockhashes.insert(U256::zero(), blockhash.clone());
|
||||
|
||||
@ -428,7 +428,7 @@ fn test_calldataload(factory: super::Factory) {
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(data);
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
@ -449,7 +449,7 @@ fn test_author(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
ext.info.author = author;
|
||||
|
||||
@ -469,7 +469,7 @@ fn test_timestamp(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
ext.info.timestamp = timestamp;
|
||||
|
||||
@ -489,7 +489,7 @@ fn test_number(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
ext.info.number = number;
|
||||
|
||||
@ -509,7 +509,7 @@ fn test_difficulty(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
ext.info.difficulty = difficulty;
|
||||
|
||||
@ -529,7 +529,7 @@ fn test_gas_limit(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
ext.info.gas_limit = gas_limit;
|
||||
|
||||
@ -548,7 +548,7 @@ fn test_mul(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -566,7 +566,7 @@ fn test_sub(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -584,7 +584,7 @@ fn test_div(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -602,7 +602,7 @@ fn test_div_zero(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -620,7 +620,7 @@ fn test_mod(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -639,7 +639,7 @@ fn test_smod(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -658,7 +658,7 @@ fn test_sdiv(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -677,7 +677,7 @@ fn test_exp(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -697,7 +697,7 @@ fn test_comparison(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -718,7 +718,7 @@ fn test_signed_comparison(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -739,7 +739,7 @@ fn test_bitops(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(150_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -762,7 +762,7 @@ fn test_addmod_mulmod(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -783,7 +783,7 @@ fn test_byte(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -802,7 +802,7 @@ fn test_signextend(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -822,7 +822,7 @@ fn test_badinstruction_int() {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let err = {
|
||||
@ -842,7 +842,7 @@ fn test_pop(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -862,7 +862,7 @@ fn test_extops(factory: super::Factory) {
|
||||
params.gas = U256::from(150_000);
|
||||
params.gas_price = U256::from(0x32);
|
||||
params.value = ActionValue::Transfer(U256::from(0x99));
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -885,7 +885,7 @@ fn test_jumps(factory: super::Factory) {
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(150_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
@ -908,7 +908,7 @@ fn test_calls(factory: super::Factory) {
|
||||
let code_address = Address::from(0x998);
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(150_000);
|
||||
params.code = Some(code);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.address = address.clone();
|
||||
let mut ext = FakeExt::new();
|
||||
ext.balances = {
|
||||
|
@ -168,13 +168,14 @@ impl<'a> Executive<'a> {
|
||||
let new_address = contract_address(&sender, &nonce);
|
||||
let params = ActionParams {
|
||||
code_address: new_address.clone(),
|
||||
code_hash: t.data.sha3(),
|
||||
address: new_address,
|
||||
sender: sender.clone(),
|
||||
origin: sender.clone(),
|
||||
gas: init_gas,
|
||||
gas_price: t.gas_price,
|
||||
value: ActionValue::Transfer(t.value),
|
||||
code: Some(t.data.clone()),
|
||||
code: Some(Arc::new(t.data.clone())),
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
};
|
||||
@ -190,6 +191,7 @@ impl<'a> Executive<'a> {
|
||||
gas_price: t.gas_price,
|
||||
value: ActionValue::Transfer(t.value),
|
||||
code: self.state.code(address),
|
||||
code_hash: self.state.code_hash(address),
|
||||
data: Some(t.data.clone()),
|
||||
call_type: CallType::Call,
|
||||
};
|
||||
@ -511,7 +513,7 @@ mod tests {
|
||||
params.address = address.clone();
|
||||
params.sender = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some("3331600055".from_hex().unwrap());
|
||||
params.code = Some(Arc::new("3331600055".from_hex().unwrap()));
|
||||
params.value = ActionValue::Transfer(U256::from(0x7));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
@ -570,7 +572,7 @@ mod tests {
|
||||
params.sender = sender.clone();
|
||||
params.origin = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
@ -628,7 +630,7 @@ mod tests {
|
||||
params.sender = sender.clone();
|
||||
params.origin = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
params.call_type = CallType::Call;
|
||||
let mut state_result = get_temp_state();
|
||||
@ -740,7 +742,7 @@ mod tests {
|
||||
params.sender = sender.clone();
|
||||
params.origin = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(100.into());
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
@ -828,7 +830,7 @@ mod tests {
|
||||
params.sender = sender.clone();
|
||||
params.origin = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
@ -880,7 +882,7 @@ mod tests {
|
||||
params.sender = sender.clone();
|
||||
params.origin = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
@ -937,7 +939,7 @@ mod tests {
|
||||
params.address = address_a.clone();
|
||||
params.sender = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code_a.clone());
|
||||
params.code = Some(Arc::new(code_a.clone()));
|
||||
params.value = ActionValue::Transfer(U256::from(100_000));
|
||||
|
||||
let mut state_result = get_temp_state();
|
||||
@ -987,10 +989,10 @@ mod tests {
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.code = Some(Arc::new(code.clone()));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.init_code(&address, code.clone());
|
||||
state.init_code(&address, code);
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
@ -1188,7 +1190,7 @@ mod tests {
|
||||
params.sender = sender.clone();
|
||||
params.origin = sender.clone();
|
||||
params.gas = U256::from(0x0186a0);
|
||||
params.code = Some(code.clone());
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
|
@ -146,7 +146,8 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
gas: *gas,
|
||||
gas_price: self.origin_info.gas_price,
|
||||
value: ActionValue::Transfer(*value),
|
||||
code: Some(code.to_vec()),
|
||||
code: Some(Arc::new(code.to_vec())),
|
||||
code_hash: code.sha3(),
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
};
|
||||
@ -185,6 +186,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
gas: *gas,
|
||||
gas_price: self.origin_info.gas_price,
|
||||
code: self.state.code(code_address),
|
||||
code_hash: self.state.code_hash(code_address),
|
||||
data: Some(data.to_vec()),
|
||||
call_type: call_type,
|
||||
};
|
||||
@ -201,8 +203,8 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
}
|
||||
}
|
||||
|
||||
fn extcode(&self, address: &Address) -> Bytes {
|
||||
self.state.code(address).unwrap_or_else(|| vec![])
|
||||
fn extcode(&self, address: &Address) -> Arc<Bytes> {
|
||||
self.state.code(address).unwrap_or_else(|| Arc::new(vec![]))
|
||||
}
|
||||
|
||||
fn extcodesize(&self, address: &Address) -> usize {
|
||||
|
@ -127,7 +127,7 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
|
||||
MessageCallResult::Success(*gas)
|
||||
}
|
||||
|
||||
fn extcode(&self, address: &Address) -> Bytes {
|
||||
fn extcode(&self, address: &Address) -> Arc<Bytes> {
|
||||
self.ext.extcode(address)
|
||||
}
|
||||
|
||||
@ -232,7 +232,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
||||
for (address, account) in vm.post_state.unwrap().into_iter() {
|
||||
let address = address.into();
|
||||
let code: Vec<u8> = account.code.into();
|
||||
fail_unless(state.code(&address).unwrap_or_else(Vec::new) == code, "code is incorrect");
|
||||
fail_unless(state.code(&address).as_ref().map_or_else(|| code.is_empty(), |c| &**c == &code), "code is incorrect");
|
||||
fail_unless(state.balance(&address) == account.balance.into(), "balance is incorrect");
|
||||
fail_unless(state.nonce(&address) == account.nonce.into(), "nonce is incorrect");
|
||||
account.storage.into_iter().foreach(|(k, v)| {
|
||||
|
@ -587,7 +587,7 @@ impl MinerService for Miner {
|
||||
|
||||
fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
|
||||
let sealing_work = self.sealing_work.lock();
|
||||
sealing_work.queue.peek_last_ref().map_or_else(|| chain.latest_code(address), |b| b.block().fields().state.code(address))
|
||||
sealing_work.queue.peek_last_ref().map_or_else(|| chain.latest_code(address), |b| b.block().fields().state.code(address).map(|c| (*c).clone()))
|
||||
}
|
||||
|
||||
fn set_author(&self, author: Address) {
|
||||
|
@ -40,14 +40,16 @@ pub struct Account {
|
||||
// Modified storage. Accumulates changes to storage made in `set_storage`
|
||||
// Takes precedence over `storage_cache`.
|
||||
storage_changes: HashMap<H256, H256>,
|
||||
// Code hash of the account. If None, means that it's a contract whose code has not yet been set.
|
||||
code_hash: Option<H256>,
|
||||
// Code hash of the account.
|
||||
code_hash: H256,
|
||||
// Size of the accoun code.
|
||||
code_size: Option<usize>,
|
||||
// Code cache of the account.
|
||||
code_cache: Bytes,
|
||||
// Account is new or has been modified
|
||||
code_cache: Arc<Bytes>,
|
||||
// Account is new or has been modified.
|
||||
filth: Filth,
|
||||
// Account code new or has been modified.
|
||||
code_filth: Filth,
|
||||
// Cached address hash.
|
||||
address_hash: Cell<Option<H256>>,
|
||||
}
|
||||
@ -62,10 +64,11 @@ impl Account {
|
||||
storage_root: SHA3_NULL_RLP,
|
||||
storage_cache: Self::empty_storage_cache(),
|
||||
storage_changes: storage,
|
||||
code_hash: Some(code.sha3()),
|
||||
code_hash: code.sha3(),
|
||||
code_size: Some(code.len()),
|
||||
code_cache: code,
|
||||
code_cache: Arc::new(code),
|
||||
filth: Filth::Dirty,
|
||||
code_filth: Filth::Dirty,
|
||||
address_hash: Cell::new(None),
|
||||
}
|
||||
}
|
||||
@ -82,9 +85,10 @@ impl Account {
|
||||
storage_root: SHA3_NULL_RLP,
|
||||
storage_cache: Self::empty_storage_cache(),
|
||||
storage_changes: pod.storage.into_iter().collect(),
|
||||
code_hash: pod.code.as_ref().map(|c| c.sha3()),
|
||||
code_hash: pod.code.as_ref().map_or(SHA3_EMPTY, |c| c.sha3()),
|
||||
code_filth: Filth::Dirty,
|
||||
code_size: Some(pod.code.as_ref().map_or(0, |c| c.len())),
|
||||
code_cache: pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c),
|
||||
code_cache: Arc::new(pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c)),
|
||||
filth: Filth::Dirty,
|
||||
address_hash: Cell::new(None),
|
||||
}
|
||||
@ -98,10 +102,11 @@ impl Account {
|
||||
storage_root: SHA3_NULL_RLP,
|
||||
storage_cache: Self::empty_storage_cache(),
|
||||
storage_changes: HashMap::new(),
|
||||
code_hash: Some(SHA3_EMPTY),
|
||||
code_cache: vec![],
|
||||
code_hash: SHA3_EMPTY,
|
||||
code_cache: Arc::new(vec![]),
|
||||
code_size: Some(0),
|
||||
filth: Filth::Dirty,
|
||||
code_filth: Filth::Clean,
|
||||
address_hash: Cell::new(None),
|
||||
}
|
||||
}
|
||||
@ -115,10 +120,11 @@ impl Account {
|
||||
storage_root: r.val_at(2),
|
||||
storage_cache: Self::empty_storage_cache(),
|
||||
storage_changes: HashMap::new(),
|
||||
code_hash: Some(r.val_at(3)),
|
||||
code_cache: vec![],
|
||||
code_hash: r.val_at(3),
|
||||
code_cache: Arc::new(vec![]),
|
||||
code_size: None,
|
||||
filth: Filth::Clean,
|
||||
code_filth: Filth::Clean,
|
||||
address_hash: Cell::new(None),
|
||||
}
|
||||
}
|
||||
@ -132,10 +138,11 @@ impl Account {
|
||||
storage_root: SHA3_NULL_RLP,
|
||||
storage_cache: Self::empty_storage_cache(),
|
||||
storage_changes: HashMap::new(),
|
||||
code_hash: None,
|
||||
code_cache: vec![],
|
||||
code_hash: SHA3_EMPTY,
|
||||
code_cache: Arc::new(vec![]),
|
||||
code_size: None,
|
||||
filth: Filth::Dirty,
|
||||
code_filth: Filth::Clean,
|
||||
address_hash: Cell::new(None),
|
||||
}
|
||||
}
|
||||
@ -143,16 +150,15 @@ impl Account {
|
||||
/// Set this account's code to the given code.
|
||||
/// NOTE: Account should have been created with `new_contract()`
|
||||
pub fn init_code(&mut self, code: Bytes) {
|
||||
assert!(self.code_hash.is_none());
|
||||
self.code_cache = code;
|
||||
self.code_hash = code.sha3();
|
||||
self.code_cache = Arc::new(code);
|
||||
self.code_size = Some(self.code_cache.len());
|
||||
self.filth = Filth::Dirty;
|
||||
self.code_filth = Filth::Dirty;
|
||||
}
|
||||
|
||||
/// Reset this account's code to the given code.
|
||||
pub fn reset_code(&mut self, code: Bytes) {
|
||||
self.code_hash = None;
|
||||
self.code_size = Some(0);
|
||||
self.init_code(code);
|
||||
}
|
||||
|
||||
@ -209,10 +215,9 @@ impl Account {
|
||||
/// return the nonce associated with this account.
|
||||
pub fn nonce(&self) -> &U256 { &self.nonce }
|
||||
|
||||
#[cfg(test)]
|
||||
/// return the code hash associated with this account.
|
||||
pub fn code_hash(&self) -> H256 {
|
||||
self.code_hash.clone().unwrap_or(SHA3_EMPTY)
|
||||
self.code_hash.clone()
|
||||
}
|
||||
|
||||
/// return the code hash associated with this account.
|
||||
@ -227,13 +232,11 @@ impl Account {
|
||||
|
||||
/// returns the account's code. If `None` then the code cache isn't available -
|
||||
/// get someone who knows to call `note_code`.
|
||||
pub fn code(&self) -> Option<&[u8]> {
|
||||
match self.code_hash {
|
||||
Some(c) if c == SHA3_EMPTY && self.code_cache.is_empty() => Some(&self.code_cache),
|
||||
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
|
||||
None => Some(&self.code_cache),
|
||||
_ => None,
|
||||
pub fn code(&self) -> Option<Arc<Bytes>> {
|
||||
if self.code_hash != SHA3_EMPTY && self.code_cache.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(self.code_cache.clone())
|
||||
}
|
||||
|
||||
/// returns the account's code size. If `None` then the code cache or code size cache isn't available -
|
||||
@ -246,24 +249,23 @@ impl Account {
|
||||
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
|
||||
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
|
||||
let h = code.sha3();
|
||||
match self.code_hash {
|
||||
Some(ref i) if h == *i => {
|
||||
self.code_cache = code;
|
||||
self.code_size = Some(self.code_cache.len());
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(h)
|
||||
if self.code_hash == h {
|
||||
self.code_cache = Arc::new(code);
|
||||
self.code_size = Some(self.code_cache.len());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(h)
|
||||
}
|
||||
}
|
||||
|
||||
/// Is `code_cache` valid; such that code is going to return Some?
|
||||
pub fn is_cached(&self) -> bool {
|
||||
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == Some(SHA3_EMPTY))
|
||||
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == SHA3_EMPTY)
|
||||
}
|
||||
|
||||
/// Is this a new or modified account?
|
||||
pub fn is_dirty(&self) -> bool {
|
||||
self.filth == Filth::Dirty || !self.storage_is_clean()
|
||||
self.filth == Filth::Dirty || self.code_filth == Filth::Dirty || !self.storage_is_clean()
|
||||
}
|
||||
|
||||
/// Mark account as clean.
|
||||
@ -277,20 +279,17 @@ impl Account {
|
||||
// TODO: fill out self.code_cache;
|
||||
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
||||
self.is_cached() ||
|
||||
match self.code_hash {
|
||||
Some(ref h) => match db.get(h) {
|
||||
Some(x) => {
|
||||
self.code_cache = x.to_vec();
|
||||
self.code_size = Some(x.len());
|
||||
true
|
||||
},
|
||||
_ => {
|
||||
warn!("Failed reverse get of {}", h);
|
||||
false
|
||||
},
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
match db.get(&self.code_hash) {
|
||||
Some(x) => {
|
||||
self.code_cache = Arc::new(x.to_vec());
|
||||
self.code_size = Some(x.len());
|
||||
true
|
||||
},
|
||||
_ => {
|
||||
warn!("Failed reverse get of {}", self.code_hash);
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide a database to get `code_size`. Should not be called if it is a contract without code.
|
||||
@ -298,18 +297,19 @@ impl Account {
|
||||
// TODO: fill out self.code_cache;
|
||||
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
||||
self.code_size.is_some() ||
|
||||
match self.code_hash {
|
||||
Some(ref h) if h != &SHA3_EMPTY => match db.get(h) {
|
||||
if self.code_hash != SHA3_EMPTY {
|
||||
match db.get(&self.code_hash) {
|
||||
Some(x) => {
|
||||
self.code_size = Some(x.len());
|
||||
true
|
||||
},
|
||||
_ => {
|
||||
warn!("Failed reverse get of {}", h);
|
||||
warn!("Failed reverse get of {}", self.code_hash);
|
||||
false
|
||||
},
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,15 +370,16 @@ impl Account {
|
||||
|
||||
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
|
||||
pub fn commit_code(&mut self, db: &mut HashDB) {
|
||||
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
|
||||
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
|
||||
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty());
|
||||
match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) {
|
||||
(true, true) => {
|
||||
self.code_hash = Some(SHA3_EMPTY);
|
||||
self.code_size = Some(0);
|
||||
self.code_filth = Filth::Clean;
|
||||
},
|
||||
(true, false) => {
|
||||
self.code_hash = Some(db.insert(&self.code_cache));
|
||||
db.emplace(self.code_hash.clone(), (*self.code_cache).clone());
|
||||
self.code_size = Some(self.code_cache.len());
|
||||
self.code_filth = Filth::Clean;
|
||||
},
|
||||
(false, _) => {},
|
||||
}
|
||||
@ -390,7 +391,7 @@ impl Account {
|
||||
stream.append(&self.nonce);
|
||||
stream.append(&self.balance);
|
||||
stream.append(&self.storage_root);
|
||||
stream.append(self.code_hash.as_ref().unwrap_or(&SHA3_EMPTY));
|
||||
stream.append(&self.code_hash);
|
||||
stream.out()
|
||||
}
|
||||
|
||||
@ -404,8 +405,9 @@ impl Account {
|
||||
storage_changes: HashMap::new(),
|
||||
code_hash: self.code_hash.clone(),
|
||||
code_size: self.code_size.clone(),
|
||||
code_cache: Bytes::new(),
|
||||
code_cache: self.code_cache.clone(),
|
||||
filth: self.filth,
|
||||
code_filth: self.code_filth,
|
||||
address_hash: self.address_hash.clone(),
|
||||
}
|
||||
}
|
||||
@ -433,6 +435,7 @@ impl Account {
|
||||
self.nonce = other.nonce;
|
||||
self.storage_root = other.storage_root;
|
||||
self.code_hash = other.code_hash;
|
||||
self.code_filth = other.code_filth;
|
||||
self.code_cache = other.code_cache;
|
||||
self.code_size = other.code_size;
|
||||
self.address_hash = other.address_hash;
|
||||
@ -536,7 +539,7 @@ mod tests {
|
||||
let mut db = MemoryDB::new();
|
||||
let mut db = AccountDBMut::new(&mut db, &Address::new());
|
||||
a.init_code(vec![0x55, 0x44, 0xffu8]);
|
||||
assert_eq!(a.code_hash(), SHA3_EMPTY);
|
||||
assert_eq!(a.code_filth, Filth::Dirty);
|
||||
assert_eq!(a.code_size(), Some(3));
|
||||
a.commit_code(&mut db);
|
||||
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
|
||||
@ -548,11 +551,12 @@ mod tests {
|
||||
let mut db = MemoryDB::new();
|
||||
let mut db = AccountDBMut::new(&mut db, &Address::new());
|
||||
a.init_code(vec![0x55, 0x44, 0xffu8]);
|
||||
assert_eq!(a.code_hash(), SHA3_EMPTY);
|
||||
assert_eq!(a.code_filth, Filth::Dirty);
|
||||
a.commit_code(&mut db);
|
||||
assert_eq!(a.code_filth, Filth::Clean);
|
||||
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
|
||||
a.reset_code(vec![0x55]);
|
||||
assert_eq!(a.code_hash(), SHA3_EMPTY);
|
||||
assert_eq!(a.code_filth, Filth::Dirty);
|
||||
a.commit_code(&mut db);
|
||||
assert_eq!(a.code_hash().hex(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be");
|
||||
}
|
||||
|
@ -319,9 +319,14 @@ impl State {
|
||||
}
|
||||
|
||||
/// Get accounts' code.
|
||||
pub fn code(&self, a: &Address) -> Option<Bytes> {
|
||||
pub fn code(&self, a: &Address) -> Option<Arc<Bytes>> {
|
||||
self.ensure_cached(a, RequireCache::Code,
|
||||
|a| a.as_ref().map_or(None, |a| a.code().map(|x|x.to_vec())))
|
||||
|a| a.as_ref().map_or(None, |a| a.code().clone()))
|
||||
}
|
||||
|
||||
pub fn code_hash(&self, a: &Address) -> H256 {
|
||||
self.ensure_cached(a, RequireCache::None,
|
||||
|a| a.as_ref().map_or(SHA3_EMPTY, |a| a.code_hash()))
|
||||
}
|
||||
|
||||
/// Get accounts' code size.
|
||||
@ -640,6 +645,7 @@ impl Clone for State {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::str::FromStr;
|
||||
use rustc_serialize::hex::FromHex;
|
||||
use super::*;
|
||||
@ -1504,14 +1510,14 @@ fn code_from_database() {
|
||||
let mut state = get_temp_state_in(temp.as_path());
|
||||
state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{});
|
||||
state.init_code(&a, vec![1, 2, 3]);
|
||||
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
|
||||
assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
|
||||
state.commit().unwrap();
|
||||
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
|
||||
assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
|
||||
state.drop()
|
||||
};
|
||||
|
||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
|
||||
assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -57,7 +57,7 @@ fn should_return_registrar() {
|
||||
IoChannel::disconnected(),
|
||||
&db_config
|
||||
).unwrap();
|
||||
assert_eq!(client.additional_params().get("registrar"), Some(&"8e4e9b13d4b45cb0befc93c3061b1408f67316b2".to_owned()));
|
||||
assert_eq!(client.additional_params().get("registrar"), Some(&"52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d".to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -181,7 +181,7 @@ impl From<ActionParams> for Create {
|
||||
from: p.sender,
|
||||
value: p.value.value(),
|
||||
gas: p.gas,
|
||||
init: p.code.unwrap_or_else(Vec::new),
|
||||
init: p.code.map_or_else(Vec::new, |c| (*c).clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,6 +164,7 @@ pub mod headers {
|
||||
}
|
||||
|
||||
/// A mode for verifying headers.
|
||||
#[allow(dead_code)]
|
||||
pub struct Headers;
|
||||
|
||||
impl Kind for Headers {
|
||||
@ -179,4 +180,4 @@ pub mod headers {
|
||||
engine.verify_block_unordered(&unverified, None).map(|_| unverified)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ impl MinerService for TestMinerService {
|
||||
}
|
||||
|
||||
fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
|
||||
self.latest_closed_block.lock().as_ref().map_or(None, |b| b.block().fields().state.code(address).clone())
|
||||
self.latest_closed_block.lock().as_ref().map_or(None, |b| b.block().fields().state.code(address).map(|c| (*c).clone()))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use target_info::Target;
|
||||
include!(concat!(env!("OUT_DIR"), "/version.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
|
||||
|
||||
#[derive(PartialEq,Eq,Clone,Copy)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
/// Boolean type for clean/dirty status.
|
||||
pub enum Filth {
|
||||
/// Data has not been changed.
|
||||
|
@ -46,4 +46,4 @@ pub use rustc_serialize::hex::{FromHex, FromHexError};
|
||||
pub use heapsize::HeapSizeOf;
|
||||
pub use itertools::Itertools;
|
||||
|
||||
pub use parking_lot::{Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
pub use parking_lot::{Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
Loading…
Reference in New Issue
Block a user