Merge branch 'master' into issues/4673

This commit is contained in:
Joseph Mark 2017-07-13 19:30:52 +07:00
commit 9c3bd83d3b
No known key found for this signature in database
GPG Key ID: 9BA8D1EE2E53C283
112 changed files with 1036 additions and 866 deletions

36
Cargo.lock generated
View File

@ -253,6 +253,16 @@ dependencies = [
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "common-types"
version = "0.1.0"
dependencies = [
"ethcore-util 1.7.0",
"ethjson 0.1.0",
"rlp 0.2.0",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "conv"
version = "0.3.3"
@ -436,6 +446,7 @@ dependencies = [
"bn 0.4.4 (git+https://github.com/paritytech/bn)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"common-types 0.1.0",
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -452,7 +463,7 @@ dependencies = [
"ethjson 0.1.0",
"ethkey 0.2.0",
"ethstore 0.1.0",
"evmjit 1.7.0",
"evm 0.1.0",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"hardware-wallet 1.7.0",
"hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)",
@ -464,7 +475,6 @@ dependencies = [
"native-contracts 0.1.0",
"num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.2.0",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -474,7 +484,6 @@ dependencies = [
"stats 0.1.0",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
]
[[package]]
@ -585,6 +594,7 @@ dependencies = [
"ethcore-ipc-codegen 1.7.0",
"ethcore-network 1.7.0",
"ethcore-util 1.7.0",
"evm 0.1.0",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@ -839,6 +849,24 @@ dependencies = [
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "evm"
version = "0.1.0"
dependencies = [
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"common-types 0.1.0",
"ethcore-util 1.7.0",
"ethjson 0.1.0",
"evmjit 1.7.0",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.2.0",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
]
[[package]]
name = "evmbin"
version = "0.1.0"
@ -846,6 +874,7 @@ dependencies = [
"docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.7.0",
"ethcore-util 1.7.0",
"evm 0.1.0",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1850,6 +1879,7 @@ dependencies = [
"ethkey 0.2.0",
"ethstore 0.1.0",
"ethsync 1.7.0",
"evm 0.1.0",
"fetch 0.1.0",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -16,6 +16,7 @@ bloomchain = "0.1"
bn = { git = "https://github.com/paritytech/bn" }
byteorder = "1.0"
clippy = { version = "0.0.103", optional = true}
common-types = { path = "types" }
crossbeam = "0.2.9"
env_logger = "0.4"
ethabi = "2.0"
@ -31,7 +32,7 @@ ethcore-util = { path = "../util" }
ethjson = { path = "../json" }
ethkey = { path = "../ethkey" }
ethstore = { path = "../ethstore" }
evmjit = { path = "../evmjit", optional = true }
evm = { path = "evm" }
futures = "0.1"
hardware-wallet = { path = "../hw" }
hyper = { git = "https://github.com/paritytech/hyper", default-features = false }
@ -52,14 +53,12 @@ semver = "0.6"
stats = { path = "../util/stats" }
time = "0.1"
transient-hashmap = "0.4"
parity-wasm = "0.12"
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
[dev-dependencies]
native-contracts = { path = "native_contracts", features = ["test_contracts"] }
[features]
jit = ["evmjit"]
jit = ["evm/jit"]
evm-debug = ["slow-blocks"]
evm-debug-tests = ["evm-debug"]
slow-blocks = [] # Use SLOW_TX_DURATION="50" (compile time!) to track transactions over 50ms

View File

@ -17,7 +17,6 @@
extern crate ethcore_ipc_codegen;
fn main() {
ethcore_ipc_codegen::derive_binary("src/types/mod.rs.in").unwrap();
ethcore_ipc_codegen::derive_ipc_cond("src/client/traits.rs", cfg!(feature="ipc")).unwrap();
ethcore_ipc_codegen::derive_ipc_cond("src/snapshot/snapshot_service_trait.rs", cfg!(feature="ipc")).unwrap();
ethcore_ipc_codegen::derive_ipc_cond("src/client/chain_notify.rs", cfg!(feature="ipc")).unwrap();

23
ethcore/evm/Cargo.toml Normal file
View File

@ -0,0 +1,23 @@
[package]
name = "evm"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
bit-set = "0.4"
byteorder = "1.0"
common-types = { path = "../types" }
ethcore-util = { path = "../../util" }
evmjit = { path = "../../evmjit", optional = true }
ethjson = { path = "../../json" }
lazy_static = "0.2"
log = "0.3"
rlp = { path = "../../util/rlp" }
parity-wasm = "0.12"
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
[dev-dependencies]
rustc-hex = "1.0"
[features]
jit = ["evmjit"]

View File

@ -19,7 +19,8 @@ use util::{Address, Bytes, U256};
use util::hash::{H256};
use util::sha3::{Hashable, SHA3_EMPTY};
use ethjson;
use types::executed::CallType;
use {CallType};
use std::sync::Arc;

View File

@ -25,7 +25,7 @@ extern crate test;
use self::test::{Bencher, black_box};
use util::*;
use action_params::ActionParams;
use evm::action_params::ActionParams;
use evm::{self, Factory, VMType};
use evm::tests::FakeExt;

View File

@ -0,0 +1,70 @@
//! EVM call types.
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
/// The type of the call-like instruction.
#[derive(Debug, PartialEq, Clone)]
pub enum CallType {
/// Not a CALL.
None,
/// CALL.
Call,
/// CALLCODE.
CallCode,
/// DELEGATECALL.
DelegateCall,
/// STATICCALL
StaticCall,
}
impl Encodable for CallType {
fn rlp_append(&self, s: &mut RlpStream) {
let v = match *self {
CallType::None => 0u32,
CallType::Call => 1,
CallType::CallCode => 2,
CallType::DelegateCall => 3,
CallType::StaticCall => 4,
};
Encodable::rlp_append(&v, s);
}
}
impl Decodable for CallType {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
rlp.as_val().and_then(|v| Ok(match v {
0u32 => CallType::None,
1 => CallType::Call,
2 => CallType::CallCode,
3 => CallType::DelegateCall,
4 => CallType::StaticCall,
_ => return Err(DecoderError::Custom("Invalid value of CallType item")),
}))
}
}
#[cfg(test)]
mod tests {
use rlp::*;
use super::CallType;
#[test]
fn encode_call_type() {
let ct = CallType::Call;
let mut s = RlpStream::new_list(2);
s.append(&ct);
assert!(!s.is_finished(), "List shouldn't finished yet");
s.append(&ct);
assert!(s.is_finished(), "List should be finished now");
s.out();
}
#[test]
fn should_encode_and_decode_call_type() {
let original = CallType::Call;
let encoded = encode(&original);
let decoded = decode(&encoded);
assert_eq!(original, decoded);
}
}

View File

@ -19,7 +19,7 @@
use std::cmp;
use std::sync::Arc;
use util::{U256, Address, H256, Hashable};
use header::BlockNumber;
use types::BlockNumber;
use ethjson;
/// Simple vector of hashes, should be at most 256 items large, can be smaller if being used
@ -82,7 +82,7 @@ mod tests {
use ethjson;
#[test]
fn it_serializes_form_json() {
fn it_serializes_from_json() {
let env_info = EnvInfo::from(ethjson::vm::Env {
author: ethjson::hash::Address(Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()),
number: ethjson::uint::Uint(U256::from(1_112_339)),

View File

@ -19,8 +19,8 @@
use std::{ops, cmp, fmt};
use util::{U128, U256, U512, trie};
use action_params::ActionParams;
use evm::Ext;
use builtin;
use {Ext};
use super::wasm;
/// Evm errors.
@ -77,12 +77,6 @@ impl From<Box<trie::TrieError>> for Error {
}
}
impl From<builtin::Error> for Error {
fn from(err: builtin::Error) -> Self {
Error::BuiltIn(err.0)
}
}
impl From<wasm::RuntimeError> for Error {
fn from(err: wasm::RuntimeError) -> Self {
Error::Wasm(format!("Runtime error: {:?}", err))
@ -109,7 +103,6 @@ impl fmt::Display for Error {
/// A specialized version of Result over EVM errors.
pub type Result<T> = ::std::result::Result<T, Error>;
/// Return data buffer. Holds memory from a previous call and a slice into that memory.
#[derive(Debug)]
pub struct ReturnData {

View File

@ -17,9 +17,10 @@
//! Interface for Evm externalities.
use util::*;
use evm::{self, Schedule, ReturnData};
use env_info::*;
use types::executed::CallType;
use call_type::CallType;
use env_info::EnvInfo;
use schedule::Schedule;
use evm::{self, ReturnData};
/// Result of externalities create function.
pub enum ContractCreateResult {

View File

@ -16,10 +16,11 @@
use util::*;
use super::u256_to_address;
use evm::{self, CostType};
use evm::instructions::{self, Instruction, InstructionInfo};
use evm::interpreter::stack::Stack;
use evm::schedule::Schedule;
use {evm, ext};
use instructions::{self, Instruction, InstructionInfo};
use interpreter::stack::Stack;
use schedule::Schedule;
macro_rules! overflowing {
($x: expr) => {{
@ -30,26 +31,26 @@ macro_rules! overflowing {
}
#[cfg_attr(feature="dev", allow(enum_variant_names))]
enum Request<Cost: CostType> {
enum Request<Cost: ::evm::CostType> {
Gas(Cost),
GasMem(Cost, Cost),
GasMemProvide(Cost, Cost, Option<U256>),
GasMemCopy(Cost, Cost, Cost)
}
pub struct InstructionRequirements<Cost: CostType> {
pub struct InstructionRequirements<Cost> {
pub gas_cost: Cost,
pub provide_gas: Option<Cost>,
pub memory_total_gas: Cost,
pub memory_required_size: usize,
}
pub struct Gasometer<Gas: CostType> {
pub struct Gasometer<Gas> {
pub current_gas: Gas,
pub current_mem_gas: Gas,
}
impl<Gas: CostType> Gasometer<Gas> {
impl<Gas: evm::CostType> Gasometer<Gas> {
pub fn new(current_gas: Gas) -> Self {
Gasometer {
@ -106,7 +107,7 @@ impl<Gas: CostType> Gasometer<Gas> {
/// it will be the amount of gas that the current context provides to the child context.
pub fn requirements(
&mut self,
ext: &evm::Ext,
ext: &ext::Ext,
instruction: Instruction,
info: &InstructionInfo,
stack: &Stack<U256>,
@ -290,7 +291,7 @@ impl<Gas: CostType> Gasometer<Gas> {
})
}
fn mem_gas_cost(&self, schedule: &evm::Schedule, current_mem_size: usize, mem_size: &Gas) -> evm::Result<(Gas, Gas, usize)> {
fn mem_gas_cost(&self, schedule: &Schedule, current_mem_size: usize, mem_size: &Gas) -> evm::Result<(Gas, Gas, usize)> {
let gas_for_mem = |mem_size: Gas| {
let s = mem_size >> 5;
// s * memory_gas + s * s / quad_coeff_div
@ -318,12 +319,12 @@ impl<Gas: CostType> Gasometer<Gas> {
#[inline]
fn mem_needed_const<Gas: CostType>(mem: &U256, add: usize) -> evm::Result<Gas> {
fn mem_needed_const<Gas: evm::CostType>(mem: &U256, add: usize) -> evm::Result<Gas> {
Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add))))
}
#[inline]
fn mem_needed<Gas: CostType>(offset: &U256, size: &U256) -> evm::Result<Gas> {
fn mem_needed<Gas: evm::CostType>(offset: &U256, size: &U256) -> evm::Result<Gas> {
if size.is_zero() {
return Ok(Gas::from(0));
}
@ -332,7 +333,7 @@ fn mem_needed<Gas: CostType>(offset: &U256, size: &U256) -> evm::Result<Gas> {
}
#[inline]
fn add_gas_usize<Gas: CostType>(value: Gas, num: usize) -> (Gas, bool) {
fn add_gas_usize<Gas: evm::CostType>(value: Gas, num: usize) -> (Gas, bool) {
value.overflow_add(Gas::from(num))
}
@ -340,7 +341,7 @@ fn add_gas_usize<Gas: CostType>(value: Gas, num: usize) -> (Gas, bool) {
fn test_mem_gas_cost() {
// given
let gasometer = Gasometer::<U256>::new(U256::zero());
let schedule = evm::Schedule::default();
let schedule = Schedule::default();
let current_mem_size = 5;
let mem_size = !U256::zero();
@ -357,7 +358,7 @@ fn test_mem_gas_cost() {
fn test_calculate_mem_cost() {
// given
let gasometer = Gasometer::<usize>::new(0);
let schedule = evm::Schedule::default();
let schedule = Schedule::default();
let current_mem_size = 0;
let mem_size = 5;

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::U256;
use evm::ReturnData;
use {ReturnData};
const MAX_RETURN_WASTE_BYTES: usize = 16384;

View File

@ -30,9 +30,10 @@ pub use self::shared_cache::SharedCache;
use std::marker::PhantomData;
use action_params::{ActionParams, ActionValue};
use types::executed::CallType;
use evm::instructions::{self, Instruction, InstructionInfo};
use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType, CreateContractAddress, ReturnData};
use call_type::CallType;
use instructions::{self, Instruction, InstructionInfo};
use evm::{self, GasLeft, CostType, ReturnData};
use ext::{self, MessageCallResult, ContractCreateResult, CreateContractAddress};
use bit_set::BitSet;
use util::*;
@ -107,7 +108,7 @@ pub struct Interpreter<Cost: CostType> {
}
impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result<GasLeft> {
fn exec(&mut self, params: ActionParams, ext: &mut ext::Ext) -> evm::Result<GasLeft> {
self.mem.clear();
let mut informant = informant::EvmInformant::new(ext.depth());
@ -204,7 +205,7 @@ impl<Cost: CostType> Interpreter<Cost> {
}
}
fn verify_instruction(&self, ext: &evm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack<U256>) -> evm::Result<()> {
fn verify_instruction(&self, ext: &ext::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack<U256>) -> evm::Result<()> {
let schedule = ext.schedule();
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
@ -270,7 +271,7 @@ impl<Cost: CostType> Interpreter<Cost> {
&mut self,
gas: Cost,
params: &ActionParams,
ext: &mut evm::Ext,
ext: &mut ext::Ext,
instruction: Instruction,
code: &mut CodeReader,
stack: &mut Stack<U256>,

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
use evm::instructions;
use instructions;
/// Stack trait with VM-friendly API
pub trait Stack<T> {

View File

@ -18,7 +18,7 @@
use util::*;
use evmjit;
use evm::{self, GasLeft};
use types::executed::CallType;
use evm::CallType;
/// Should be used to convert jit types to ethcore
trait FromJit<T>: Sized {

View File

@ -16,16 +16,41 @@
//! Ethereum virtual machine.
extern crate byteorder;
extern crate bit_set;
extern crate common_types as types;
extern crate ethcore_util as util;
extern crate ethjson;
extern crate rlp;
extern crate parity_wasm;
extern crate wasm_utils;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[cfg(feature = "jit")]
extern crate evmjit;
#[cfg(test)]
extern crate rustc_hex;
pub mod action_params;
pub mod call_type;
pub mod env_info;
pub mod ext;
pub mod evm;
pub mod interpreter;
#[macro_use]
pub mod factory;
pub mod schedule;
pub mod wasm;
#[macro_use]
pub mod factory;
mod vmtype;
mod instructions;
#[cfg(feature = "jit" )]
mod jit;
@ -34,10 +59,12 @@ mod tests;
#[cfg(all(feature="benches", test))]
mod benches;
pub use self::action_params::ActionParams;
pub use self::call_type::CallType;
pub use self::env_info::EnvInfo;
pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType, ReturnData};
pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
pub use self::instructions::{InstructionInfo, INSTRUCTIONS, push_bytes};
pub use self::vmtype::VMType;
pub use self::factory::Factory;
pub use self::schedule::{Schedule, CleanDustMode};
pub use types::executed::CallType;

View File

@ -15,7 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Cost schedule and other parameterisations for the EVM.
use spec::CommonParams;
/// Definition of the cost schedule and other parameterisations for the EVM.
pub struct Schedule {
@ -185,26 +184,6 @@ impl Schedule {
}
}
/// Schedule for the post-EIP-150-era of the Ethereum main net.
pub fn from_params(block_number: u64, params: &CommonParams) -> Schedule {
let mut schedule = Schedule::new_post_eip150(usize::max_value(), true, true, true);
schedule.apply_params(block_number, params);
schedule
}
/// Apply common spec config parameters to the schedule.
pub fn apply_params(&mut self, block_number: u64, params: &CommonParams) {
self.have_create2 = block_number >= params.eip86_transition;
self.have_revert = block_number >= params.eip140_transition;
self.have_static_call = block_number >= params.eip214_transition;
if block_number >= params.eip210_transition {
self.blockhash_gas = 350;
}
if block_number >= params.dust_protection_transition {
self.kill_dust = if params.remove_dust_contracts { CleanDustMode::WithCodeAndStorage } else { CleanDustMode::BasicOnly };
}
}
/// Schedule for the Metropolis of the Ethereum main net.
pub fn new_metropolis() -> Schedule {
let mut schedule = Self::new_post_eip150(24576, true, true, true);

View File

@ -19,13 +19,12 @@ use rustc_hex::FromHex;
use util::*;
use action_params::{ActionParams, ActionValue};
use env_info::EnvInfo;
use types::executed::CallType;
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData};
use tests::helpers::*;
use types::transaction::SYSTEM_ADDRESS;
use executive::Executive;
use state::Substate;
use trace::{NoopVMTracer, NoopTracer};
use call_type::CallType;
use schedule::Schedule;
use evm::{self, GasLeft, ReturnData};
use ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
use factory::Factory;
use vmtype::VMType;
pub struct FakeLogEntry {
topics: Vec<H256>,
@ -438,67 +437,6 @@ fn test_blockhash(factory: super::Factory) {
assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash);
}
evm_test!{test_blockhash_eip210: test_blockhash_eip210_jit, test_blockhash_eip210_int}
fn test_blockhash_eip210(factory: super::Factory) {
let get_prev_hash_code = Arc::new("600143034060205260206020f3".from_hex().unwrap()); // this returns previous block hash
let get_prev_hash_code_hash = get_prev_hash_code.sha3();
// This is same as DEFAULT_BLOCKHASH_CONTRACT except for metropolis transition block check removed.
let test_blockhash_contract = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b61014a565b4360003512151561009057600060405260206040f35b610100600035430312156100b357610100600035075460605260206060f3610149565b62010000600035430312156100d157600061010060003507146100d4565b60005b156100f6576101006101006000350507610100015460805260206080f3610148565b630100000060003543031215610116576000620100006000350714610119565b60005b1561013c57610100620100006000350507610200015460a052602060a0f3610147565b600060c052602060c0f35b5b5b5b5b";
let blockhash_contract_code = Arc::new(test_blockhash_contract.from_hex().unwrap());
let blockhash_contract_code_hash = blockhash_contract_code.sha3();
let engine = TestEngine::new_metropolis();
let mut env_info = EnvInfo::default();
// populate state with 256 last hashes
let mut state = get_temp_state_with_factory(factory);
let contract_address: Address = 0xf0.into();
state.init_code(&contract_address, (*blockhash_contract_code).clone()).unwrap();
for i in 1 .. 257 {
env_info.number = i.into();
let params = ActionParams {
code_address: contract_address.clone(),
address: contract_address,
sender: SYSTEM_ADDRESS.clone(),
origin: SYSTEM_ADDRESS.clone(),
gas: 100000.into(),
gas_price: 0.into(),
value: ActionValue::Transfer(0.into()),
code: Some(blockhash_contract_code.clone()),
code_hash: Some(blockhash_contract_code_hash),
data: Some(H256::from(i - 1).to_vec()),
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, &engine);
let mut substate = Substate::new();
let mut output = [];
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
panic!("Encountered error on updating last hashes: {}", e);
}
}
env_info.number = 256;
let params = ActionParams {
code_address: Address::new(),
address: Address::new(),
sender: Address::new(),
origin: Address::new(),
gas: 100000.into(),
gas_price: 0.into(),
value: ActionValue::Transfer(0.into()),
code: Some(get_prev_hash_code),
code_hash: Some(get_prev_hash_code_hash),
data: None,
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, &engine);
let mut substate = Substate::new();
let mut output = H256::new();
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
panic!("Encountered error on getting last hash: {}", e);
}
assert_eq!(output, 255.into());
}
evm_test!{test_calldataload: test_calldataload_jit, test_calldataload_int}
fn test_calldataload(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();

View File

@ -58,7 +58,7 @@ impl WasmInterpreter {
impl evm::Evm for WasmInterpreter {
fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result<GasLeft> {
fn exec(&mut self, params: ActionParams, ext: &mut ::ext::Ext) -> evm::Result<GasLeft> {
use parity_wasm::elements::Deserialize;
let code = params.code.expect("exec is only called on contract with code; qed");

View File

@ -20,7 +20,7 @@ use std::sync::Arc;
use byteorder::{LittleEndian, ByteOrder};
use evm;
use ext;
use parity_wasm::interpreter;
use util::{Address, H256, U256};
@ -62,14 +62,14 @@ pub struct Runtime<'a> {
gas_counter: u64,
gas_limit: u64,
dynamic_top: u32,
ext: &'a mut evm::Ext,
ext: &'a mut ext::Ext,
memory: Arc<interpreter::MemoryInstance>,
}
impl<'a> Runtime<'a> {
/// New runtime for wasm contract with specified params
pub fn with_params<'b>(
ext: &'b mut evm::Ext,
ext: &'b mut ext::Ext,
memory: Arc<interpreter::MemoryInstance>,
stack_space: u32,
gas_limit: u64,
@ -153,14 +153,14 @@ impl<'a> Runtime<'a> {
.map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?
.into();
match self.ext.create(&gas_left, &endowment, &code, evm::CreateContractAddress::FromSenderAndCodeHash) {
evm::ContractCreateResult::Created(address, gas_left) => {
match self.ext.create(&gas_left, &endowment, &code, ext::CreateContractAddress::FromSenderAndCodeHash) {
ext::ContractCreateResult::Created(address, gas_left) => {
self.memory.set(result_ptr, &*address)?;
self.gas_counter = self.gas_limit - gas_left.low_u64();
trace!(target: "wasm", "runtime: create contract success (@{:?})", address);
Ok(Some(0i32.into()))
},
evm::ContractCreateResult::Failed => {
ext::ContractCreateResult::Failed => {
trace!(target: "wasm", "runtime: create contract fail");
Ok(Some((-1i32).into()))
}

View File

@ -1,22 +1,31 @@
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
// Copyright 2015-2017 Parity Technologies (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 ethcore_logger::init_log;
use super::super::tests::{FakeExt, FakeCall, FakeCallType};
use super::WasmInterpreter;
use evm::{self, Evm, GasLeft};
use action_params::{ActionParams, ActionValue};
use util::{U256, H256, Address};
fn load_sample(name: &str) -> Vec<u8> {
let mut path = PathBuf::from("./res/wasm-tests/compiled");
path.push(name);
let mut file = File::open(path).expect(&format!("File {} for test to exist", name));
let mut data = vec![];
file.read_to_end(&mut data).expect(&format!("Test {} to load ok", name));
data
macro_rules! load_sample {
($name: expr) => {
include_bytes!(concat!("../../../res/wasm-tests/compiled/", $name)).to_vec()
}
}
fn test_finalize(res: Result<GasLeft, evm::Error>) -> Result<U256, evm::Error> {
@ -34,9 +43,7 @@ fn wasm_interpreter() -> WasmInterpreter {
/// Empty contract does almost nothing except producing 1 (one) local node debug log message
#[test]
fn empty() {
init_log();
let code = load_sample("empty.wasm");
let code = load_sample!("empty.wasm");
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
let mut params = ActionParams::default();
@ -58,9 +65,7 @@ fn empty() {
// logger.wasm writes all these provided fixed header fields to some arbitrary storage keys.
#[test]
fn logger() {
init_log();
let code = load_sample("logger.wasm");
let code = load_sample!("logger.wasm");
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
let sender: Address = "0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d".parse().unwrap();
let origin: Address = "0102030405060708090a0b0c0d0e0f1011121314".parse().unwrap();
@ -113,9 +118,7 @@ fn logger() {
// if it has any result.
#[test]
fn identity() {
init_log();
let code = load_sample("identity.wasm");
let code = load_sample!("identity.wasm");
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
let mut params = ActionParams::default();
@ -148,9 +151,7 @@ fn identity() {
// This also tests byte-perfect memory allocation and in/out ptr lifecycle.
#[test]
fn dispersion() {
init_log();
let code = load_sample("dispersion.wasm");
let code = load_sample!("dispersion.wasm");
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
@ -179,9 +180,7 @@ fn dispersion() {
#[test]
fn suicide_not() {
init_log();
let code = load_sample("suicidal.wasm");
let code = load_sample!("suicidal.wasm");
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
@ -210,9 +209,7 @@ fn suicide_not() {
#[test]
fn suicide() {
init_log();
let code = load_sample("suicidal.wasm");
let code = load_sample!("suicidal.wasm");
let refund: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
let mut params = ActionParams::default();
@ -242,11 +239,9 @@ fn suicide() {
#[test]
fn create() {
init_log();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(load_sample("creator.wasm")));
params.code = Some(Arc::new(load_sample!("creator.wasm")));
params.data = Some(vec![0u8, 2, 4, 8, 16, 32, 64, 128]);
params.value = ActionValue::transfer(1_000_000_000);

View File

@ -18,6 +18,7 @@ ethcore-network = { path = "../../util/network" }
ethcore-io = { path = "../../util/io" }
ethcore-ipc = { path = "../../ipc/rpc", optional = true }
ethcore-devtools = { path = "../../devtools" }
evm = { path = "../evm" }
rlp = { path = "../../util/rlp" }
time = "0.1"
smallvec = "0.4"

View File

@ -18,10 +18,10 @@
use std::sync::{Weak, Arc};
use ethcore::block_import_error::BlockImportError;
use ethcore::block_status::BlockStatus;
use ethcore::client::{ClientReport, EnvInfo};
use ethcore::engines::Engine;
use ethcore::error::BlockImportError;
use ethcore::ids::BlockId;
use ethcore::header::Header;
use ethcore::verification::queue::{self, HeaderQueue};

View File

@ -71,6 +71,7 @@ extern crate ethcore_io as io;
extern crate ethcore_network as network;
extern crate ethcore_util as util;
extern crate ethcore;
extern crate evm;
extern crate futures;
extern crate itertools;
extern crate rand;

View File

@ -21,10 +21,10 @@ use std::sync::Arc;
use ethcore::basic_account::BasicAccount;
use ethcore::encoded;
use ethcore::engines::Engine;
use ethcore::env_info::EnvInfo;
use ethcore::receipt::Receipt;
use ethcore::state::{self, ProvedExecution};
use ethcore::transaction::SignedTransaction;
use evm::env_info::EnvInfo;
use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field};

View File

@ -26,9 +26,8 @@
use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map::Entry;
use ethcore::error::TransactionError;
use ethcore::error::{TransactionError, TransactionImportResult};
use ethcore::transaction::{Condition, PendingTransaction, SignedTransaction};
use ethcore::transaction_import::TransactionImportResult;
use util::{Address, U256, H256, H256FastMap};
// Knowledge of an account's current nonce.

View File

@ -16,13 +16,11 @@
//! Ethcore basic typenames.
use util::hash::H2048;
/// Type for a 2048-bit log-bloom, as used by our blocks.
pub type LogBloom = H2048;
pub type LogBloom = ::log_entry::LogBloom;
/// Constant 2048-bit datum for 0. Often used as a default.
pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]);
pub static ZERO_LOGBLOOM: LogBloom = ::util::hash::H2048([0x00; 256]);
#[cfg_attr(feature="dev", allow(enum_variant_names))]
/// Semantic boolean for when a seal/signature is included.

View File

@ -25,7 +25,7 @@ use util::{Bytes, Address, Hashable, U256, H256, ordered_trie_root, SHA3_NULL_RL
use util::error::{Mismatch, OutOfBounds};
use basic_types::{LogBloom, Seal};
use env_info::{EnvInfo, LastHashes};
use evm::env_info::{EnvInfo, LastHashes};
use engines::Engine;
use error::{Error, BlockError, TransactionError};
use factory::Factories;
@ -200,7 +200,7 @@ pub trait IsBlock {
/// Trait for a object that has a state database.
pub trait Drain {
/// Drop this object and return the underlieing database.
/// Drop this object and return the underlying database.
fn drain(self) -> StateDB;
}
@ -370,6 +370,22 @@ impl<'x> OpenBlock<'x> {
}
}
/// Push transactions onto the block.
pub fn push_transactions(&mut self, transactions: &[SignedTransaction]) -> Result<(), Error> {
push_transactions(self, transactions)
}
/// Populate self from a header.
pub fn populate_from(&mut self, header: &Header) {
self.set_difficulty(*header.difficulty());
self.set_gas_limit(*header.gas_limit());
self.set_timestamp(header.timestamp());
self.set_author(header.author().clone());
self.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
self.set_uncles_hash(header.uncles_hash().clone());
self.set_transactions_root(header.transactions_root().clone());
}
/// Turn this into a `ClosedBlock`.
pub fn close(self) -> ClosedBlock {
let mut s = self;
@ -579,18 +595,13 @@ pub fn enact(
is_epoch_begin,
)?;
b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
b.set_author(header.author().clone());
b.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
b.set_uncles_hash(header.uncles_hash().clone());
b.set_transactions_root(header.transactions_root().clone());
b.populate_from(header);
b.push_transactions(transactions)?;
push_transactions(&mut b, transactions)?;
for u in uncles {
b.push_uncle(u.clone())?;
}
Ok(b.close_and_lock())
}
@ -656,7 +667,7 @@ mod tests {
use tests::helpers::*;
use super::*;
use engines::Engine;
use env_info::LastHashes;
use evm::env_info::LastHashes;
use error::Error;
use header::Header;
use factory::Factories;
@ -681,7 +692,36 @@ mod tests {
let header = block.header();
let transactions: Result<Vec<_>, Error> = block.transactions().into_iter().map(SignedTransaction::new).collect();
let transactions = transactions?;
enact(&header, &transactions, &block.uncles(), engine, tracing, db, parent, last_hashes, factories, false)
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(parent.number() + 1), factories.clone())?;
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n",
header.number(), s.root(), header.author(), s.balance(&header.author())?);
}
}
let mut b = OpenBlock::new(
engine,
factories,
tracing,
db,
parent,
last_hashes,
Address::new(),
(3141562.into(), 31415620.into()),
vec![],
false,
)?;
b.populate_from(&header);
b.push_transactions(&transactions)?;
for u in &block.uncles() {
b.push_uncle(u.clone())?;
}
Ok(b.close_and_lock())
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards

View File

@ -36,6 +36,12 @@ impl From<&'static str> for Error {
}
}
impl Into<::evm::Error> for Error {
fn into(self) -> ::evm::Error {
::evm::Error::BuiltIn(self.0)
}
}
/// Native implementation of a built-in contract.
pub trait Impl: Send + Sync {
/// execute this built-in on the given input, writing to the given output.

View File

@ -17,7 +17,6 @@
use std::collections::{HashSet, HashMap, BTreeMap, VecDeque};
use std::str::FromStr;
use std::sync::{Arc, Weak};
use std::fmt;
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant};
use time::precise_time_ns;
@ -43,8 +42,8 @@ use client::{
};
use encoded;
use engines::{Engine, EpochTransition};
use env_info::EnvInfo;
use env_info::LastHashes;
use evm::env_info::EnvInfo;
use evm::env_info::LastHashes;
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
use evm::{Factory as EvmFactory, Schedule};
use executive::{Executive, Executed, TransactOptions, contract_address};
@ -84,12 +83,6 @@ const MAX_TX_QUEUE_SIZE: usize = 4096;
const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2;
const MIN_HISTORY_SIZE: u64 = 8;
impl fmt::Display for BlockChainInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "#{}.{}", self.best_block_number, self.best_block_hash)
}
}
/// Report on the status of a client.
#[derive(Default, Clone, Debug, Eq, PartialEq)]
pub struct ClientReport {
@ -537,7 +530,7 @@ impl Client {
} else {
imported_blocks.push(header.hash());
let route = self.commit_block(closed_block, &header.hash(), &block.bytes);
let route = self.commit_block(closed_block, &header, &block.bytes);
import_results.push(route);
self.report.write().accrue_block(&block);
@ -642,10 +635,14 @@ impl Client {
Ok(hash)
}
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &[u8]) -> ImportRoute where B: IsBlock + Drain {
let number = block.header().number();
let parent = block.header().parent_hash().clone();
let header = block.header().clone(); // TODO: optimize and avoid copy.
// NOTE: the header of the block passed here is not necessarily sealed, as
// it is for reconstructing the state transition.
//
// The header passed is from the original block data and is sealed.
fn commit_block<B>(&self, block: B, header: &Header, block_data: &[u8]) -> ImportRoute where B: IsBlock + Drain {
let hash = &header.hash();
let number = header.number();
let parent = header.parent_hash();
let chain = self.chain.read();
// Commit results
@ -655,6 +652,8 @@ impl Client {
.map(Into::into)
.collect();
assert_eq!(header.hash(), BlockView::new(block_data).header_view().sha3());
//let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new));
let mut batch = DBTransaction::new();
@ -664,6 +663,17 @@ impl Client {
// TODO: Prove it with a test.
let mut state = block.drain();
// check epoch end signal, potentially generating a proof on the current
// state.
self.check_epoch_end_signal(
&header,
block_data,
&receipts,
&state,
&chain,
&mut batch,
);
state.journal_under(&mut batch, number, hash).expect("DB commit failed");
let route = chain.insert_block(&mut batch, block_data, receipts.clone());
@ -681,10 +691,6 @@ impl Client {
self.db.read().write_buffered(batch);
chain.commit();
// check for epoch end. do this after writing first batch so we can prove
// transactions on the block's state.
// TODO: work these changes into the existing DBTransaction.
self.check_epoch_end_signal(&header, block_data, &receipts, &chain);
self.check_epoch_end(&header, &chain);
self.update_last_hashes(&parent, hash);
@ -698,38 +704,82 @@ impl Client {
// check for epoch end signal and write pending transition if it occurs.
// state for the given block must be available.
fn check_epoch_end_signal(&self, header: &Header, block: &[u8], receipts: &[Receipt], chain: &BlockChain) {
fn check_epoch_end_signal(
&self,
header: &Header,
block_bytes: &[u8],
receipts: &[Receipt],
state_db: &StateDB,
chain: &BlockChain,
batch: &mut DBTransaction,
) {
use engines::EpochChange;
let hash = header.hash();
match self.engine.signals_epoch_end(header, Some(block), Some(&receipts)) {
match self.engine.signals_epoch_end(header, Some(block_bytes), Some(&receipts)) {
EpochChange::Yes(proof) => {
use engines::epoch::PendingTransition;
use engines::Proof;
let proof = match proof {
Proof::Known(proof) => proof,
Proof::WithState(with_state) =>
match self.with_proving_caller(BlockId::Hash(hash), move |c| with_state(c)) {
Proof::WithState(with_state) => {
let env_info = EnvInfo {
number: header.number(),
author: header.author().clone(),
timestamp: header.timestamp(),
difficulty: header.difficulty().clone(),
last_hashes: self.build_last_hashes(header.parent_hash().clone()),
gas_used: U256::default(),
gas_limit: u64::max_value().into(),
};
let call = move |addr, data| {
let mut state_db = state_db.boxed_clone();
let backend = ::state::backend::Proving::new(state_db.as_hashdb_mut());
let transaction =
self.contract_call_tx(BlockId::Hash(*header.parent_hash()), addr, data);
let mut state = State::from_existing(
backend,
header.state_root().clone(),
self.engine.account_start_nonce(header.number()),
self.factories.clone(),
).expect("state known to be available for just-imported block; qed");
let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false };
let res = Executive::new(&mut state, &env_info, &*self.engine)
.transact(&transaction, options);
let res = match res {
Err(ExecutionError::Internal(e)) =>
Err(format!("Internal error: {}", e)),
Err(e) => {
trace!(target: "client", "Proved call failed: {}", e);
Ok((Vec::new(), state.drop().1.extract_proof()))
}
Ok(res) => Ok((res.output, state.drop().1.extract_proof())),
};
res.map(|(output, proof)| (output, proof.into_iter().map(|x| x.into_vec()).collect()))
};
match (with_state)(&call) {
Ok(proof) => proof,
Err(e) => {
warn!(target: "client", "Failed to generate transition proof for block {}: {}", hash, e);
warn!(target: "client", "Snapshots produced by this client may be incomplete");
Vec::new()
}
},
}
}
};
debug!(target: "client", "Block {} signals epoch end.", hash);
// write pending transition to DB.
let mut batch = DBTransaction::new();
let pending = PendingTransition { proof: proof };
chain.insert_pending_transition(&mut batch, hash, pending);
self.db.read().write_buffered(batch);
chain.insert_pending_transition(batch, hash, pending);
},
EpochChange::No => {},
EpochChange::Unsure(_) => {
@ -756,7 +806,11 @@ impl Client {
block_number: header.number(),
proof: proof,
});
self.db.read().write_buffered(batch);
// always write the batch directly since epoch transition proofs are
// fetched from a DB iterator and DB iterators are only available on
// flushed data.
self.db.read().write(batch).expect("DB flush failed");
}
}
@ -1773,7 +1827,9 @@ impl MiningBlockChainClient for Client {
let number = block.header().number();
let block_data = block.rlp_bytes();
let route = self.commit_block(block, &h, &block_data);
let header = block.header().clone();
let route = self.commit_block(block, &header, &block_data);
trace!(target: "client", "Imported sealed block #{} ({})", number, h);
self.state_db.lock().sync_cache(&route.enacted, &route.retracted, false);
route

View File

@ -17,14 +17,16 @@
use std::str::FromStr;
use std::path::Path;
use std::fmt::{Display, Formatter, Error as FmtError};
use mode::Mode as IpcMode;
use verification::{VerifierType, QueueConfig};
use util::{journaldb, CompactionProfile};
pub use std::time::Duration;
pub use blockchain::Config as BlockChainConfig;
pub use trace::Config as TraceConfig;
pub use evm::VMType;
use verification::{VerifierType, QueueConfig};
use util::{journaldb, CompactionProfile};
/// Client state db compaction profile
#[derive(Debug, PartialEq, Clone)]
pub enum DatabaseCompactionProfile {
@ -98,6 +100,29 @@ impl Display for Mode {
}
}
impl Into<IpcMode> for Mode {
fn into(self) -> IpcMode {
match self {
Mode::Off => IpcMode::Off,
Mode::Dark(timeout) => IpcMode::Dark(timeout.as_secs()),
Mode::Passive(timeout, alarm) => IpcMode::Passive(timeout.as_secs(), alarm.as_secs()),
Mode::Active => IpcMode::Active,
}
}
}
impl From<IpcMode> for Mode {
fn from(mode: IpcMode) -> Self {
match mode {
IpcMode::Off => Mode::Off,
IpcMode::Dark(timeout) => Mode::Dark(Duration::from_secs(timeout)),
IpcMode::Passive(timeout, alarm) => Mode::Passive(Duration::from_secs(timeout), Duration::from_secs(alarm)),
IpcMode::Active => Mode::Active,
}
}
}
/// Client configuration. Includes configs for all sub-systems.
#[derive(Debug, PartialEq, Default)]
pub struct ClientConfig {

View File

@ -23,7 +23,7 @@ use util::kvdb::{self, KeyValueDB};
use {state, state_db, client, executive, trace, db, spec};
use factory::Factories;
use evm::{self, VMType};
use action_params::ActionParams;
use evm::action_params::ActionParams;
/// EVM test Error.
#[derive(Debug)]

View File

@ -40,11 +40,9 @@ pub use types::pruning_info::PruningInfo;
pub use types::call_analytics::CallAnalytics;
pub use executive::{Executed, Executive, TransactOptions};
pub use env_info::{LastHashes, EnvInfo};
pub use evm::env_info::{LastHashes, EnvInfo};
pub use block_import_error::BlockImportError;
pub use transaction_import::TransactionImportResult;
pub use transaction_import::TransactionImportError;
pub use error::{BlockImportError, TransactionImportError, TransactionImportResult};
pub use verification::VerifierType;
/// IPC interfaces

View File

@ -15,24 +15,27 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::BTreeMap;
use util::{U256, Address, H256, H2048, Bytes, Itertools};
use util::hashdb::DBValue;
use blockchain::TreeRoute;
use verification::queue::QueueInfo as BlockQueueInfo;
use block::{OpenBlock, SealedBlock, ClosedBlock};
use header::{BlockNumber};
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction};
use transaction_import::TransactionImportResult;
use log_entry::LocalizedLogEntry;
use filter::Filter;
use blockchain::TreeRoute;
use encoded;
use evm::env_info::LastHashes;
use error::{ImportResult, CallError, Error as EthcoreError};
use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
use error::{TransactionImportResult, BlockImportError};
use evm::{Factory as EvmFactory, Schedule};
use executive::Executed;
use env_info::LastHashes;
use block_import_error::BlockImportError;
use filter::Filter;
use header::{BlockNumber};
use ipc::IpcConfig;
use log_entry::LocalizedLogEntry;
use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction};
use verification::queue::QueueInfo as BlockQueueInfo;
use util::{U256, Address, H256, H2048, Bytes, Itertools};
use util::hashdb::DBValue;
use types::ids::*;
use types::basic_account::BasicAccount;
use types::trace_filter::Filter as TraceFilter;
@ -41,7 +44,6 @@ use types::blockchain_info::BlockChainInfo;
use types::block_status::BlockStatus;
use types::mode::Mode;
use types::pruning_info::PruningInfo;
use encoded;
#[ipc(client_ident="RemoteClient")]
/// Blockchain database client. Owns and manages a blockchain and a block queue.

View File

@ -66,6 +66,7 @@ impl RollingFinality {
let entry = self.sign_count.entry(signer);
if let (true, &Entry::Vacant(_)) = (would_be_finalized, &entry) {
trace!(target: "finality", "Encountered already finalized block {}", hash);
break
}
@ -75,6 +76,7 @@ impl RollingFinality {
self.headers.push_front((hash, signer));
}
trace!(target: "finality", "Rolling finality state: {:?}", self.headers);
Ok(())
}
@ -128,6 +130,9 @@ impl RollingFinality {
}
}
trace!(target: "finality", "Blocks finalized by {:?}: {:?}", head, newly_finalized);
self.last_pushed = Some(head);
Ok(newly_finalized)
}
}

View File

@ -220,9 +220,9 @@ pub struct AuthorityRound {
builtins: BTreeMap<Address, Builtin>,
transition_service: IoService<()>,
step: Arc<Step>,
proposed: AtomicBool,
can_propose: AtomicBool,
client: RwLock<Option<Weak<EngineClient>>>,
signer: EngineSigner,
signer: RwLock<EngineSigner>,
validators: Box<ValidatorSet>,
validate_score_transition: u64,
eip155_transition: u64,
@ -311,7 +311,7 @@ fn verify_external<F: Fn(Report)>(header: &Header, validators: &ValidatorSet, st
// Give one step slack if step is lagging, double vote is still not possible.
if step.is_future(header_step) {
trace!(target: "engine", "verify_block_unordered: block from the future");
trace!(target: "engine", "verify_block_external: block from the future");
report(Report::Benign(*header.author(), header.number()));
Err(BlockError::InvalidSeal)?
} else {
@ -321,7 +321,7 @@ fn verify_external<F: Fn(Report)>(header: &Header, validators: &ValidatorSet, st
!verify_address(&correct_proposer, &proposer_signature, &header.bare_hash())?;
if is_invalid_proposer {
trace!(target: "engine", "verify_block_unordered: bad proposer for step: {}", header_step);
trace!(target: "engine", "verify_block_external: bad proposer for step: {}", header_step);
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
} else {
Ok(())
@ -372,7 +372,7 @@ impl AuthorityRound {
calibrate: our_params.start_step.is_none(),
duration: our_params.step_duration,
}),
proposed: AtomicBool::new(false),
can_propose: AtomicBool::new(true),
client: RwLock::new(None),
signer: Default::default(),
validators: our_params.validators,
@ -439,7 +439,7 @@ impl Engine for AuthorityRound {
fn step(&self) {
self.step.increment();
self.proposed.store(false, AtomicOrdering::SeqCst);
self.can_propose.store(true, AtomicOrdering::SeqCst);
if let Some(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() {
c.update_sealing();
@ -471,7 +471,7 @@ impl Engine for AuthorityRound {
}
fn seals_internally(&self) -> Option<bool> {
Some(self.signer.address() != Address::default())
Some(self.signer.read().is_some())
}
/// Attempt to seal the block internally.
@ -481,7 +481,7 @@ impl Engine for AuthorityRound {
fn generate_seal(&self, block: &ExecutedBlock) -> Seal {
// first check to avoid generating signature most of the time
// (but there's still a race to the `compare_and_swap`)
if self.proposed.load(AtomicOrdering::SeqCst) { return Seal::None; }
if !self.can_propose.load(AtomicOrdering::SeqCst) { return Seal::None; }
let header = block.header();
let step = self.step.load();
@ -512,11 +512,11 @@ impl Engine for AuthorityRound {
};
if is_step_proposer(validators, header.parent_hash(), step, header.author()) {
if let Ok(signature) = self.signer.sign(header.bare_hash()) {
if let Ok(signature) = self.sign(header.bare_hash()) {
trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step);
// only issue the seal if we were the first to reach the compare_and_swap.
if !self.proposed.compare_and_swap(false, true, AtomicOrdering::SeqCst) {
if self.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) {
return Seal::Regular(vec![encode(&step).into_vec(), encode(&(&H520::from(signature) as &[u8])).into_vec()]);
}
} else {
@ -532,7 +532,7 @@ impl Engine for AuthorityRound {
fn on_new_block(
&self,
block: &mut ExecutedBlock,
last_hashes: Arc<::env_info::LastHashes>,
last_hashes: Arc<::evm::env_info::LastHashes>,
epoch_begin: bool,
) -> Result<(), Error> {
let parent_hash = block.fields().header.parent_hash().clone();
@ -614,17 +614,19 @@ impl Engine for AuthorityRound {
Err(EngineError::DoubleVote(header.author().clone()))?;
}
// Report skipped primaries.
if step > parent_step + 1 {
// TODO: use epochmanager to get correct validator set for reporting?
// or just rely on the fact that in general these will be the same
// and some reports might go missing?
trace!(target: "engine", "Author {} built block with step gap. current step: {}, parent step: {}",
if let (true, Some(me)) = (step > parent_step + 1, self.signer.read().address()) {
debug!(target: "engine", "Author {} built block with step gap. current step: {}, parent step: {}",
header.author(), step, parent_step);
let mut reported = HashSet::new();
for s in parent_step + 1..step {
let skipped_primary = step_proposer(&*self.validators, &parent.hash(), s);
// Do not report this signer.
if skipped_primary != me {
self.validators.report_benign(&skipped_primary, header.number(), header.number());
}
// Stop reporting once validators start repeating.
if !reported.insert(skipped_primary) { break; }
}
}
let gas_limit_divisor = self.gas_limit_bound_divisor;
@ -723,6 +725,9 @@ impl Engine for AuthorityRound {
if epoch_manager.finality_checker.subchain_head() != Some(*chain_head.parent_hash()) {
// build new finality checker from ancestry of chain head,
// not including chain head itself yet.
trace!(target: "finality", "Building finality up to parent of {} ({})",
chain_head.hash(), chain_head.parent_hash());
let mut hash = chain_head.parent_hash().clone();
let epoch_transition_hash = epoch_manager.epoch_transition_hash;
@ -734,6 +739,8 @@ impl Engine for AuthorityRound {
if header.number() == 0 { return None }
let res = (hash, header.author().clone());
trace!(target: "finality", "Ancestry iteration: yielding {:?}", res);
hash = header.parent_hash().clone();
Some(res)
})
@ -766,6 +773,16 @@ impl Engine for AuthorityRound {
let finality_proof = ::rlp::encode_list(&finality_proof);
epoch_manager.note_new_epoch();
info!(target: "engine", "Applying validator set change signalled at block {}", signal_number);
// We turn off can_propose here because upon validator set change there can
// be two valid proposers for a single step: one from the old set and
// one from the new.
//
// This way, upon encountering an epoch change, the proposer from the
// new set will be forced to wait until the next step to avoid sealing a
// block that breaks the invariant that the parent's step < the block's step.
self.can_propose.store(false, AtomicOrdering::SeqCst);
return Some(combine_proofs(signal_number, &pending.proof, &*finality_proof));
}
}
@ -816,11 +833,11 @@ impl Engine for AuthorityRound {
}
fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) {
self.signer.set(ap, address, password);
self.signer.write().set(ap, address, password);
}
fn sign(&self, hash: H256) -> Result<Signature, Error> {
self.signer.sign(hash).map_err(Into::into)
self.signer.read().sign(hash).map_err(Into::into)
}
fn snapshot_components(&self) -> Option<Box<::snapshot::SnapshotComponents>> {
@ -1018,6 +1035,12 @@ mod tests {
header.set_gas_limit(U256::from_str("222222").unwrap());
header.set_seal(vec![encode(&3usize).into_vec()]);
// Do not report when signer not present.
assert!(aura.verify_block_family(&header, &parent_header, None).is_ok());
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 0);
aura.set_signer(Arc::new(AccountProvider::transient_provider()), Default::default(), Default::default());
assert!(aura.verify_block_family(&header, &parent_header, None).is_ok());
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1);
}

View File

@ -82,7 +82,7 @@ pub struct BasicAuthority {
params: CommonParams,
gas_limit_bound_divisor: U256,
builtins: BTreeMap<Address, Builtin>,
signer: EngineSigner,
signer: RwLock<EngineSigner>,
validators: Box<ValidatorSet>,
}
@ -129,7 +129,7 @@ impl Engine for BasicAuthority {
}
fn seals_internally(&self) -> Option<bool> {
Some(self.signer.address() != Address::default())
Some(self.signer.read().is_some())
}
/// Attempt to seal the block internally.
@ -138,7 +138,7 @@ impl Engine for BasicAuthority {
let author = header.author();
if self.validators.contains(header.parent_hash(), author) {
// account should be pernamently unlocked, otherwise sealing will fail
if let Ok(signature) = self.signer.sign(header.bare_hash()) {
if let Ok(signature) = self.sign(header.bare_hash()) {
return Seal::Regular(vec![::rlp::encode(&(&H520::from(signature) as &[u8])).into_vec()]);
} else {
trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable");
@ -240,11 +240,11 @@ impl Engine for BasicAuthority {
}
fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) {
self.signer.set(ap, address, password);
self.signer.write().set(ap, address, password);
}
fn sign(&self, hash: H256) -> Result<Signature, Error> {
self.signer.sign(hash).map_err(Into::into)
self.signer.read().sign(hash).map_err(Into::into)
}
fn snapshot_components(&self) -> Option<Box<::snapshot::SnapshotComponents>> {

View File

@ -43,7 +43,7 @@ use account_provider::AccountProvider;
use block::ExecutedBlock;
use builtin::Builtin;
use client::Client;
use env_info::{EnvInfo, LastHashes};
use evm::env_info::{EnvInfo, LastHashes};
use error::Error;
use evm::Schedule;
use header::{Header, BlockNumber};
@ -193,7 +193,7 @@ pub trait Engine : Sync + Send {
/// Get the EVM schedule for the given `block_number`.
fn schedule(&self, block_number: BlockNumber) -> Schedule {
Schedule::from_params(block_number, self.params())
self.params().schedule(block_number)
}
/// Builtin-contracts we would like to see in the chain.
@ -394,12 +394,12 @@ pub trait Engine : Sync + Send {
/// Common engine utilities
pub mod common {
use block::ExecutedBlock;
use env_info::{EnvInfo, LastHashes};
use evm::env_info::{EnvInfo, LastHashes};
use error::Error;
use transaction::SYSTEM_ADDRESS;
use executive::Executive;
use types::executed::CallType;
use action_params::{ActionParams, ActionValue};
use evm::CallType;
use evm::action_params::{ActionParams, ActionValue};
use trace::{NoopTracer, NoopVMTracer};
use state::Substate;

View File

@ -16,21 +16,21 @@
//! A signer used by Engines which need to sign messages.
use util::{Arc, Mutex, RwLock, H256, Address};
use util::{Arc, H256, Address};
use ethkey::Signature;
use account_provider::{self, AccountProvider};
/// Everything that an Engine needs to sign messages.
pub struct EngineSigner {
account_provider: Mutex<Arc<AccountProvider>>,
address: RwLock<Address>,
password: RwLock<Option<String>>,
account_provider: Arc<AccountProvider>,
address: Option<Address>,
password: Option<String>,
}
impl Default for EngineSigner {
fn default() -> Self {
EngineSigner {
account_provider: Mutex::new(Arc::new(AccountProvider::transient_provider())),
account_provider: Arc::new(AccountProvider::transient_provider()),
address: Default::default(),
password: Default::default(),
}
@ -39,25 +39,30 @@ impl Default for EngineSigner {
impl EngineSigner {
/// Set up the signer to sign with given address and password.
pub fn set(&self, ap: Arc<AccountProvider>, address: Address, password: String) {
*self.account_provider.lock() = ap;
*self.address.write() = address;
*self.password.write() = Some(password);
pub fn set(&mut self, ap: Arc<AccountProvider>, address: Address, password: String) {
self.account_provider = ap;
self.address = Some(address);
self.password = Some(password);
debug!(target: "poa", "Setting Engine signer to {}", address);
}
/// Sign a consensus message hash.
pub fn sign(&self, hash: H256) -> Result<Signature, account_provider::SignError> {
self.account_provider.lock().sign(*self.address.read(), self.password.read().clone(), hash)
self.account_provider.sign(self.address.unwrap_or_else(Default::default), self.password.clone(), hash)
}
/// Signing address.
pub fn address(&self) -> Address {
self.address.read().clone()
pub fn address(&self) -> Option<Address> {
self.address.clone()
}
/// Check if the given address is the signing address.
pub fn is_address(&self, address: &Address) -> bool {
*self.address.read() == *address
self.address.map_or(false, |a| a == *address)
}
/// Check if the signing address was set.
pub fn is_some(&self) -> bool {
self.address.is_some()
}
}

View File

@ -86,7 +86,7 @@ pub struct Tendermint {
/// Vote accumulator.
votes: VoteCollector<ConsensusMessage>,
/// Used to sign messages and proposals.
signer: EngineSigner,
signer: RwLock<EngineSigner>,
/// Message for the last PoLC.
lock_change: RwLock<Option<ConsensusMessage>>,
/// Last lock view.
@ -159,19 +159,22 @@ impl Tendermint {
let r = self.view.load(AtomicOrdering::SeqCst);
let s = *self.step.read();
let vote_info = message_info_rlp(&VoteStep::new(h, r, s), block_hash);
match self.signer.sign(vote_info.sha3()).map(Into::into) {
Ok(signature) => {
match (self.signer.read().address(), self.sign(vote_info.sha3()).map(Into::into)) {
(Some(validator), Ok(signature)) => {
let message_rlp = message_full_rlp(&signature, &vote_info);
let message = ConsensusMessage::new(signature, h, r, s, block_hash);
let validator = self.signer.address();
self.votes.vote(message.clone(), &validator);
debug!(target: "engine", "Generated {:?} as {}.", message, validator);
self.handle_valid_message(&message);
Some(message_rlp)
},
Err(e) => {
trace!(target: "engine", "Could not sign the message {}", e);
(None, _) => {
trace!(target: "engine", "No message, since there is no engine signer.");
None
},
(Some(v), Err(e)) => {
trace!(target: "engine", "{} could not sign the message {}", v, e);
None
},
}
@ -272,7 +275,7 @@ impl Tendermint {
/// Check if current signer is the current proposer.
fn is_signer_proposer(&self, bh: &H256) -> bool {
let proposer = self.view_proposer(bh, self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst));
self.signer.is_address(&proposer)
self.signer.read().is_address(&proposer)
}
fn is_height(&self, message: &ConsensusMessage) -> bool {
@ -420,7 +423,7 @@ impl Engine for Tendermint {
/// Should this node participate.
fn seals_internally(&self) -> Option<bool> {
Some(self.signer.address() != Address::default())
Some(self.signer.read().is_some())
}
/// Attempt to seal generate a proposal seal.
@ -436,7 +439,7 @@ impl Engine for Tendermint {
let view = self.view.load(AtomicOrdering::SeqCst);
let bh = Some(header.bare_hash());
let vote_info = message_info_rlp(&VoteStep::new(height, view, Step::Propose), bh.clone());
if let Ok(signature) = self.signer.sign(vote_info.sha3()).map(Into::into) {
if let Ok(signature) = self.sign(vote_info.sha3()).map(Into::into) {
// Insert Propose vote.
debug!(target: "engine", "Submitting proposal {} at height {} view {}.", header.bare_hash(), height, view);
self.votes.vote(ConsensusMessage::new(signature, height, view, Step::Propose, bh), author);
@ -565,13 +568,13 @@ impl Engine for Tendermint {
fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) {
{
self.signer.set(ap, address, password);
self.signer.write().set(ap, address, password);
}
self.to_step(Step::Propose);
}
fn sign(&self, hash: H256) -> Result<Signature, Error> {
self.signer.sign(hash).map_err(Into::into)
self.signer.read().sign(hash).map_err(Into::into)
}
fn stop(&self) {
@ -901,7 +904,7 @@ mod tests {
#[test]
fn seal_submission() {
use ethkey::{Generator, Random};
use types::transaction::{Transaction, Action};
use transaction::{Transaction, Action};
use client::BlockChainClient;
let tap = Arc::new(AccountProvider::transient_provider());

View File

@ -110,6 +110,9 @@ fn prove_initial(provider: &Provider, header: &Header, caller: &Call) -> Result<
trace!(target: "engine", "obtained proof for initial set: {} validators, {} bytes",
validators.len(), proof.len());
info!(target: "engine", "Signal for switch to contract-based validator set.");
info!(target: "engine", "Initial contract validators: {:?}", validators);
proof
})
}
@ -231,9 +234,7 @@ impl ValidatorSet for ValidatorSafeContract {
.map(|out| (out, Vec::new()))) // generate no proofs in general
}
fn on_epoch_begin(&self, first: bool, _header: &Header, caller: &mut SystemCall) -> Result<(), ::error::Error> {
if first { return Ok(()) } // only signalled changes need to be noted.
fn on_epoch_begin(&self, _first: bool, _header: &Header, caller: &mut SystemCall) -> Result<(), ::error::Error> {
self.provider.finalize_change(caller)
.wait()
.map_err(::engines::EngineError::FailedSystemCall)
@ -271,8 +272,9 @@ impl ValidatorSet for ValidatorSafeContract {
None => ::engines::EpochChange::Unsure(::engines::Unsure::NeedsReceipts),
Some(receipts) => match self.extract_from_event(bloom, header, receipts) {
None => ::engines::EpochChange::No,
Some(_) => {
debug!(target: "engine", "signalling transition within contract");
Some(list) => {
info!(target: "engine", "Signal for transition within contract. New list: {:?}",
&*list);
let proof = encode_proof(&header, receipts);
::engines::EpochChange::Yes(::engines::Proof::Known(proof))
@ -297,7 +299,7 @@ impl ValidatorSet for ValidatorSafeContract {
let (old_header, state_items) = decode_first_proof(&rlp)?;
let old_hash = old_header.hash();
let env_info = ::env_info::EnvInfo {
let env_info = ::evm::env_info::EnvInfo {
number: old_header.number(),
author: *old_header.author(),
difficulty: *old_header.difficulty(),

View File

@ -22,13 +22,12 @@ use header::BlockNumber;
use basic_types::LogBloom;
use client::Error as ClientError;
use ipc::binary::{BinaryConvertError, BinaryConvertable};
use types::block_import_error::BlockImportError;
use snapshot::Error as SnapshotError;
use engines::EngineError;
use ethkey::Error as EthkeyError;
use account_provider::SignError as AccountsError;
pub use types::executed::{ExecutionError, CallError};
pub use executed::{ExecutionError, CallError};
#[derive(Debug, PartialEq, Clone, Copy)]
/// Errors concerning transaction processing.
@ -239,6 +238,53 @@ impl fmt::Display for ImportError {
f.write_fmt(format_args!("Block import error ({})", msg))
}
}
/// Error dedicated to import block function
#[derive(Debug)]
pub enum BlockImportError {
/// Import error
Import(ImportError),
/// Block error
Block(BlockError),
/// Other error
Other(String),
}
impl From<Error> for BlockImportError {
fn from(e: Error) -> Self {
match e {
Error::Block(block_error) => BlockImportError::Block(block_error),
Error::Import(import_error) => BlockImportError::Import(import_error),
_ => BlockImportError::Other(format!("other block import error: {:?}", e)),
}
}
}
/// Represents the result of importing transaction.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TransactionImportResult {
/// Transaction was imported to current queue.
Current,
/// Transaction was imported to future queue.
Future
}
/// Api-level error for transaction import
#[derive(Debug, Clone)]
pub enum TransactionImportError {
/// Transaction error
Transaction(TransactionError),
/// Other error
Other(String),
}
impl From<Error> for TransactionImportError {
fn from(e: Error) -> Self {
match e {
Error::Transaction(transaction_error) => TransactionImportError::Transaction(transaction_error),
_ => TransactionImportError::Other(format!("other block import error: {:?}", e)),
}
}
}
#[derive(Debug)]
/// General error type which should be capable of representing all errors in ethcore.

View File

@ -19,7 +19,7 @@ use ethash::{quick_get_difficulty, slow_get_seedhash, EthashManager};
use util::*;
use block::*;
use builtin::Builtin;
use env_info::EnvInfo;
use evm::env_info::EnvInfo;
use error::{BlockError, Error, TransactionError};
use header::{Header, BlockNumber};
use state::CleanupMode;
@ -29,7 +29,7 @@ use engines::{self, Engine};
use evm::Schedule;
use ethjson;
use rlp::{self, UntrustedRlp};
use env_info::LastHashes;
use evm::env_info::LastHashes;
/// Parity tries to round block.gas_limit to multiple of this constant
pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]);
@ -209,7 +209,8 @@ impl Engine for Arc<Ethash> {
block_number >= self.ethash_params.eip160_transition,
block_number >= self.ethash_params.eip161abc_transition,
block_number >= self.ethash_params.eip161d_transition);
schedule.apply_params(block_number, self.params());
self.params().update_schedule(block_number, &mut schedule);
schedule
}
}
@ -1027,7 +1028,7 @@ mod tests {
#[test]
fn rejects_transactions_below_min_gas_price() {
use ethkey::{Generator, Random};
use types::transaction::{Transaction, Action};
use transaction::{Transaction, Action};
let spec = new_homestead_test();
let mut ethparams = get_default_ethash_params();

View File

@ -17,58 +17,15 @@
//! Transaction execution format module.
use util::{Bytes, U256, Address, U512, trie};
use rlp::*;
use evm;
use trace::{VMTrace, FlatTrace};
use types::log_entry::LogEntry;
use types::state_diff::StateDiff;
use log_entry::LogEntry;
use state_diff::StateDiff;
use std::fmt;
/// The type of the call-like instruction.
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub enum CallType {
/// Not a CALL.
None,
/// CALL.
Call,
/// CALLCODE.
CallCode,
/// DELEGATECALL.
DelegateCall,
/// STATICCALL
StaticCall,
}
impl Encodable for CallType {
fn rlp_append(&self, s: &mut RlpStream) {
let v = match *self {
CallType::None => 0u32,
CallType::Call => 1,
CallType::CallCode => 2,
CallType::DelegateCall => 3,
CallType::StaticCall => 4,
};
Encodable::rlp_append(&v, s);
}
}
impl Decodable for CallType {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
rlp.as_val().and_then(|v| Ok(match v {
0u32 => CallType::None,
1 => CallType::Call,
2 => CallType::CallCode,
3 => CallType::DelegateCall,
4 => CallType::StaticCall,
_ => return Err(DecoderError::Custom("Invalid value of CallType item")),
}))
}
}
/// Transaction execution receipt.
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Executed {
/// True if the outer call/create resulted in an exceptional exit.
pub exception: Option<evm::Error>,
@ -112,7 +69,6 @@ pub struct Executed {
/// Result of executing the transaction.
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub enum ExecutionError {
/// Returned when there gas paid for transaction execution is
/// lower than base gas required.
@ -192,7 +148,6 @@ impl fmt::Display for ExecutionError {
/// Result of executing the transaction.
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub enum CallError {
/// Couldn't find the transaction in the chain.
TransactionNotFound,
@ -230,29 +185,3 @@ impl fmt::Display for CallError {
/// Transaction execution result.
pub type ExecutionResult = Result<Executed, ExecutionError>;
#[cfg(test)]
mod tests {
use rlp::*;
use super::CallType;
#[test]
fn encode_call_type() {
let ct = CallType::Call;
let mut s = RlpStream::new_list(2);
s.append(&ct);
assert!(!s.is_finished(), "List shouldn't finished yet");
s.append(&ct);
assert!(s.is_finished(), "List should be finished now");
s.out();
}
#[test]
fn should_encode_and_decode_call_type() {
let original = CallType::Call;
let encoded = encode(&original);
let decoded = decode(&encoded);
assert_eq!(original, decoded);
}
}

View File

@ -16,18 +16,18 @@
//! Transaction Execution environment.
use util::*;
use action_params::{ActionParams, ActionValue};
use evm::action_params::{ActionParams, ActionValue};
use state::{Backend as StateBackend, State, Substate, CleanupMode};
use engines::Engine;
use types::executed::CallType;
use env_info::EnvInfo;
use evm::CallType;
use evm::env_info::EnvInfo;
use error::ExecutionError;
use evm::{self, wasm, Factory, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData, CleanDustMode};
use externalities::*;
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
use transaction::{Action, SignedTransaction};
use crossbeam;
pub use types::executed::{Executed, ExecutionResult};
pub use executed::{Executed, ExecutionResult};
/// Roughly estimate what stack size each level of evm depth will use
/// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132)
@ -602,8 +602,8 @@ mod tests {
use super::*;
use util::{H256, U256, U512, Address, FromStr};
use util::bytes::BytesRef;
use action_params::{ActionParams, ActionValue};
use env_info::EnvInfo;
use evm::action_params::{ActionParams, ActionValue};
use evm::env_info::EnvInfo;
use evm::{Factory, VMType, CreateContractAddress};
use error::ExecutionError;
use state::{Substate, CleanupMode};
@ -613,7 +613,7 @@ mod tests {
use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer};
use transaction::{Action, Transaction};
use types::executed::CallType;
use evm::CallType;
#[test]
fn test_contract_address() {

View File

@ -16,14 +16,14 @@
//! Transaction Execution environment.
use util::*;
use action_params::{ActionParams, ActionValue};
use evm::action_params::{ActionParams, ActionValue};
use state::{Backend as StateBackend, State, Substate, CleanupMode};
use engines::Engine;
use env_info::EnvInfo;
use evm::env_info::EnvInfo;
use executive::*;
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData};
use types::executed::CallType;
use types::transaction::UNSIGNED_SENDER;
use evm::CallType;
use transaction::UNSIGNED_SENDER;
use trace::{Tracer, VMTracer};
/// Policy for handling output data on `RETURN` opcode.
@ -396,13 +396,13 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
mod tests {
use util::*;
use engines::Engine;
use env_info::EnvInfo;
use evm::env_info::EnvInfo;
use evm::Ext;
use state::{State, Substate};
use tests::helpers::*;
use super::*;
use trace::{NoopTracer, NoopVMTracer};
use types::executed::CallType;
use evm::CallType;
fn get_test_origin() -> OriginInfo {
OriginInfo {

View File

@ -25,8 +25,7 @@ use std::cell::RefCell;
pub use basic_types::Seal;
/// Type for Block number
pub type BlockNumber = u64;
pub use types::BlockNumber;
/// A block header.
///

View File

@ -15,15 +15,15 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use super::test_common::*;
use action_params::ActionParams;
use evm::action_params::ActionParams;
use state::{Backend as StateBackend, State, Substate};
use executive::*;
use engines::Engine;
use env_info::EnvInfo;
use evm::env_info::EnvInfo;
use evm;
use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData};
use externalities::*;
use types::executed::CallType;
use evm::CallType;
use tests::helpers::*;
use ethjson;
use trace::{Tracer, NoopTracer};

View File

@ -21,8 +21,8 @@ use ethereum;
use spec::Spec;
use ethjson;
use ethjson::state::test::ForkSpec;
use types::transaction::SignedTransaction;
use env_info::EnvInfo;
use transaction::SignedTransaction;
use evm::env_info::EnvInfo;
lazy_static! {
pub static ref FRONTIER: Spec = ethereum::new_frontier_test();

View File

@ -76,6 +76,7 @@ extern crate bloomchain;
extern crate bn;
extern crate byteorder;
extern crate crossbeam;
extern crate common_types as types;
extern crate crypto;
extern crate env_logger;
extern crate ethabi;
@ -105,8 +106,6 @@ extern crate semver;
extern crate stats;
extern crate time;
extern crate transient_hashmap;
extern crate parity_wasm;
extern crate wasm_utils;
#[macro_use]
extern crate log;
@ -116,6 +115,8 @@ extern crate ethcore_util as util;
extern crate lazy_static;
#[macro_use]
extern crate ethcore_ipc as ipc;
#[cfg_attr(test, macro_use)]
extern crate evm;
#[cfg(feature = "jit" )]
extern crate evmjit;
@ -123,26 +124,26 @@ extern crate evmjit;
pub extern crate ethstore;
pub mod account_provider;
pub mod engines;
pub mod block;
pub mod client;
pub mod db;
pub mod encoded;
pub mod engines;
pub mod error;
pub mod ethereum;
pub mod executed;
pub mod header;
pub mod service;
pub mod trace;
pub mod spec;
pub mod views;
pub mod pod_state;
pub mod migrations;
pub mod miner;
pub mod pod_state;
pub mod service;
pub mod snapshot;
pub mod action_params;
pub mod db;
pub mod verification;
pub mod spec;
pub mod state;
pub mod env_info;
#[macro_use] pub mod evm;
pub mod trace;
pub mod transaction;
pub mod verification;
pub mod views;
mod cache_manager;
mod blooms;
@ -154,7 +155,6 @@ mod builtin;
mod executive;
mod externalities;
mod blockchain;
mod types;
mod factory;
#[cfg(test)]

View File

@ -1280,7 +1280,7 @@ mod tests {
use ethkey::{Generator, Random};
use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult};
use header::BlockNumber;
use types::transaction::{SignedTransaction, Transaction, PendingTransaction, Action};
use transaction::{SignedTransaction, Transaction, PendingTransaction, Action};
use spec::Spec;
use tests::helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts};

View File

@ -134,7 +134,7 @@ mod tests {
use views::BlockView;
use block::Block;
use super::AbridgedBlock;
use types::transaction::{Action, Transaction};
use transaction::{Action, Transaction};
use util::{Address, H256, U256, Bytes};

View File

@ -20,10 +20,10 @@ use rustc_hex::FromHex;
use super::genesis::Genesis;
use super::seal::Generic as GenericSeal;
use action_params::{ActionValue, ActionParams};
use evm::action_params::{ActionValue, ActionParams};
use builtin::Builtin;
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT};
use env_info::EnvInfo;
use evm::env_info::EnvInfo;
use error::Error;
use ethereum;
use ethjson;
@ -36,7 +36,7 @@ use state_db::StateDB;
use state::{Backend, State, Substate};
use state::backend::Basic as BasicBackend;
use trace::{NoopTracer, NoopVMTracer};
use types::executed::CallType;
use evm::CallType;
use util::*;
/// Parameters common to all engines.
@ -87,6 +87,31 @@ pub struct CommonParams {
pub wasm: bool,
}
impl CommonParams {
/// Schedule for an EVM in the post-EIP-150-era of the Ethereum main net.
pub fn schedule(&self, block_number: u64) -> ::evm::Schedule {
let mut schedule = ::evm::Schedule::new_post_eip150(usize::max_value(), true, true, true);
self.update_schedule(block_number, &mut schedule);
schedule
}
/// Apply common spec config parameters to the schedule.
pub fn update_schedule(&self, block_number: u64, schedule: &mut ::evm::Schedule) {
schedule.have_create2 = block_number >= self.eip86_transition;
schedule.have_revert = block_number >= self.eip140_transition;
schedule.have_static_call = block_number >= self.eip214_transition;
if block_number >= self.eip210_transition {
schedule.blockhash_gas = 350;
}
if block_number >= self.dust_protection_transition {
schedule.kill_dust = match self.remove_dust_contracts {
true => ::evm::CleanDustMode::WithCodeAndStorage,
false => ::evm::CleanDustMode::BasicOnly,
};
}
}
}
impl From<ethjson::spec::Params> for CommonParams {
fn from(p: ethjson::spec::Params) -> Self {
CommonParams {

View File

@ -24,7 +24,7 @@ use std::collections::hash_map::Entry;
use receipt::Receipt;
use engines::Engine;
use env_info::EnvInfo;
use evm::env_info::EnvInfo;
use error::Error;
use executive::{Executive, TransactOptions};
use factory::Factories;
@ -32,7 +32,7 @@ use trace::FlatTrace;
use pod_account::*;
use pod_state::{self, PodState};
use types::basic_account::BasicAccount;
use types::executed::{Executed, ExecutionError};
use executed::{Executed, ExecutionError};
use types::state_diff::StateDiff;
use transaction::SignedTransaction;
use state_db::StateDB;
@ -982,12 +982,12 @@ mod tests {
use ethkey::Secret;
use util::{U256, H256, Address, Hashable};
use tests::helpers::*;
use env_info::EnvInfo;
use evm::env_info::EnvInfo;
use spec::*;
use transaction::*;
use ethcore_logger::init_log;
use trace::{FlatTrace, TraceError, trace};
use types::executed::CallType;
use evm::CallType;
fn secret() -> Secret {
"".sha3().into()

76
ethcore/src/tests/evm.rs Normal file
View File

@ -0,0 +1,76 @@
//! Tests of EVM integration with transaction execution.
use evm::action_params::{ActionParams, ActionValue};
use evm::env_info::EnvInfo;
use evm::{Factory, VMType};
use evm::call_type::CallType;
use executive::Executive;
use state::Substate;
use tests::helpers::*;
use trace::{NoopVMTracer, NoopTracer};
use transaction::SYSTEM_ADDRESS;
use rustc_hex::FromHex;
use util::*;
evm_test!{test_blockhash_eip210: test_blockhash_eip210_jit, test_blockhash_eip210_int}
fn test_blockhash_eip210(factory: Factory) {
let get_prev_hash_code = Arc::new("600143034060205260206020f3".from_hex().unwrap()); // this returns previous block hash
let get_prev_hash_code_hash = get_prev_hash_code.sha3();
// This is same as DEFAULT_BLOCKHASH_CONTRACT except for metropolis transition block check removed.
let test_blockhash_contract = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b61014a565b4360003512151561009057600060405260206040f35b610100600035430312156100b357610100600035075460605260206060f3610149565b62010000600035430312156100d157600061010060003507146100d4565b60005b156100f6576101006101006000350507610100015460805260206080f3610148565b630100000060003543031215610116576000620100006000350714610119565b60005b1561013c57610100620100006000350507610200015460a052602060a0f3610147565b600060c052602060c0f35b5b5b5b5b";
let blockhash_contract_code = Arc::new(test_blockhash_contract.from_hex().unwrap());
let blockhash_contract_code_hash = blockhash_contract_code.sha3();
let engine = TestEngine::new_metropolis();
let mut env_info = EnvInfo::default();
// populate state with 256 last hashes
let mut state = get_temp_state_with_factory(factory);
let contract_address: Address = 0xf0.into();
state.init_code(&contract_address, (*blockhash_contract_code).clone()).unwrap();
for i in 1 .. 257 {
env_info.number = i.into();
let params = ActionParams {
code_address: contract_address.clone(),
address: contract_address,
sender: SYSTEM_ADDRESS.clone(),
origin: SYSTEM_ADDRESS.clone(),
gas: 100000.into(),
gas_price: 0.into(),
value: ActionValue::Transfer(0.into()),
code: Some(blockhash_contract_code.clone()),
code_hash: Some(blockhash_contract_code_hash),
data: Some(H256::from(i - 1).to_vec()),
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, &engine);
let mut substate = Substate::new();
let mut output = [];
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
panic!("Encountered error on updating last hashes: {}", e);
}
}
env_info.number = 256;
let params = ActionParams {
code_address: Address::new(),
address: Address::new(),
sender: Address::new(),
origin: Address::new(),
gas: 100000.into(),
gas_price: 0.into(),
value: ActionValue::Transfer(0.into()),
code: Some(get_prev_hash_code),
code_hash: Some(get_prev_hash_code_hash),
data: None,
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, &engine);
let mut substate = Substate::new();
let mut output = H256::new();
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
panic!("Encountered error on getting last hash: {}", e);
}
assert_eq!(output, 255.into());
}

View File

@ -16,5 +16,8 @@
pub mod helpers;
mod client;
mod evm;
#[cfg(feature="ipc")]
mod rpc;

View File

@ -410,7 +410,7 @@ mod tests {
use trace::{Filter, LocalizedTrace, AddressesFilter, TraceError};
use trace::trace::{Call, Action, Res};
use trace::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces};
use types::executed::CallType;
use evm::CallType;
struct NoopExtras;

View File

@ -17,7 +17,7 @@
//! Simple executive tracer.
use util::{Bytes, Address, U256};
use action_params::ActionParams;
use evm::action_params::ActionParams;
use trace::trace::{Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide};
use trace::{Tracer, VMTracer, FlatTrace, TraceError};

View File

@ -22,21 +22,24 @@ mod db;
mod executive_tracer;
mod import;
mod noop_tracer;
mod types;
pub use types::trace_types::{filter, flat, localized, trace};
pub use types::trace_types::error::Error as TraceError;
pub use self::config::Config;
pub use self::db::TraceDB;
pub use types::trace_types::trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff};
pub use types::trace_types::flat::{FlatTrace, FlatTransactionTraces, FlatBlockTraces};
pub use self::noop_tracer::{NoopTracer, NoopVMTracer};
pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer};
pub use types::trace_types::filter::{Filter, AddressesFilter};
pub use self::import::ImportRequest;
pub use self::localized::LocalizedTrace;
pub use self::types::{filter, flat, localized, trace};
pub use self::types::error::Error as TraceError;
pub use self::types::trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff};
pub use self::types::flat::{FlatTrace, FlatTransactionTraces, FlatBlockTraces};
pub use self::types::filter::{Filter, AddressesFilter};
use util::{Bytes, Address, U256, H256, DBTransaction};
use self::trace::{Call, Create};
use action_params::ActionParams;
use evm::action_params::ActionParams;
use header::BlockNumber;
/// This trait is used by executive to build traces.

View File

@ -17,7 +17,7 @@
//! Nonoperative tracer.
use util::{Bytes, Address, U256};
use action_params::ActionParams;
use evm::action_params::ActionParams;
use trace::{Tracer, VMTracer, FlatTrace, TraceError};
use trace::trace::{Call, Create, VMTrace};

View File

@ -22,7 +22,6 @@ use evm::Error as EvmError;
/// Trace evm errors.
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub enum Error {
/// `OutOfGas` is returned when transaction execution runs out of gas.
OutOfGas,

View File

@ -23,13 +23,12 @@ use util::sha3::Hashable;
use util::bloom::Bloomable;
use basic_types::LogBloom;
use trace::flat::FlatTrace;
use types::trace_types::trace::{Action, Res};
use super::trace::{Action, Res};
/// Addresses filter.
///
/// Used to create bloom possibilities and match filters.
#[derive(Debug)]
#[cfg_attr(feature = "ipc", binary)]
pub struct AddressesFilter {
list: Vec<Address>
}
@ -76,7 +75,6 @@ impl AddressesFilter {
}
#[derive(Debug)]
#[cfg_attr(feature = "ipc", binary)]
/// Traces filter.
pub struct Filter {
/// Block range.
@ -143,7 +141,7 @@ mod tests {
use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide};
use trace::flat::FlatTrace;
use trace::{Filter, AddressesFilter, TraceError};
use types::executed::CallType;
use evm::CallType;
#[test]
fn empty_trace_filter_bloom_possibilities() {

View File

@ -26,7 +26,6 @@ use super::trace::{Action, Res};
///
/// Parent and children indexes refer to positions in this vector.
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct FlatTrace {
/// Type of action performed by a transaction.
pub action: Action,
@ -164,7 +163,7 @@ mod tests {
use rlp::*;
use super::{FlatBlockTraces, FlatTransactionTraces, FlatTrace};
use trace::trace::{Action, Res, CallResult, Call, Suicide};
use types::executed::CallType;
use evm::CallType;
#[test]
fn encode_flat_transaction_traces() {

View File

@ -22,7 +22,6 @@ use header::BlockNumber;
/// Localized trace.
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct LocalizedTrace {
/// Type of action performed by a transaction.
pub action: Action,

View File

@ -21,9 +21,9 @@ use util::sha3::Hashable;
use util::bloom::Bloomable;
use rlp::*;
use action_params::ActionParams;
use evm::action_params::ActionParams;
use basic_types::LogBloom;
use types::executed::CallType;
use evm::CallType;
use super::error::Error;
/// `Call` result.

View File

@ -32,9 +32,8 @@ pub const UNSIGNED_SENDER: Address = ::util::H160([0xff; 20]);
/// System sender address for internal state updates.
pub const SYSTEM_ADDRESS: Address = ::util::H160([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xfe]);
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
/// Transaction action type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Action {
/// Create creates new contract.
Create,
@ -59,7 +58,6 @@ impl Decodable for Action {
/// Transaction activation condition.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub enum Condition {
/// Valid at this block number or later.
Number(BlockNumber),
@ -70,7 +68,6 @@ pub enum Condition {
/// A set of information describing an externally-originating message call
/// or contract creation operation.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Transaction {
/// Nonce.
pub nonce: U256,
@ -241,9 +238,8 @@ impl Transaction {
}
}
/// Signed transaction information.
/// Signed transaction information without verified signature.
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct UnverifiedTransaction {
/// Plain Transaction.
unsigned: Transaction,
@ -470,7 +466,6 @@ impl SignedTransaction {
/// Signed Transaction that is a part of canon blockchain.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct LocalizedTransaction {
/// Signed part.
pub signed: UnverifiedTransaction,
@ -511,7 +506,6 @@ impl Deref for LocalizedTransaction {
/// Queued transaction with additional information.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct PendingTransaction {
/// Signed transaction data.
pub transaction: SignedTransaction,
@ -544,8 +538,13 @@ impl From<SignedTransaction> for PendingTransaction {
}
}
#[test]
fn sender_test() {
#[cfg(test)]
mod tests {
use super::*;
use util::{Hashable, U256};
#[test]
fn sender_test() {
let t: UnverifiedTransaction = decode(&::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
assert_eq!(t.data, b"");
assert_eq!(t.gas, U256::from(0x5208u64));
@ -557,10 +556,10 @@ fn sender_test() {
assert_eq!(t.value, U256::from(0x0au64));
assert_eq!(public_to_address(&t.recover_public().unwrap()), "0f65fe9276bc9a24ae7083ae28e2660ef72df99e".into());
assert_eq!(t.network_id(), None);
}
}
#[test]
fn signing() {
#[test]
fn signing() {
use ethkey::{Random, Generator};
let key = Random.generate().unwrap();
@ -574,10 +573,10 @@ fn signing() {
}.sign(&key.secret(), None);
assert_eq!(Address::from(key.public().sha3()), t.sender());
assert_eq!(t.network_id(), None);
}
}
#[test]
fn fake_signing() {
#[test]
fn fake_signing() {
let t = Transaction {
action: Action::Create,
nonce: U256::from(42),
@ -592,10 +591,10 @@ fn fake_signing() {
let t = t.clone();
assert_eq!(Address::from(0x69), t.sender());
assert_eq!(t.network_id(), None);
}
}
#[test]
fn should_recover_from_network_specific_signing() {
#[test]
fn should_recover_from_network_specific_signing() {
use ethkey::{Random, Generator};
let key = Random.generate().unwrap();
let t = Transaction {
@ -608,10 +607,10 @@ fn should_recover_from_network_specific_signing() {
}.sign(&key.secret(), Some(69));
assert_eq!(Address::from(key.public().sha3()), t.sender());
assert_eq!(t.network_id(), Some(69));
}
}
#[test]
fn should_agree_with_vitalik() {
#[test]
fn should_agree_with_vitalik() {
use rustc_hex::FromHex;
let test_vector = |tx_data: &str, address: &'static str| {
@ -631,4 +630,5 @@ fn should_agree_with_vitalik() {
test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332");
test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029");
test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f");
}
}

View File

@ -1,42 +0,0 @@
// Copyright 2015-2017 Parity Technologies (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/>.
//! Block import error related types
use error::{ImportError, BlockError, Error};
use std::convert::From;
/// Error dedicated to import block function
#[derive(Debug)]
#[cfg_attr(feature = "ipc", binary)]
pub enum BlockImportError {
/// Import error
Import(ImportError),
/// Block error
Block(BlockError),
/// Other error
Other(String),
}
impl From<Error> for BlockImportError {
fn from(e: Error) -> Self {
match e {
Error::Block(block_error) => BlockImportError::Block(block_error),
Error::Import(import_error) => BlockImportError::Import(import_error),
_ => BlockImportError::Other(format!("other block import error: {:?}", e)),
}
}
}

View File

@ -1,42 +0,0 @@
// Copyright 2015-2017 Parity Technologies (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/>.
//! Block status description module
use verification::queue::Status as QueueStatus;
/// General block status
#[derive(Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", binary)]
pub enum BlockStatus {
/// Part of the blockchain.
InChain,
/// Queued for import.
Queued,
/// Known as bad.
Bad,
/// Unknown.
Unknown,
}
impl From<QueueStatus> for BlockStatus {
fn from(status: QueueStatus) -> Self {
match status {
QueueStatus::Queued => BlockStatus::Queued,
QueueStatus::Bad => BlockStatus::Bad,
QueueStatus::Unknown => BlockStatus::Unknown,
}
}
}

View File

@ -1,50 +0,0 @@
// Copyright 2015-2017 Parity Technologies (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/>.
//! Transaction import result related types
use ipc::binary::{BinaryConvertError, BinaryConvertable};
use error::{TransactionError, Error};
#[derive(Debug, Clone, Copy, PartialEq)]
/// Represents the result of importing transaction.
pub enum TransactionImportResult {
/// Transaction was imported to current queue.
Current,
/// Transaction was imported to future queue.
Future
}
binary_fixed_size!(TransactionImportResult);
/// Api-level error for transaction import
#[derive(Debug, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub enum TransactionImportError {
/// Transaction error
Transaction(TransactionError),
/// Other error
Other(String),
}
impl From<Error> for TransactionImportError {
fn from(e: Error) -> Self {
match e {
Error::Transaction(transaction_error) => TransactionImportError::Transaction(transaction_error),
_ => TransactionImportError::Other(format!("other block import error: {:?}", e)),
}
}
}

View File

@ -115,6 +115,17 @@ pub enum Status {
Unknown,
}
impl Into<::block_status::BlockStatus> for Status {
fn into(self) -> ::block_status::BlockStatus {
use ::block_status::BlockStatus;
match self {
Status::Queued => BlockStatus::Queued,
Status::Bad => BlockStatus::Bad,
Status::Unknown => BlockStatus::Unknown,
}
}
}
// the internal queue sizes.
struct Sizes {
unverified: AtomicUsize,

View File

@ -585,7 +585,7 @@ mod tests {
#[test]
fn dust_protection() {
use ethkey::{Generator, Random};
use types::transaction::{Transaction, Action};
use transaction::{Transaction, Action};
use engines::NullEngine;
let mut params = CommonParams::default();

13
ethcore/types/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "common-types"
description = "Common types used throughout the codebase"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
rlp = { path = "../../util/rlp" }
ethcore-util = { path = "../../util" }
ethjson = { path = "../../json" }
[dev-dependencies]
rustc-hex= "1.0"

View File

@ -20,12 +20,10 @@ use std::cmp::*;
use std::fmt;
use std::collections::BTreeMap;
use util::{U256, H256, Bytes};
use ipc::binary::BinaryConvertable;
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
/// Diff type for specifying a change (or not).
pub enum Diff<T> where T: Eq + BinaryConvertable {
pub enum Diff<T> where T: Eq {
/// Both sides are the same.
Same,
/// Left (pre, source) side doesn't include value, right side (post, destination) does.
@ -36,7 +34,7 @@ pub enum Diff<T> where T: Eq + BinaryConvertable {
Died(T),
}
impl<T> Diff<T> where T: Eq + BinaryConvertable {
impl<T> Diff<T> where T: Eq {
/// Construct new object with given `pre` and `post`.
pub fn new(pre: T, post: T) -> Self { if pre == post { Diff::Same } else { Diff::Changed(pre, post) } }

View File

@ -14,12 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Types used in the public api
#![cfg_attr(feature = "ipc", allow(dead_code, unused_assignments, unused_variables))] // codegen issues
#[cfg(feature = "ipc")]
include!(concat!(env!("OUT_DIR"), "/mod.rs.in"));
#[cfg(not(feature = "ipc"))]
include!("mod.rs.in");
/// General block status
#[derive(Debug, Eq, PartialEq)]
pub enum BlockStatus {
/// Part of the blockchain.
InChain,
/// Queued for import.
Queued,
/// Known as bad.
Bad,
/// Unknown.
Unknown,
}

View File

@ -16,13 +16,14 @@
//! Blockhain info type definition
use std::fmt;
use util::{U256, H256};
use header::BlockNumber;
use types::security_level::SecurityLevel;
use security_level::SecurityLevel;
use {BlockNumber};
/// Information about the blockchain gathered together.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "ipc", binary)]
pub struct BlockChainInfo {
/// Blockchain difficulty.
pub total_difficulty: U256,
@ -57,3 +58,9 @@ impl BlockChainInfo {
}
}
}
impl fmt::Display for BlockChainInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "#{}.{}", self.best_block_number, self.best_block_hash)
}
}

View File

@ -18,7 +18,6 @@
/// Options concerning what analytics we run on the call.
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", binary)]
pub struct CallAnalytics {
/// Make a transaction trace.
pub transaction_tracing: bool,

View File

@ -18,12 +18,11 @@
use util::{Address, H256, Hashable, H2048};
use util::bloom::Bloomable;
use client::BlockId;
use ids::BlockId;
use log_entry::LogEntry;
/// Blockchain Filter.
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Filter {
/// Blockchain will be searched from this block.
pub from_block: BlockId,
@ -114,7 +113,7 @@ impl Filter {
#[cfg(test)]
mod tests {
use filter::Filter;
use client::BlockId;
use ids::BlockId;
use log_entry::LogEntry;
#[test]

View File

@ -17,11 +17,10 @@
//! Unique identifiers.
use util::hash::H256;
use header::BlockNumber;
use {BlockNumber};
/// Uniquely identifies block.
#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub enum BlockId {
/// Block's sha3.
/// Querying by hash is always faster.
@ -38,7 +37,6 @@ pub enum BlockId {
/// Uniquely identifies transaction.
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub enum TransactionId {
/// Transaction's sha3.
Hash(H256),
@ -48,7 +46,6 @@ pub enum TransactionId {
}
/// Uniquely identifies Trace.
#[cfg_attr(feature = "ipc", binary)]
pub struct TraceId {
/// Transaction
pub transaction: TransactionId,
@ -58,7 +55,6 @@ pub struct TraceId {
/// Uniquely identifies Uncle.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct UncleId {
/// Block id.
pub block: BlockId,

View File

@ -14,27 +14,33 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
pub mod transaction;
pub mod ids;
pub mod receipt;
pub mod tree_route;
pub mod blockchain_info;
pub mod log_entry;
pub mod trace_types;
pub mod executed;
pub mod block_status;
//! Types used in the public API
extern crate ethcore_util as util;
extern crate ethjson;
extern crate rlp;
#[cfg(test)]
extern crate rustc_hex;
pub mod account_diff;
pub mod state_diff;
pub mod verification_queue_info;
pub mod filter;
pub mod trace_filter;
pub mod basic_account;
pub mod block_status;
pub mod blockchain_info;
pub mod call_analytics;
pub mod transaction_import;
pub mod block_import_error;
pub mod restoration_status;
pub mod snapshot_manifest;
pub mod filter;
pub mod ids;
pub mod log_entry;
pub mod mode;
pub mod pruning_info;
pub mod receipt;
pub mod restoration_status;
pub mod security_level;
pub mod encoded;
pub mod basic_account;
pub mod snapshot_manifest;
pub mod state_diff;
pub mod trace_filter;
pub mod tree_route;
pub mod verification_queue_info;
/// Type for block number.
pub type BlockNumber = u64;

View File

@ -21,13 +21,13 @@ use util::{H256, Address, Bytes, HeapSizeOf, Hashable};
use util::bloom::Bloomable;
use rlp::*;
use basic_types::LogBloom;
use header::BlockNumber;
use {BlockNumber};
use ethjson;
pub type LogBloom = ::util::H2048;
/// A record of execution for a `LOG` operation.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct LogEntry {
/// The address of the contract executing at the point of the `LOG` operation.
pub address: Address,
@ -82,7 +82,6 @@ impl From<ethjson::state::Log> for LogEntry {
/// Log localized in a blockchain.
#[derive(Default, Debug, PartialEq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct LocalizedLogEntry {
/// Plain log entry.
pub entry: LogEntry,

View File

@ -17,11 +17,9 @@
//! Mode type
pub use std::time::Duration;
use client::Mode as ClientMode;
/// IPC-capable shadow-type for `client::config::Mode`
#[derive(Clone, Debug)]
#[cfg_attr(feature = "ipc", binary)]
pub enum Mode {
/// Same as `ClientMode::Off`.
Off,
@ -32,25 +30,3 @@ pub enum Mode {
/// Same as `ClientMode::Active`.
Active,
}
impl From<ClientMode> for Mode {
fn from(mode: ClientMode) -> Self {
match mode {
ClientMode::Off => Mode::Off,
ClientMode::Dark(timeout) => Mode::Dark(timeout.as_secs()),
ClientMode::Passive(timeout, alarm) => Mode::Passive(timeout.as_secs(), alarm.as_secs()),
ClientMode::Active => Mode::Active,
}
}
}
impl From<Mode> for ClientMode {
fn from(mode: Mode) -> Self {
match mode {
Mode::Off => ClientMode::Off,
Mode::Dark(timeout) => ClientMode::Dark(Duration::from_secs(timeout)),
Mode::Passive(timeout, alarm) => ClientMode::Passive(Duration::from_secs(timeout), Duration::from_secs(alarm)),
Mode::Active => ClientMode::Active,
}
}
}

View File

@ -22,7 +22,6 @@
/// Client pruning info. See module-level docs for more details.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct PruningInfo {
/// The first block which everything can be served after.
pub earliest_chain: u64,

View File

@ -20,13 +20,11 @@ use util::{H256, U256, Address};
use util::HeapSizeOf;
use rlp::*;
use basic_types::LogBloom;
use header::BlockNumber;
use log_entry::{LogEntry, LocalizedLogEntry};
use {BlockNumber};
use log_entry::{LogBloom, LogEntry, LocalizedLogEntry};
/// Information describing execution of a transaction.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Receipt {
/// The state root after executing the transaction. Optional since EIP98
pub state_root: Option<H256>,
@ -92,7 +90,6 @@ impl HeapSizeOf for Receipt {
/// Receipt with additional info.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct RichReceipt {
/// Transaction hash.
pub transaction_hash: H256,
@ -114,7 +111,6 @@ pub struct RichReceipt {
/// Receipt with additional info.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct LocalizedReceipt {
/// Transaction hash.
pub transaction_hash: H256,
@ -138,8 +134,13 @@ pub struct LocalizedReceipt {
pub state_root: Option<H256>,
}
#[test]
fn test_no_state_root() {
#[cfg(test)]
mod tests {
use super::Receipt;
use log_entry::LogEntry;
#[test]
fn test_no_state_root() {
let expected = ::rustc_hex::FromHex::from_hex("f9014183040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
let r = Receipt::new(
None,
@ -150,11 +151,11 @@ fn test_no_state_root() {
data: vec![0u8; 32]
}]
);
assert_eq!(&encode(&r)[..], &expected[..]);
}
assert_eq!(&::rlp::encode(&r)[..], &expected[..]);
}
#[test]
fn test_basic() {
#[test]
fn test_basic() {
let expected = ::rustc_hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
let r = Receipt::new(
Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()),
@ -165,8 +166,9 @@ fn test_basic() {
data: vec![0u8; 32]
}]
);
let encoded = encode(&r);
let encoded = ::rlp::encode(&r);
assert_eq!(&encoded[..], &expected[..]);
let decoded: Receipt = decode(&encoded);
let decoded: Receipt = ::rlp::decode(&encoded);
assert_eq!(decoded, r);
}
}

View File

@ -18,7 +18,6 @@
/// Statuses for restorations.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[cfg_attr(feature = "ipc", binary)]
pub enum RestorationStatus {
/// No restoration.
Inactive,

View File

@ -16,11 +16,10 @@
//! Indication of how secure the chain is.
use header::BlockNumber;
use {BlockNumber};
/// Indication of how secure the chain is.
#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub enum SecurityLevel {
/// All blocks from genesis to chain head are known to have valid state transitions and PoW.
FullState,

View File

@ -22,7 +22,6 @@ use util::Bytes;
/// Manifest data.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct ManifestData {
/// Snapshot format version.
pub version: u64,

View File

@ -22,10 +22,9 @@ use std::collections::BTreeMap;
use util::Address;
use account_diff::*;
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
/// Expression for the delta between two system states. Encoded the
/// delta of every altered account.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct StateDiff {
/// Raw diff key-value
pub raw: BTreeMap<Address, AccountDiff>

View File

@ -18,10 +18,9 @@
use std::ops::Range;
use util::{Address};
use types::ids::BlockId;
use ids::BlockId;
/// Easy to use trace filter.
#[cfg_attr(feature = "ipc", binary)]
pub struct Filter {
/// Range of filtering.
pub range: Range<BlockId>,

Some files were not shown because too many files have changed in this diff Show More