Merge branch 'master' into ui-2

This commit is contained in:
Jaco Greeff 2017-07-13 10:56:12 +02:00
commit d8c3c247f8
142 changed files with 1300 additions and 1000 deletions

38
Cargo.lock generated
View File

@ -253,6 +253,16 @@ dependencies = [
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "conv" name = "conv"
version = "0.3.3" version = "0.3.3"
@ -436,6 +446,7 @@ dependencies = [
"bn 0.4.4 (git+https://github.com/paritytech/bn)", "bn 0.4.4 (git+https://github.com/paritytech/bn)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -452,7 +463,7 @@ dependencies = [
"ethjson 0.1.0", "ethjson 0.1.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"ethstore 0.1.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)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"hardware-wallet 1.7.0", "hardware-wallet 1.7.0",
"hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)", "hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)",
@ -464,7 +475,6 @@ dependencies = [
"native-contracts 0.1.0", "native-contracts 0.1.0",
"num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.2.0", "rlp 0.2.0",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -474,7 +484,6 @@ dependencies = [
"stats 0.1.0", "stats 0.1.0",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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]] [[package]]
@ -585,6 +594,7 @@ dependencies = [
"ethcore-ipc-codegen 1.7.0", "ethcore-ipc-codegen 1.7.0",
"ethcore-network 1.7.0", "ethcore-network 1.7.0",
"ethcore-util 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)", "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)", "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)", "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)", "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]] [[package]]
name = "evmbin" name = "evmbin"
version = "0.1.0" version = "0.1.0"
@ -846,6 +874,7 @@ dependencies = [
"docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.7.0", "ethcore 1.7.0",
"ethcore-util 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)", "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 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)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1850,6 +1879,7 @@ dependencies = [
"ethkey 0.2.0", "ethkey 0.2.0",
"ethstore 0.1.0", "ethstore 0.1.0",
"ethsync 1.7.0", "ethsync 1.7.0",
"evm 0.1.0",
"fetch 0.1.0", "fetch 0.1.0",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1934,7 +1964,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-ui-precompiled" name = "parity-ui-precompiled"
version = "1.4.0" version = "1.4.0"
source = "git+https://github.com/paritytech/js-precompiled.git#fa572f52beb3a7b6f6473a5a5cf07518d899c4d9" source = "git+https://github.com/paritytech/js-precompiled.git#b49a1d46cc6c545403d18579ef7ae9f9d14eea7e"
dependencies = [ dependencies = [
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -81,14 +81,6 @@ Once you have rustup, install parity or download and build from source
---- ----
## Quick build and install
```bash
cargo install --git https://github.com/paritytech/parity.git parity
```
----
## Install from the snap store ## Install from the snap store
In any of the [supported Linux distros](https://snapcraft.io/docs/core/install): In any of the [supported Linux distros](https://snapcraft.io/docs/core/install):

View File

@ -25,6 +25,7 @@ use util::sha3::sha3;
use page::{LocalPageEndpoint, PageCache}; use page::{LocalPageEndpoint, PageCache};
use handlers::{ContentValidator, ValidatorResponse}; use handlers::{ContentValidator, ValidatorResponse};
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest};
use Embeddable;
type OnDone = Box<Fn(Option<LocalPageEndpoint>) + Send>; type OnDone = Box<Fn(Option<LocalPageEndpoint>) + Send>;
@ -116,16 +117,16 @@ pub struct Dapp {
id: String, id: String,
dapps_path: PathBuf, dapps_path: PathBuf,
on_done: OnDone, on_done: OnDone,
embeddable_on: Option<(String, u16)>, embeddable_on: Embeddable,
} }
impl Dapp { impl Dapp {
pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, embeddable_on: Option<(String, u16)>) -> Self { pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, embeddable_on: Embeddable) -> Self {
Dapp { Dapp {
id: id, id,
dapps_path: dapps_path, dapps_path,
on_done: on_done, on_done,
embeddable_on: embeddable_on, embeddable_on,
} }
} }

View File

@ -31,7 +31,7 @@ use parity_reactor::Remote;
use hyper; use hyper;
use hyper::status::StatusCode; use hyper::status::StatusCode;
use {SyncStatus, random_filename}; use {Embeddable, SyncStatus, random_filename};
use util::Mutex; use util::Mutex;
use page::LocalPageEndpoint; use page::LocalPageEndpoint;
use handlers::{ContentHandler, ContentFetcherHandler}; use handlers::{ContentHandler, ContentFetcherHandler};
@ -52,7 +52,7 @@ pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + 'static = URLHint
resolver: R, resolver: R,
cache: Arc<Mutex<ContentCache>>, cache: Arc<Mutex<ContentCache>>,
sync: Arc<SyncStatus>, sync: Arc<SyncStatus>,
embeddable_on: Option<(String, u16)>, embeddable_on: Embeddable,
remote: Remote, remote: Remote,
fetch: F, fetch: F,
only_content: bool, only_content: bool,
@ -93,22 +93,22 @@ impl<R: URLHint + 'static, F: Fetch> ContentFetcher<F, R> {
self self
} }
pub fn embeddable_on(mut self, embeddable_on: Option<(String, u16)>) -> Self { pub fn embeddable_on(mut self, embeddable_on: Embeddable) -> Self {
self.embeddable_on = embeddable_on; self.embeddable_on = embeddable_on;
self self
} }
fn still_syncing(address: Option<(String, u16)>) -> Box<Handler> { fn still_syncing(embeddable: Embeddable) -> Box<Handler> {
Box::new(ContentHandler::error( Box::new(ContentHandler::error(
StatusCode::ServiceUnavailable, StatusCode::ServiceUnavailable,
"Sync In Progress", "Sync In Progress",
"Your node is still syncing. We cannot resolve any content before it's fully synced.", "Your node is still syncing. We cannot resolve any content before it's fully synced.",
Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"), Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"),
address, embeddable,
)) ))
} }
fn dapps_disabled(address: Option<(String, u16)>) -> Box<Handler> { fn dapps_disabled(address: Embeddable) -> Box<Handler> {
Box::new(ContentHandler::error( Box::new(ContentHandler::error(
StatusCode::ServiceUnavailable, StatusCode::ServiceUnavailable,
"Network Dapps Not Available", "Network Dapps Not Available",

View File

@ -22,6 +22,7 @@ use std::path::{Path, PathBuf};
use page::{LocalPageEndpoint, PageCache}; use page::{LocalPageEndpoint, PageCache};
use endpoint::{Endpoint, EndpointInfo}; use endpoint::{Endpoint, EndpointInfo};
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest}; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest};
use Embeddable;
struct LocalDapp { struct LocalDapp {
id: String, id: String,
@ -60,14 +61,14 @@ fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo {
/// Returns Dapp Id and Local Dapp Endpoint for given filesystem path. /// Returns Dapp Id and Local Dapp Endpoint for given filesystem path.
/// Parses the path to extract last component (for name). /// Parses the path to extract last component (for name).
/// `None` is returned when path is invalid or non-existent. /// `None` is returned when path is invalid or non-existent.
pub fn local_endpoint<P: AsRef<Path>>(path: P, signer_address: Option<(String, u16)>) -> Option<(String, Box<LocalPageEndpoint>)> { pub fn local_endpoint<P: AsRef<Path>>(path: P, embeddable: Embeddable) -> Option<(String, Box<LocalPageEndpoint>)> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
path.canonicalize().ok().and_then(|path| { path.canonicalize().ok().and_then(|path| {
let name = path.file_name().and_then(|name| name.to_str()); let name = path.file_name().and_then(|name| name.to_str());
name.map(|name| { name.map(|name| {
let dapp = local_dapp(name.into(), path.clone()); let dapp = local_dapp(name.into(), path.clone());
(dapp.id, Box::new(LocalPageEndpoint::new( (dapp.id, Box::new(LocalPageEndpoint::new(
dapp.path, dapp.info, PageCache::Disabled, signer_address.clone()) dapp.path, dapp.info, PageCache::Disabled, embeddable.clone())
)) ))
}) })
}) })
@ -86,12 +87,12 @@ fn local_dapp(name: String, path: PathBuf) -> LocalDapp {
/// Returns endpoints for Local Dapps found for given filesystem path. /// Returns endpoints for Local Dapps found for given filesystem path.
/// Scans the directory and collects `LocalPageEndpoints`. /// Scans the directory and collects `LocalPageEndpoints`.
pub fn local_endpoints<P: AsRef<Path>>(dapps_path: P, signer_address: Option<(String, u16)>) -> BTreeMap<String, Box<Endpoint>> { pub fn local_endpoints<P: AsRef<Path>>(dapps_path: P, embeddable: Embeddable) -> BTreeMap<String, Box<Endpoint>> {
let mut pages = BTreeMap::<String, Box<Endpoint>>::new(); let mut pages = BTreeMap::<String, Box<Endpoint>>::new();
for dapp in local_dapps(dapps_path.as_ref()) { for dapp in local_dapps(dapps_path.as_ref()) {
pages.insert( pages.insert(
dapp.id, dapp.id,
Box::new(LocalPageEndpoint::new(dapp.path, dapp.info, PageCache::Disabled, signer_address.clone())) Box::new(LocalPageEndpoint::new(dapp.path, dapp.info, PageCache::Disabled, embeddable.clone()))
); );
} }
pages pages

View File

@ -26,7 +26,7 @@ use fetch::Fetch;
use parity_dapps::WebApp; use parity_dapps::WebApp;
use parity_reactor::Remote; use parity_reactor::Remote;
use parity_ui; use parity_ui;
use {WebProxyTokens}; use {WebProxyTokens, ParentFrameSettings};
mod app; mod app;
mod cache; mod cache;
@ -52,23 +52,23 @@ pub fn ui() -> Box<Endpoint> {
Box::new(PageEndpoint::with_fallback_to_index(parity_ui::App::default())) Box::new(PageEndpoint::with_fallback_to_index(parity_ui::App::default()))
} }
pub fn ui_redirection(ui_address: Option<(String, u16)>) -> Box<Endpoint> { pub fn ui_redirection(embeddable: Option<ParentFrameSettings>) -> Box<Endpoint> {
Box::new(ui::Redirection::new(ui_address)) Box::new(ui::Redirection::new(embeddable))
} }
pub fn all_endpoints<F: Fetch>( pub fn all_endpoints<F: Fetch>(
dapps_path: PathBuf, dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>, extra_dapps: Vec<PathBuf>,
dapps_domain: String, dapps_domain: &str,
ui_address: Option<(String, u16)>, embeddable: Option<ParentFrameSettings>,
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
remote: Remote, remote: Remote,
fetch: F, fetch: F,
) -> Endpoints { ) -> Endpoints {
// fetch fs dapps at first to avoid overwriting builtins // fetch fs dapps at first to avoid overwriting builtins
let mut pages = fs::local_endpoints(dapps_path, ui_address.clone()); let mut pages = fs::local_endpoints(dapps_path, embeddable.clone());
for path in extra_dapps { for path in extra_dapps {
if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), ui_address.clone()) { if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), embeddable.clone()) {
pages.insert(id, endpoint); pages.insert(id, endpoint);
} else { } else {
warn!(target: "dapps", "Ignoring invalid dapp at {}", path.display()); warn!(target: "dapps", "Ignoring invalid dapp at {}", path.display());
@ -76,9 +76,9 @@ pub fn all_endpoints<F: Fetch>(
} }
// NOTE [ToDr] Dapps will be currently embeded on 8180 // NOTE [ToDr] Dapps will be currently embeded on 8180
insert::<parity_ui::App>(&mut pages, "ui", Embeddable::Yes(ui_address.clone())); insert::<parity_ui::App>(&mut pages, "ui", Embeddable::Yes(embeddable.clone()));
pages.insert("proxy".into(), ProxyPac::boxed(ui_address.clone(), dapps_domain)); pages.insert("proxy".into(), ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()));
pages.insert(WEB_PATH.into(), Web::boxed(ui_address.clone(), web_proxy_tokens.clone(), remote.clone(), fetch.clone())); pages.insert(WEB_PATH.into(), Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), remote.clone(), fetch.clone()));
Arc::new(pages) Arc::new(pages)
} }
@ -91,7 +91,7 @@ fn insert<T : WebApp + Default + 'static>(pages: &mut BTreeMap<String, Box<Endpo
} }
enum Embeddable { enum Embeddable {
Yes(Option<(String, u16)>), Yes(Option<ParentFrameSettings>),
#[allow(dead_code)] #[allow(dead_code)]
No, No,
} }

View File

@ -19,28 +19,28 @@
use hyper::{Control, StatusCode}; use hyper::{Control, StatusCode};
use endpoint::{Endpoint, Handler, EndpointPath}; use endpoint::{Endpoint, Handler, EndpointPath};
use {address, handlers}; use {handlers, Embeddable};
/// Redirection to UI server. /// Redirection to UI server.
pub struct Redirection { pub struct Redirection {
signer_address: Option<(String, u16)>, embeddable_on: Embeddable,
} }
impl Redirection { impl Redirection {
pub fn new( pub fn new(
signer_address: Option<(String, u16)>, embeddable_on: Embeddable,
) -> Self { ) -> Self {
Redirection { Redirection {
signer_address: signer_address, embeddable_on,
} }
} }
} }
impl Endpoint for Redirection { impl Endpoint for Redirection {
fn to_async_handler(&self, _path: EndpointPath, _control: Control) -> Box<Handler> { fn to_async_handler(&self, _path: EndpointPath, _control: Control) -> Box<Handler> {
if let Some(ref signer_address) = self.signer_address { if let Some(ref frame) = self.embeddable_on {
trace!(target: "dapps", "Redirecting to signer interface."); trace!(target: "dapps", "Redirecting to signer interface.");
handlers::Redirection::boxed(&format!("http://{}", address(signer_address))) handlers::Redirection::boxed(&format!("http://{}:{}", &frame.host, frame.port))
} else { } else {
trace!(target: "dapps", "Signer disabled, returning 404."); trace!(target: "dapps", "Signer disabled, returning 404.");
Box::new(handlers::ContentHandler::error( Box::new(handlers::ContentHandler::error(
@ -48,7 +48,7 @@ impl Endpoint for Redirection {
"404 Not Found", "404 Not Found",
"Your homepage is not available when Trusted Signer is disabled.", "Your homepage is not available when Trusted Signer is disabled.",
Some("You can still access dapps by writing a correct address, though. Re-enable Signer to get your homepage back."), Some("You can still access dapps by writing a correct address, though. Re-enable Signer to get your homepage back."),
self.signer_address.clone(), None,
)) ))
} }
} }

View File

@ -24,6 +24,7 @@ use hyper::status::StatusCode;
use util::version; use util::version;
use handlers::add_security_headers; use handlers::add_security_headers;
use Embeddable;
#[derive(Clone)] #[derive(Clone)]
pub struct ContentHandler { pub struct ContentHandler {
@ -31,7 +32,7 @@ pub struct ContentHandler {
content: String, content: String,
mimetype: Mime, mimetype: Mime,
write_pos: usize, write_pos: usize,
safe_to_embed_on: Option<(String, u16)>, safe_to_embed_on: Embeddable,
} }
impl ContentHandler { impl ContentHandler {
@ -39,11 +40,17 @@ impl ContentHandler {
Self::new(StatusCode::Ok, content, mimetype) Self::new(StatusCode::Ok, content, mimetype)
} }
pub fn html(code: StatusCode, content: String, embeddable_on: Option<(String, u16)>) -> Self { pub fn html(code: StatusCode, content: String, embeddable_on: Embeddable) -> Self {
Self::new_embeddable(code, content, mime!(Text/Html), embeddable_on) Self::new_embeddable(code, content, mime!(Text/Html), embeddable_on)
} }
pub fn error(code: StatusCode, title: &str, message: &str, details: Option<&str>, embeddable_on: Option<(String, u16)>) -> Self { pub fn error(
code: StatusCode,
title: &str,
message: &str,
details: Option<&str>,
embeddable_on: Embeddable,
) -> Self {
Self::html(code, format!( Self::html(code, format!(
include_str!("../error_tpl.html"), include_str!("../error_tpl.html"),
title=title, title=title,
@ -57,13 +64,18 @@ impl ContentHandler {
Self::new_embeddable(code, content, mimetype, None) Self::new_embeddable(code, content, mimetype, None)
} }
pub fn new_embeddable(code: StatusCode, content: String, mimetype: Mime, embeddable_on: Option<(String, u16)>) -> Self { pub fn new_embeddable(
code: StatusCode,
content: String,
mimetype: Mime,
safe_to_embed_on: Embeddable,
) -> Self {
ContentHandler { ContentHandler {
code: code, code,
content: content, content,
mimetype: mimetype, mimetype,
write_pos: 0, write_pos: 0,
safe_to_embed_on: embeddable_on, safe_to_embed_on,
} }
} }
} }
@ -80,7 +92,7 @@ impl server::Handler<HttpStream> for ContentHandler {
fn on_response(&mut self, res: &mut server::Response) -> Next { fn on_response(&mut self, res: &mut server::Response) -> Next {
res.set_status(self.code); res.set_status(self.code);
res.headers_mut().set(header::ContentType(self.mimetype.clone())); res.headers_mut().set(header::ContentType(self.mimetype.clone()));
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on.clone()); add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on.take());
Next::write() Next::write()
} }

View File

@ -33,6 +33,7 @@ use hyper::status::StatusCode;
use endpoint::EndpointPath; use endpoint::EndpointPath;
use handlers::{ContentHandler, StreamingHandler}; use handlers::{ContentHandler, StreamingHandler};
use page::{LocalPageEndpoint, PageHandlerWaiting}; use page::{LocalPageEndpoint, PageHandlerWaiting};
use {Embeddable};
const FETCH_TIMEOUT: u64 = 300; const FETCH_TIMEOUT: u64 = 300;
@ -179,7 +180,7 @@ impl server::Handler<HttpStream> for WaitingHandler {
#[derive(Clone)] #[derive(Clone)]
struct Errors { struct Errors {
embeddable_on: Option<(String, u16)>, embeddable_on: Embeddable,
} }
impl Errors { impl Errors {
@ -241,20 +242,20 @@ impl<H: ContentValidator, F: Fetch> ContentFetcherHandler<H, F> {
path: EndpointPath, path: EndpointPath,
control: Control, control: Control,
installer: H, installer: H,
embeddable_on: Option<(String, u16)>, embeddable_on: Embeddable,
remote: Remote, remote: Remote,
fetch: F, fetch: F,
) -> Self { ) -> Self {
ContentFetcherHandler { ContentFetcherHandler {
fetch_control: FetchControl::default(), fetch_control: FetchControl::default(),
control: control, control,
remote: remote, remote,
fetch: fetch, fetch,
status: FetchState::NotStarted(url), status: FetchState::NotStarted(url),
installer: Some(installer), installer: Some(installer),
path: path, path,
errors: Errors { errors: Errors {
embeddable_on: embeddable_on, embeddable_on,
}, },
} }
} }

View File

@ -30,22 +30,20 @@ pub use self::fetch::{ContentFetcherHandler, ContentValidator, FetchControl, Val
pub use self::redirect::Redirection; pub use self::redirect::Redirection;
pub use self::streaming::StreamingHandler; pub use self::streaming::StreamingHandler;
use std::iter;
use util::Itertools;
use url::Url; use url::Url;
use hyper::{server, header, net, uri}; use hyper::{server, header, net, uri};
use address; use {apps, address, Embeddable};
/// Adds security-related headers to the Response. /// Adds security-related headers to the Response.
pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Option<(String, u16)>) { pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embeddable) {
headers.set_raw("X-XSS-Protection", vec![b"1; mode=block".to_vec()]); headers.set_raw("X-XSS-Protection", vec![b"1; mode=block".to_vec()]);
headers.set_raw("X-Content-Type-Options", vec![b"nosniff".to_vec()]); headers.set_raw("X-Content-Type-Options", vec![b"nosniff".to_vec()]);
// Embedding header: // Embedding header:
if let Some(ref embeddable_on) = embeddable_on { if let None = embeddable_on {
headers.set_raw("X-Frame-Options", vec![
format!("ALLOW-FROM http://{}", address(embeddable_on)).into_bytes()
]);
} else {
// TODO [ToDr] Should we be more strict here (DENY?)?
headers.set_raw("X-Frame-Options", vec![b"SAMEORIGIN".to_vec()]); headers.set_raw("X-Frame-Options", vec![b"SAMEORIGIN".to_vec()]);
} }
@ -62,7 +60,7 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Option
b"child-src 'self' http: https:;".to_vec(), b"child-src 'self' http: https:;".to_vec(),
// We allow data: blob: and HTTP(s) images. // We allow data: blob: and HTTP(s) images.
// We could get rid of wildcarding HTTP and only allow RPC server URL. // We could get rid of wildcarding HTTP and only allow RPC server URL.
// (http require for local dapps icons) // (http required for local dapps icons)
b"img-src 'self' 'unsafe-inline' data: blob: http: https:;".to_vec(), b"img-src 'self' 'unsafe-inline' data: blob: http: https:;".to_vec(),
// Allow style from data: blob: and HTTPS. // Allow style from data: blob: and HTTPS.
b"style-src 'self' 'unsafe-inline' data: blob: https:;".to_vec(), b"style-src 'self' 'unsafe-inline' data: blob: https:;".to_vec(),
@ -80,10 +78,27 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Option
b"block-all-mixed-content;".to_vec(), b"block-all-mixed-content;".to_vec(),
// Specify if the site can be embedded. // Specify if the site can be embedded.
match embeddable_on { match embeddable_on {
Some((ref host, ref port)) if host == "127.0.0.1" => { Some(ref embed) => {
format!("frame-ancestors {} {};", address(&(host.to_owned(), *port)), address(&("localhost".to_owned(), *port))) let std = address(&embed.host, embed.port);
let proxy = format!("{}.{}", apps::HOME_PAGE, embed.dapps_domain);
let domain = format!("*.{}:{}", embed.dapps_domain, embed.port);
let mut ancestors = vec![std, domain, proxy]
.into_iter()
.chain(embed.extra_embed_on
.iter()
.map(|&(ref host, port)| format!("{}:{}", host, port))
);
let ancestors = if embed.host == "127.0.0.1" {
let localhost = address("localhost", embed.port);
ancestors.chain(iter::once(localhost)).join(" ")
} else {
ancestors.join(" ")
};
format!("frame-ancestors {};", ancestors)
}, },
Some(ref embed) => format!("frame-ancestors {};", address(embed)),
None => format!("frame-ancestors 'self';"), None => format!("frame-ancestors 'self';"),
}.into_bytes(), }.into_bytes(),
]); ]);

View File

@ -24,6 +24,7 @@ use hyper::mime::Mime;
use hyper::status::StatusCode; use hyper::status::StatusCode;
use handlers::add_security_headers; use handlers::add_security_headers;
use Embeddable;
const BUFFER_SIZE: usize = 1024; const BUFFER_SIZE: usize = 1024;
@ -33,11 +34,11 @@ pub struct StreamingHandler<R: io::Read> {
status: StatusCode, status: StatusCode,
content: io::BufReader<R>, content: io::BufReader<R>,
mimetype: Mime, mimetype: Mime,
safe_to_embed_on: Option<(String, u16)>, safe_to_embed_on: Embeddable,
} }
impl<R: io::Read> StreamingHandler<R> { impl<R: io::Read> StreamingHandler<R> {
pub fn new(content: R, status: StatusCode, mimetype: Mime, embeddable_on: Option<(String, u16)>) -> Self { pub fn new(content: R, status: StatusCode, mimetype: Mime, embeddable_on: Embeddable) -> Self {
StreamingHandler { StreamingHandler {
buffer: [0; BUFFER_SIZE], buffer: [0; BUFFER_SIZE],
buffer_leftover: 0, buffer_leftover: 0,
@ -68,7 +69,7 @@ impl<R: io::Read> server::Handler<HttpStream> for StreamingHandler<R> {
fn on_response(&mut self, res: &mut server::Response) -> Next { fn on_response(&mut self, res: &mut server::Response) -> Next {
res.set_status(self.status); res.set_status(self.status);
res.headers_mut().set(header::ContentType(self.mimetype.clone())); res.headers_mut().set(header::ContentType(self.mimetype.clone()));
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on.clone()); add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on.take());
Next::write() Next::write()
} }

View File

@ -175,6 +175,7 @@ impl Middleware {
pool: CpuPool, pool: CpuPool,
remote: Remote, remote: Remote,
ui_address: Option<(String, u16)>, ui_address: Option<(String, u16)>,
extra_embed_on: Vec<(String, u16)>,
dapps_path: PathBuf, dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>, extra_dapps: Vec<PathBuf>,
dapps_domain: &str, dapps_domain: &str,
@ -183,17 +184,18 @@ impl Middleware {
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
fetch: F, fetch: F,
) -> Self { ) -> Self {
let embeddable = as_embeddable(ui_address, extra_embed_on, dapps_domain);
let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
hash_fetch::urlhint::URLHintContract::new(registrar), hash_fetch::urlhint::URLHintContract::new(registrar),
sync_status.clone(), sync_status.clone(),
remote.clone(), remote.clone(),
fetch.clone(), fetch.clone(),
).embeddable_on(ui_address.clone()).allow_dapps(true)); ).embeddable_on(embeddable.clone()).allow_dapps(true));
let endpoints = apps::all_endpoints( let endpoints = apps::all_endpoints(
dapps_path, dapps_path,
extra_dapps, extra_dapps,
dapps_domain.to_owned(), dapps_domain,
ui_address.clone(), embeddable.clone(),
web_proxy_tokens, web_proxy_tokens,
remote.clone(), remote.clone(),
fetch.clone(), fetch.clone(),
@ -207,7 +209,10 @@ impl Middleware {
remote.clone(), remote.clone(),
sync_status, sync_status,
); );
special.insert(router::SpecialEndpoint::Home, Some(apps::ui_redirection(ui_address.clone()))); special.insert(
router::SpecialEndpoint::Home,
Some(apps::ui_redirection(embeddable.clone())),
);
special special
}; };
@ -215,7 +220,7 @@ impl Middleware {
content_fetcher, content_fetcher,
Some(endpoints.clone()), Some(endpoints.clone()),
special, special,
ui_address, embeddable,
dapps_domain.to_owned(), dapps_domain.to_owned(),
); );
@ -251,8 +256,21 @@ fn special_endpoints(
special special
} }
fn address(address: &(String, u16)) -> String { fn address(host: &str, port: u16) -> String {
format!("{}:{}", address.0, address.1) format!("{}:{}", host, port)
}
fn as_embeddable(
ui_address: Option<(String, u16)>,
extra_embed_on: Vec<(String, u16)>,
dapps_domain: &str,
) -> Option<ParentFrameSettings> {
ui_address.map(|(host, port)| ParentFrameSettings {
host,
port,
extra_embed_on,
dapps_domain: dapps_domain.to_owned(),
})
} }
/// Random filename /// Random filename
@ -261,3 +279,18 @@ fn random_filename() -> String {
let mut rng = ::rand::OsRng::new().unwrap(); let mut rng = ::rand::OsRng::new().unwrap();
rng.gen_ascii_chars().take(12).collect() rng.gen_ascii_chars().take(12).collect()
} }
type Embeddable = Option<ParentFrameSettings>;
/// Parent frame host and port allowed to embed the content.
#[derive(Debug, Clone)]
pub struct ParentFrameSettings {
/// Hostname
pub host: String,
/// Port
pub port: u16,
/// Additional pages the pages can be embedded on.
pub extra_embed_on: Vec<(String, u16)>,
/// Dapps Domain (web3.site)
pub dapps_domain: String,
}

View File

@ -18,6 +18,7 @@ use page::{handler, PageCache};
use std::sync::Arc; use std::sync::Arc;
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
use parity_dapps::{WebApp, File, Info}; use parity_dapps::{WebApp, File, Info};
use Embeddable;
pub struct PageEndpoint<T : WebApp + 'static> { pub struct PageEndpoint<T : WebApp + 'static> {
/// Content of the files /// Content of the files
@ -25,7 +26,7 @@ pub struct PageEndpoint<T : WebApp + 'static> {
/// Prefix to strip from the path (when `None` deducted from `app_id`) /// Prefix to strip from the path (when `None` deducted from `app_id`)
pub prefix: Option<String>, pub prefix: Option<String>,
/// Safe to be loaded in frame by other origin. (use wisely!) /// Safe to be loaded in frame by other origin. (use wisely!)
safe_to_embed_on: Option<(String, u16)>, safe_to_embed_on: Embeddable,
info: EndpointInfo, info: EndpointInfo,
fallback_to_index_html: bool, fallback_to_index_html: bool,
} }
@ -73,7 +74,7 @@ impl<T: WebApp + 'static> PageEndpoint<T> {
/// Creates new `PageEndpoint` which can be safely used in iframe /// Creates new `PageEndpoint` which can be safely used in iframe
/// even from different origin. It might be dangerous (clickjacking). /// even from different origin. It might be dangerous (clickjacking).
/// Use wisely! /// Use wisely!
pub fn new_safe_to_embed(app: T, address: Option<(String, u16)>) -> Self { pub fn new_safe_to_embed(app: T, address: Embeddable) -> Self {
let info = app.info(); let info = app.info();
PageEndpoint { PageEndpoint {
app: Arc::new(app), app: Arc::new(app),

View File

@ -24,6 +24,7 @@ use hyper::status::StatusCode;
use hyper::{Decoder, Encoder, Next}; use hyper::{Decoder, Encoder, Next};
use endpoint::EndpointPath; use endpoint::EndpointPath;
use handlers::{ContentHandler, add_security_headers}; use handlers::{ContentHandler, add_security_headers};
use {Embeddable};
/// Represents a file that can be sent to client. /// Represents a file that can be sent to client.
/// Implementation should keep track of bytes already sent internally. /// Implementation should keep track of bytes already sent internally.
@ -59,7 +60,7 @@ pub enum ServedFile<T: Dapp> {
} }
impl<T: Dapp> ServedFile<T> { impl<T: Dapp> ServedFile<T> {
pub fn new(embeddable_on: Option<(String, u16)>) -> Self { pub fn new(embeddable_on: Embeddable) -> Self {
ServedFile::Error(ContentHandler::error( ServedFile::Error(ContentHandler::error(
StatusCode::NotFound, StatusCode::NotFound,
"404 Not Found", "404 Not Found",
@ -102,7 +103,7 @@ pub struct PageHandler<T: Dapp> {
/// Requested path. /// Requested path.
pub path: EndpointPath, pub path: EndpointPath,
/// Flag indicating if the file can be safely embeded (put in iframe). /// Flag indicating if the file can be safely embeded (put in iframe).
pub safe_to_embed_on: Option<(String, u16)>, pub safe_to_embed_on: Embeddable,
/// Cache settings for this page. /// Cache settings for this page.
pub cache: PageCache, pub cache: PageCache,
} }
@ -174,7 +175,7 @@ impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> {
} }
// Security headers: // Security headers:
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on.clone()); add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on.take());
Next::write() Next::write()
}, },
ServedFile::Error(ref mut handler) => { ServedFile::Error(ref mut handler) => {

View File

@ -21,6 +21,7 @@ use std::path::{Path, PathBuf};
use page::handler::{self, PageCache, PageHandlerWaiting}; use page::handler::{self, PageCache, PageHandlerWaiting};
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
use mime::Mime; use mime::Mime;
use Embeddable;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LocalPageEndpoint { pub struct LocalPageEndpoint {
@ -28,11 +29,11 @@ pub struct LocalPageEndpoint {
mime: Option<Mime>, mime: Option<Mime>,
info: Option<EndpointInfo>, info: Option<EndpointInfo>,
cache: PageCache, cache: PageCache,
embeddable_on: Option<(String, u16)>, embeddable_on: Embeddable,
} }
impl LocalPageEndpoint { impl LocalPageEndpoint {
pub fn new(path: PathBuf, info: EndpointInfo, cache: PageCache, embeddable_on: Option<(String, u16)>) -> Self { pub fn new(path: PathBuf, info: EndpointInfo, cache: PageCache, embeddable_on: Embeddable) -> Self {
LocalPageEndpoint { LocalPageEndpoint {
path: path, path: path,
mime: None, mime: None,

View File

@ -19,27 +19,24 @@
use endpoint::{Endpoint, Handler, EndpointPath}; use endpoint::{Endpoint, Handler, EndpointPath};
use handlers::ContentHandler; use handlers::ContentHandler;
use apps::HOME_PAGE; use apps::HOME_PAGE;
use address; use {address, Embeddable};
pub struct ProxyPac { pub struct ProxyPac {
signer_address: Option<(String, u16)>, embeddable: Embeddable,
dapps_domain: String, dapps_domain: String,
} }
impl ProxyPac { impl ProxyPac {
pub fn boxed(signer_address: Option<(String, u16)>, dapps_domain: String) -> Box<Endpoint> { pub fn boxed(embeddable: Embeddable, dapps_domain: String) -> Box<Endpoint> {
Box::new(ProxyPac { Box::new(ProxyPac { embeddable, dapps_domain })
signer_address: signer_address,
dapps_domain: dapps_domain,
})
} }
} }
impl Endpoint for ProxyPac { impl Endpoint for ProxyPac {
fn to_handler(&self, path: EndpointPath) -> Box<Handler> { fn to_handler(&self, path: EndpointPath) -> Box<Handler> {
let signer = self.signer_address let ui = self.embeddable
.as_ref() .as_ref()
.map(address) .map(|ref parent| address(&parent.host, parent.port))
.unwrap_or_else(|| format!("{}:{}", path.host, path.port)); .unwrap_or_else(|| format!("{}:{}", path.host, path.port));
let content = format!( let content = format!(
@ -58,7 +55,7 @@ function FindProxyForURL(url, host) {{
return "DIRECT"; return "DIRECT";
}} }}
"#, "#,
HOME_PAGE, self.dapps_domain, path.host, path.port, signer); HOME_PAGE, self.dapps_domain, path.host, path.port, ui);
Box::new(ContentHandler::ok(content, mime!(Application/Javascript))) Box::new(ContentHandler::ok(content, mime!(Application/Javascript)))
} }

View File

@ -30,6 +30,7 @@ use apps;
use apps::fetcher::Fetcher; use apps::fetcher::Fetcher;
use endpoint::{Endpoint, Endpoints, EndpointPath, Handler}; use endpoint::{Endpoint, Endpoints, EndpointPath, Handler};
use handlers; use handlers;
use Embeddable;
/// Special endpoints are accessible on every domain (every dapp) /// Special endpoints are accessible on every domain (every dapp)
#[derive(Debug, PartialEq, Hash, Eq)] #[derive(Debug, PartialEq, Hash, Eq)]
@ -45,7 +46,7 @@ pub struct Router {
endpoints: Option<Endpoints>, endpoints: Option<Endpoints>,
fetch: Arc<Fetcher>, fetch: Arc<Fetcher>,
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>, special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
embeddable_on: Option<(String, u16)>, embeddable_on: Embeddable,
dapps_domain: String, dapps_domain: String,
} }
@ -148,7 +149,7 @@ impl Router {
content_fetcher: Arc<Fetcher>, content_fetcher: Arc<Fetcher>,
endpoints: Option<Endpoints>, endpoints: Option<Endpoints>,
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>, special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
embeddable_on: Option<(String, u16)>, embeddable_on: Embeddable,
dapps_domain: String, dapps_domain: String,
) -> Self { ) -> Self {
Router { Router {

View File

@ -259,6 +259,7 @@ impl Server {
CpuPool::new(4), CpuPool::new(4),
remote, remote,
signer_address, signer_address,
vec![],
dapps_path, dapps_path,
extra_dapps, extra_dapps,
DAPPS_DOMAIN.into(), DAPPS_DOMAIN.into(),

View File

@ -31,9 +31,7 @@ use handlers::{
StreamingHandler, extract_url, StreamingHandler, extract_url,
}; };
use url::Url; use url::Url;
use WebProxyTokens; use {Embeddable, WebProxyTokens};
pub type Embeddable = Option<(String, u16)>;
pub struct Web<F> { pub struct Web<F> {
embeddable_on: Embeddable, embeddable_on: Embeddable,
@ -43,12 +41,17 @@ pub struct Web<F> {
} }
impl<F: Fetch> Web<F> { impl<F: Fetch> Web<F> {
pub fn boxed(embeddable_on: Embeddable, web_proxy_tokens: Arc<WebProxyTokens>, remote: Remote, fetch: F) -> Box<Endpoint> { pub fn boxed(
embeddable_on: Embeddable,
web_proxy_tokens: Arc<WebProxyTokens>,
remote: Remote,
fetch: F,
) -> Box<Endpoint> {
Box::new(Web { Box::new(Web {
embeddable_on: embeddable_on, embeddable_on,
web_proxy_tokens: web_proxy_tokens, web_proxy_tokens,
remote: remote, remote,
fetch: fetch, fetch,
}) })
} }
} }

View File

@ -102,12 +102,7 @@ pub fn request(address: &SocketAddr, request: &str) -> Response {
/// Check if all required security headers are present /// Check if all required security headers are present
pub fn assert_security_headers_present(headers: &[String], port: Option<u16>) { pub fn assert_security_headers_present(headers: &[String], port: Option<u16>) {
if let Some(port) = port { if let None = port {
assert!(
headers.iter().find(|header| header.as_str() == &format!("X-Frame-Options: ALLOW-FROM http://127.0.0.1:{}", port)).is_some(),
"X-Frame-Options: ALLOW-FROM missing: {:?}", headers
);
} else {
assert!( assert!(
headers.iter().find(|header| header.as_str() == "X-Frame-Options: SAMEORIGIN").is_some(), headers.iter().find(|header| header.as_str() == "X-Frame-Options: SAMEORIGIN").is_some(),
"X-Frame-Options: SAMEORIGIN missing: {:?}", headers "X-Frame-Options: SAMEORIGIN missing: {:?}", headers

View File

@ -16,6 +16,7 @@ bloomchain = "0.1"
bn = { git = "https://github.com/paritytech/bn" } bn = { git = "https://github.com/paritytech/bn" }
byteorder = "1.0" byteorder = "1.0"
clippy = { version = "0.0.103", optional = true} clippy = { version = "0.0.103", optional = true}
common-types = { path = "types" }
crossbeam = "0.2.9" crossbeam = "0.2.9"
env_logger = "0.4" env_logger = "0.4"
ethabi = "2.0" ethabi = "2.0"
@ -31,7 +32,7 @@ ethcore-util = { path = "../util" }
ethjson = { path = "../json" } ethjson = { path = "../json" }
ethkey = { path = "../ethkey" } ethkey = { path = "../ethkey" }
ethstore = { path = "../ethstore" } ethstore = { path = "../ethstore" }
evmjit = { path = "../evmjit", optional = true } evm = { path = "evm" }
futures = "0.1" futures = "0.1"
hardware-wallet = { path = "../hw" } hardware-wallet = { path = "../hw" }
hyper = { git = "https://github.com/paritytech/hyper", default-features = false } hyper = { git = "https://github.com/paritytech/hyper", default-features = false }
@ -52,14 +53,12 @@ semver = "0.6"
stats = { path = "../util/stats" } stats = { path = "../util/stats" }
time = "0.1" time = "0.1"
transient-hashmap = "0.4" transient-hashmap = "0.4"
parity-wasm = "0.12"
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
[dev-dependencies] [dev-dependencies]
native-contracts = { path = "native_contracts", features = ["test_contracts"] } native-contracts = { path = "native_contracts", features = ["test_contracts"] }
[features] [features]
jit = ["evmjit"] jit = ["evm/jit"]
evm-debug = ["slow-blocks"] evm-debug = ["slow-blocks"]
evm-debug-tests = ["evm-debug"] evm-debug-tests = ["evm-debug"]
slow-blocks = [] # Use SLOW_TX_DURATION="50" (compile time!) to track transactions over 50ms 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; extern crate ethcore_ipc_codegen;
fn main() { 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/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/snapshot/snapshot_service_trait.rs", cfg!(feature="ipc")).unwrap();
ethcore_ipc_codegen::derive_ipc_cond("src/client/chain_notify.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::hash::{H256};
use util::sha3::{Hashable, SHA3_EMPTY}; use util::sha3::{Hashable, SHA3_EMPTY};
use ethjson; use ethjson;
use types::executed::CallType;
use {CallType};
use std::sync::Arc; use std::sync::Arc;

View File

@ -25,7 +25,7 @@ extern crate test;
use self::test::{Bencher, black_box}; use self::test::{Bencher, black_box};
use util::*; use util::*;
use action_params::ActionParams; use evm::action_params::ActionParams;
use evm::{self, Factory, VMType}; use evm::{self, Factory, VMType};
use evm::tests::FakeExt; 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::cmp;
use std::sync::Arc; use std::sync::Arc;
use util::{U256, Address, H256, Hashable}; use util::{U256, Address, H256, Hashable};
use header::BlockNumber; use types::BlockNumber;
use ethjson; use ethjson;
/// Simple vector of hashes, should be at most 256 items large, can be smaller if being used /// 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; use ethjson;
#[test] #[test]
fn it_serializes_form_json() { fn it_serializes_from_json() {
let env_info = EnvInfo::from(ethjson::vm::Env { let env_info = EnvInfo::from(ethjson::vm::Env {
author: ethjson::hash::Address(Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()), author: ethjson::hash::Address(Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()),
number: ethjson::uint::Uint(U256::from(1_112_339)), number: ethjson::uint::Uint(U256::from(1_112_339)),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,16 +16,41 @@
//! Ethereum virtual machine. //! 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 ext;
pub mod evm; pub mod evm;
pub mod interpreter; pub mod interpreter;
#[macro_use]
pub mod factory;
pub mod schedule; pub mod schedule;
pub mod wasm; pub mod wasm;
#[macro_use]
pub mod factory;
mod vmtype; mod vmtype;
mod instructions; mod instructions;
#[cfg(feature = "jit" )] #[cfg(feature = "jit" )]
mod jit; mod jit;
@ -34,10 +59,12 @@ mod tests;
#[cfg(all(feature="benches", test))] #[cfg(all(feature="benches", test))]
mod benches; 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::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType, ReturnData};
pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress}; pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
pub use self::instructions::{InstructionInfo, INSTRUCTIONS, push_bytes}; pub use self::instructions::{InstructionInfo, INSTRUCTIONS, push_bytes};
pub use self::vmtype::VMType; pub use self::vmtype::VMType;
pub use self::factory::Factory; pub use self::factory::Factory;
pub use self::schedule::{Schedule, CleanDustMode}; 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/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Cost schedule and other parameterisations for the EVM. //! Cost schedule and other parameterisations for the EVM.
use spec::CommonParams;
/// Definition of the cost schedule and other parameterisations for the EVM. /// Definition of the cost schedule and other parameterisations for the EVM.
pub struct Schedule { 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. /// Schedule for the Metropolis of the Ethereum main net.
pub fn new_metropolis() -> Schedule { pub fn new_metropolis() -> Schedule {
let mut schedule = Self::new_post_eip150(24576, true, true, true); let mut schedule = Self::new_post_eip150(24576, true, true, true);

View File

@ -19,13 +19,12 @@ use rustc_hex::FromHex;
use util::*; use util::*;
use action_params::{ActionParams, ActionValue}; use action_params::{ActionParams, ActionValue};
use env_info::EnvInfo; use env_info::EnvInfo;
use types::executed::CallType; use call_type::CallType;
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; use schedule::Schedule;
use tests::helpers::*; use evm::{self, GasLeft, ReturnData};
use types::transaction::SYSTEM_ADDRESS; use ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
use executive::Executive; use factory::Factory;
use state::Substate; use vmtype::VMType;
use trace::{NoopVMTracer, NoopTracer};
pub struct FakeLogEntry { pub struct FakeLogEntry {
topics: Vec<H256>, topics: Vec<H256>,
@ -438,67 +437,6 @@ fn test_blockhash(factory: super::Factory) {
assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash); 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} evm_test!{test_calldataload: test_calldataload_jit, test_calldataload_int}
fn test_calldataload(factory: super::Factory) { fn test_calldataload(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();

View File

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

View File

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

View File

@ -18,10 +18,10 @@
use std::sync::{Weak, Arc}; use std::sync::{Weak, Arc};
use ethcore::block_import_error::BlockImportError;
use ethcore::block_status::BlockStatus; use ethcore::block_status::BlockStatus;
use ethcore::client::{ClientReport, EnvInfo}; use ethcore::client::{ClientReport, EnvInfo};
use ethcore::engines::Engine; use ethcore::engines::Engine;
use ethcore::error::BlockImportError;
use ethcore::ids::BlockId; use ethcore::ids::BlockId;
use ethcore::header::Header; use ethcore::header::Header;
use ethcore::verification::queue::{self, HeaderQueue}; 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_network as network;
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate ethcore; extern crate ethcore;
extern crate evm;
extern crate futures; extern crate futures;
extern crate itertools; extern crate itertools;
extern crate rand; extern crate rand;

View File

@ -21,10 +21,10 @@ use std::sync::Arc;
use ethcore::basic_account::BasicAccount; use ethcore::basic_account::BasicAccount;
use ethcore::encoded; use ethcore::encoded;
use ethcore::engines::Engine; use ethcore::engines::Engine;
use ethcore::env_info::EnvInfo;
use ethcore::receipt::Receipt; use ethcore::receipt::Receipt;
use ethcore::state::{self, ProvedExecution}; use ethcore::state::{self, ProvedExecution};
use ethcore::transaction::SignedTransaction; use ethcore::transaction::SignedTransaction;
use evm::env_info::EnvInfo;
use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field}; 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::{BTreeMap, HashMap};
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use ethcore::error::TransactionError; use ethcore::error::{TransactionError, TransactionImportResult};
use ethcore::transaction::{Condition, PendingTransaction, SignedTransaction}; use ethcore::transaction::{Condition, PendingTransaction, SignedTransaction};
use ethcore::transaction_import::TransactionImportResult;
use util::{Address, U256, H256, H256FastMap}; use util::{Address, U256, H256, H256FastMap};
// Knowledge of an account's current nonce. // Knowledge of an account's current nonce.

View File

@ -64,7 +64,9 @@ pub enum SignError {
/// Low-level hardware device error. /// Low-level hardware device error.
Hardware(HardwareError), Hardware(HardwareError),
/// Low-level error from store /// Low-level error from store
SStore(SSError) SStore(SSError),
/// Inappropriate chain
InappropriateChain,
} }
impl fmt::Display for SignError { impl fmt::Display for SignError {
@ -74,6 +76,7 @@ impl fmt::Display for SignError {
SignError::NotFound => write!(f, "Account does not exist"), SignError::NotFound => write!(f, "Account does not exist"),
SignError::Hardware(ref e) => write!(f, "{}", e), SignError::Hardware(ref e) => write!(f, "{}", e),
SignError::SStore(ref e) => write!(f, "{}", e), SignError::SStore(ref e) => write!(f, "{}", e),
SignError::InappropriateChain => write!(f, "Inappropriate chain"),
} }
} }
} }

View File

@ -16,13 +16,11 @@
//! Ethcore basic typenames. //! Ethcore basic typenames.
use util::hash::H2048;
/// Type for a 2048-bit log-bloom, as used by our blocks. /// 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. /// 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))] #[cfg_attr(feature="dev", allow(enum_variant_names))]
/// Semantic boolean for when a seal/signature is included. /// 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 util::error::{Mismatch, OutOfBounds};
use basic_types::{LogBloom, Seal}; use basic_types::{LogBloom, Seal};
use env_info::{EnvInfo, LastHashes}; use evm::env_info::{EnvInfo, LastHashes};
use engines::Engine; use engines::Engine;
use error::{Error, BlockError, TransactionError}; use error::{Error, BlockError, TransactionError};
use factory::Factories; use factory::Factories;
@ -200,7 +200,7 @@ pub trait IsBlock {
/// Trait for a object that has a state database. /// Trait for a object that has a state database.
pub trait Drain { pub trait Drain {
/// Drop this object and return the underlieing database. /// Drop this object and return the underlying database.
fn drain(self) -> StateDB; 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`. /// Turn this into a `ClosedBlock`.
pub fn close(self) -> ClosedBlock { pub fn close(self) -> ClosedBlock {
let mut s = self; let mut s = self;
@ -579,18 +595,13 @@ pub fn enact(
is_epoch_begin, is_epoch_begin,
)?; )?;
b.set_difficulty(*header.difficulty()); b.populate_from(header);
b.set_gas_limit(*header.gas_limit()); b.push_transactions(transactions)?;
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());
push_transactions(&mut b, transactions)?;
for u in uncles { for u in uncles {
b.push_uncle(u.clone())?; b.push_uncle(u.clone())?;
} }
Ok(b.close_and_lock()) Ok(b.close_and_lock())
} }
@ -656,7 +667,7 @@ mod tests {
use tests::helpers::*; use tests::helpers::*;
use super::*; use super::*;
use engines::Engine; use engines::Engine;
use env_info::LastHashes; use evm::env_info::LastHashes;
use error::Error; use error::Error;
use header::Header; use header::Header;
use factory::Factories; use factory::Factories;
@ -681,7 +692,36 @@ mod tests {
let header = block.header(); let header = block.header();
let transactions: Result<Vec<_>, Error> = block.transactions().into_iter().map(SignedTransaction::new).collect(); let transactions: Result<Vec<_>, Error> = block.transactions().into_iter().map(SignedTransaction::new).collect();
let transactions = transactions?; 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 /// 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. /// Native implementation of a built-in contract.
pub trait Impl: Send + Sync { pub trait Impl: Send + Sync {
/// execute this built-in on the given input, writing to the given output. /// 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::collections::{HashSet, HashMap, BTreeMap, VecDeque};
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::fmt;
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant}; use std::time::{Instant};
use time::precise_time_ns; use time::precise_time_ns;
@ -43,8 +42,8 @@ use client::{
}; };
use encoded; use encoded;
use engines::{Engine, EpochTransition}; use engines::{Engine, EpochTransition};
use env_info::EnvInfo; use evm::env_info::EnvInfo;
use env_info::LastHashes; use evm::env_info::LastHashes;
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
use evm::{Factory as EvmFactory, Schedule}; use evm::{Factory as EvmFactory, Schedule};
use executive::{Executive, Executed, TransactOptions, contract_address}; 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 MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2;
const MIN_HISTORY_SIZE: u64 = 8; 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. /// Report on the status of a client.
#[derive(Default, Clone, Debug, Eq, PartialEq)] #[derive(Default, Clone, Debug, Eq, PartialEq)]
pub struct ClientReport { pub struct ClientReport {
@ -537,7 +530,7 @@ impl Client {
} else { } else {
imported_blocks.push(header.hash()); 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); import_results.push(route);
self.report.write().accrue_block(&block); self.report.write().accrue_block(&block);
@ -642,10 +635,14 @@ impl Client {
Ok(hash) Ok(hash)
} }
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &[u8]) -> ImportRoute where B: IsBlock + Drain { // NOTE: the header of the block passed here is not necessarily sealed, as
let number = block.header().number(); // it is for reconstructing the state transition.
let parent = block.header().parent_hash().clone(); //
let header = block.header().clone(); // TODO: optimize and avoid copy. // 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(); let chain = self.chain.read();
// Commit results // Commit results
@ -655,6 +652,8 @@ impl Client {
.map(Into::into) .map(Into::into)
.collect(); .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 traces = From::from(block.traces().clone().unwrap_or_else(Vec::new));
let mut batch = DBTransaction::new(); let mut batch = DBTransaction::new();
@ -664,6 +663,17 @@ impl Client {
// TODO: Prove it with a test. // TODO: Prove it with a test.
let mut state = block.drain(); 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"); state.journal_under(&mut batch, number, hash).expect("DB commit failed");
let route = chain.insert_block(&mut batch, block_data, receipts.clone()); let route = chain.insert_block(&mut batch, block_data, receipts.clone());
@ -681,10 +691,6 @@ impl Client {
self.db.read().write_buffered(batch); self.db.read().write_buffered(batch);
chain.commit(); 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.check_epoch_end(&header, &chain);
self.update_last_hashes(&parent, hash); self.update_last_hashes(&parent, hash);
@ -698,38 +704,82 @@ impl Client {
// check for epoch end signal and write pending transition if it occurs. // check for epoch end signal and write pending transition if it occurs.
// state for the given block must be available. // 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; use engines::EpochChange;
let hash = header.hash(); 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) => { EpochChange::Yes(proof) => {
use engines::epoch::PendingTransition; use engines::epoch::PendingTransition;
use engines::Proof; use engines::Proof;
let proof = match proof { let proof = match proof {
Proof::Known(proof) => proof, Proof::Known(proof) => proof,
Proof::WithState(with_state) => Proof::WithState(with_state) => {
match self.with_proving_caller(BlockId::Hash(hash), move |c| with_state(c)) { 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, Ok(proof) => proof,
Err(e) => { Err(e) => {
warn!(target: "client", "Failed to generate transition proof for block {}: {}", hash, e); warn!(target: "client", "Failed to generate transition proof for block {}: {}", hash, e);
warn!(target: "client", "Snapshots produced by this client may be incomplete"); warn!(target: "client", "Snapshots produced by this client may be incomplete");
Vec::new() Vec::new()
} }
}, }
}
}; };
debug!(target: "client", "Block {} signals epoch end.", hash); debug!(target: "client", "Block {} signals epoch end.", hash);
// write pending transition to DB.
let mut batch = DBTransaction::new();
let pending = PendingTransition { proof: proof }; let pending = PendingTransition { proof: proof };
chain.insert_pending_transition(&mut batch, hash, pending); chain.insert_pending_transition(batch, hash, pending);
self.db.read().write_buffered(batch);
}, },
EpochChange::No => {}, EpochChange::No => {},
EpochChange::Unsure(_) => { EpochChange::Unsure(_) => {
@ -756,7 +806,11 @@ impl Client {
block_number: header.number(), block_number: header.number(),
proof: proof, 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 number = block.header().number();
let block_data = block.rlp_bytes(); 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); trace!(target: "client", "Imported sealed block #{} ({})", number, h);
self.state_db.lock().sync_cache(&route.enacted, &route.retracted, false); self.state_db.lock().sync_cache(&route.enacted, &route.retracted, false);
route route

View File

@ -17,14 +17,16 @@
use std::str::FromStr; use std::str::FromStr;
use std::path::Path; use std::path::Path;
use std::fmt::{Display, Formatter, Error as FmtError}; 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 std::time::Duration;
pub use blockchain::Config as BlockChainConfig; pub use blockchain::Config as BlockChainConfig;
pub use trace::Config as TraceConfig; pub use trace::Config as TraceConfig;
pub use evm::VMType; pub use evm::VMType;
use verification::{VerifierType, QueueConfig};
use util::{journaldb, CompactionProfile};
/// Client state db compaction profile /// Client state db compaction profile
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum DatabaseCompactionProfile { 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. /// Client configuration. Includes configs for all sub-systems.
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default)]
pub struct ClientConfig { pub struct ClientConfig {

View File

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

View File

@ -40,11 +40,9 @@ pub use types::pruning_info::PruningInfo;
pub use types::call_analytics::CallAnalytics; pub use types::call_analytics::CallAnalytics;
pub use executive::{Executed, Executive, TransactOptions}; 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 error::{BlockImportError, TransactionImportError, TransactionImportResult};
pub use transaction_import::TransactionImportResult;
pub use transaction_import::TransactionImportError;
pub use verification::VerifierType; pub use verification::VerifierType;
/// IPC interfaces /// IPC interfaces

View File

@ -15,24 +15,27 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::BTreeMap; 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 block::{OpenBlock, SealedBlock, ClosedBlock};
use header::{BlockNumber}; use blockchain::TreeRoute;
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction}; use encoded;
use transaction_import::TransactionImportResult; use evm::env_info::LastHashes;
use log_entry::LocalizedLogEntry;
use filter::Filter;
use error::{ImportResult, CallError, Error as EthcoreError}; use error::{ImportResult, CallError, Error as EthcoreError};
use receipt::LocalizedReceipt; use error::{TransactionImportResult, BlockImportError};
use trace::LocalizedTrace;
use evm::{Factory as EvmFactory, Schedule}; use evm::{Factory as EvmFactory, Schedule};
use executive::Executed; use executive::Executed;
use env_info::LastHashes; use filter::Filter;
use block_import_error::BlockImportError; use header::{BlockNumber};
use ipc::IpcConfig; 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::ids::*;
use types::basic_account::BasicAccount; use types::basic_account::BasicAccount;
use types::trace_filter::Filter as TraceFilter; use types::trace_filter::Filter as TraceFilter;
@ -41,7 +44,6 @@ use types::blockchain_info::BlockChainInfo;
use types::block_status::BlockStatus; use types::block_status::BlockStatus;
use types::mode::Mode; use types::mode::Mode;
use types::pruning_info::PruningInfo; use types::pruning_info::PruningInfo;
use encoded;
#[ipc(client_ident="RemoteClient")] #[ipc(client_ident="RemoteClient")]
/// Blockchain database client. Owns and manages a blockchain and a block queue. /// 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); let entry = self.sign_count.entry(signer);
if let (true, &Entry::Vacant(_)) = (would_be_finalized, &entry) { if let (true, &Entry::Vacant(_)) = (would_be_finalized, &entry) {
trace!(target: "finality", "Encountered already finalized block {}", hash);
break break
} }
@ -75,6 +76,7 @@ impl RollingFinality {
self.headers.push_front((hash, signer)); self.headers.push_front((hash, signer));
} }
trace!(target: "finality", "Rolling finality state: {:?}", self.headers);
Ok(()) Ok(())
} }
@ -128,6 +130,9 @@ impl RollingFinality {
} }
} }
trace!(target: "finality", "Blocks finalized by {:?}: {:?}", head, newly_finalized);
self.last_pushed = Some(head);
Ok(newly_finalized) Ok(newly_finalized)
} }
} }

View File

@ -220,9 +220,9 @@ pub struct AuthorityRound {
builtins: BTreeMap<Address, Builtin>, builtins: BTreeMap<Address, Builtin>,
transition_service: IoService<()>, transition_service: IoService<()>,
step: Arc<Step>, step: Arc<Step>,
proposed: AtomicBool, can_propose: AtomicBool,
client: RwLock<Option<Weak<EngineClient>>>, client: RwLock<Option<Weak<EngineClient>>>,
signer: EngineSigner, signer: RwLock<EngineSigner>,
validators: Box<ValidatorSet>, validators: Box<ValidatorSet>,
validate_score_transition: u64, validate_score_transition: u64,
eip155_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. // Give one step slack if step is lagging, double vote is still not possible.
if step.is_future(header_step) { 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())); report(Report::Benign(*header.author(), header.number()));
Err(BlockError::InvalidSeal)? Err(BlockError::InvalidSeal)?
} else { } 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())?; !verify_address(&correct_proposer, &proposer_signature, &header.bare_hash())?;
if is_invalid_proposer { 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() }))? Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
} else { } else {
Ok(()) Ok(())
@ -372,7 +372,7 @@ impl AuthorityRound {
calibrate: our_params.start_step.is_none(), calibrate: our_params.start_step.is_none(),
duration: our_params.step_duration, duration: our_params.step_duration,
}), }),
proposed: AtomicBool::new(false), can_propose: AtomicBool::new(true),
client: RwLock::new(None), client: RwLock::new(None),
signer: Default::default(), signer: Default::default(),
validators: our_params.validators, validators: our_params.validators,
@ -439,7 +439,7 @@ impl Engine for AuthorityRound {
fn step(&self) { fn step(&self) {
self.step.increment(); 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(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() { if let Some(c) = weak.upgrade() {
c.update_sealing(); c.update_sealing();
@ -471,7 +471,7 @@ impl Engine for AuthorityRound {
} }
fn seals_internally(&self) -> Option<bool> { fn seals_internally(&self) -> Option<bool> {
Some(self.signer.address() != Address::default()) Some(self.signer.read().is_some())
} }
/// Attempt to seal the block internally. /// Attempt to seal the block internally.
@ -481,7 +481,7 @@ impl Engine for AuthorityRound {
fn generate_seal(&self, block: &ExecutedBlock) -> Seal { fn generate_seal(&self, block: &ExecutedBlock) -> Seal {
// first check to avoid generating signature most of the time // first check to avoid generating signature most of the time
// (but there's still a race to the `compare_and_swap`) // (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 header = block.header();
let step = self.step.load(); 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 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); 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. // 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()]); return Seal::Regular(vec![encode(&step).into_vec(), encode(&(&H520::from(signature) as &[u8])).into_vec()]);
} }
} else { } else {
@ -532,7 +532,7 @@ impl Engine for AuthorityRound {
fn on_new_block( fn on_new_block(
&self, &self,
block: &mut ExecutedBlock, block: &mut ExecutedBlock,
last_hashes: Arc<::env_info::LastHashes>, last_hashes: Arc<::evm::env_info::LastHashes>,
epoch_begin: bool, epoch_begin: bool,
) -> Result<(), Error> { ) -> Result<(), Error> {
let parent_hash = block.fields().header.parent_hash().clone(); let parent_hash = block.fields().header.parent_hash().clone();
@ -614,16 +614,18 @@ impl Engine for AuthorityRound {
Err(EngineError::DoubleVote(header.author().clone()))?; Err(EngineError::DoubleVote(header.author().clone()))?;
} }
// Report skipped primaries. // Report skipped primaries.
if step > parent_step + 1 { if let (true, Some(me)) = (step > parent_step + 1, self.signer.read().address()) {
// TODO: use epochmanager to get correct validator set for reporting? debug!(target: "engine", "Author {} built block with step gap. current step: {}, parent step: {}",
// 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: {}",
header.author(), step, parent_step); header.author(), step, parent_step);
let mut reported = HashSet::new();
for s in parent_step + 1..step { for s in parent_step + 1..step {
let skipped_primary = step_proposer(&*self.validators, &parent.hash(), s); let skipped_primary = step_proposer(&*self.validators, &parent.hash(), s);
self.validators.report_benign(&skipped_primary, header.number(), header.number()); // 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; }
} }
} }
@ -723,6 +725,9 @@ impl Engine for AuthorityRound {
if epoch_manager.finality_checker.subchain_head() != Some(*chain_head.parent_hash()) { if epoch_manager.finality_checker.subchain_head() != Some(*chain_head.parent_hash()) {
// build new finality checker from ancestry of chain head, // build new finality checker from ancestry of chain head,
// not including chain head itself yet. // 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 mut hash = chain_head.parent_hash().clone();
let epoch_transition_hash = epoch_manager.epoch_transition_hash; let epoch_transition_hash = epoch_manager.epoch_transition_hash;
@ -734,6 +739,8 @@ impl Engine for AuthorityRound {
if header.number() == 0 { return None } if header.number() == 0 { return None }
let res = (hash, header.author().clone()); let res = (hash, header.author().clone());
trace!(target: "finality", "Ancestry iteration: yielding {:?}", res);
hash = header.parent_hash().clone(); hash = header.parent_hash().clone();
Some(res) Some(res)
}) })
@ -766,6 +773,16 @@ impl Engine for AuthorityRound {
let finality_proof = ::rlp::encode_list(&finality_proof); let finality_proof = ::rlp::encode_list(&finality_proof);
epoch_manager.note_new_epoch(); 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)); 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) { 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> { 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>> { 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_gas_limit(U256::from_str("222222").unwrap());
header.set_seal(vec![encode(&3usize).into_vec()]); 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!(aura.verify_block_family(&header, &parent_header, None).is_ok());
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1); assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1);
} }

View File

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

View File

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

View File

@ -16,21 +16,21 @@
//! A signer used by Engines which need to sign messages. //! 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 ethkey::Signature;
use account_provider::{self, AccountProvider}; use account_provider::{self, AccountProvider};
/// Everything that an Engine needs to sign messages. /// Everything that an Engine needs to sign messages.
pub struct EngineSigner { pub struct EngineSigner {
account_provider: Mutex<Arc<AccountProvider>>, account_provider: Arc<AccountProvider>,
address: RwLock<Address>, address: Option<Address>,
password: RwLock<Option<String>>, password: Option<String>,
} }
impl Default for EngineSigner { impl Default for EngineSigner {
fn default() -> Self { fn default() -> Self {
EngineSigner { EngineSigner {
account_provider: Mutex::new(Arc::new(AccountProvider::transient_provider())), account_provider: Arc::new(AccountProvider::transient_provider()),
address: Default::default(), address: Default::default(),
password: Default::default(), password: Default::default(),
} }
@ -39,25 +39,30 @@ impl Default for EngineSigner {
impl EngineSigner { impl EngineSigner {
/// Set up the signer to sign with given address and password. /// Set up the signer to sign with given address and password.
pub fn set(&self, ap: Arc<AccountProvider>, address: Address, password: String) { pub fn set(&mut self, ap: Arc<AccountProvider>, address: Address, password: String) {
*self.account_provider.lock() = ap; self.account_provider = ap;
*self.address.write() = address; self.address = Some(address);
*self.password.write() = Some(password); self.password = Some(password);
debug!(target: "poa", "Setting Engine signer to {}", address); debug!(target: "poa", "Setting Engine signer to {}", address);
} }
/// Sign a consensus message hash. /// Sign a consensus message hash.
pub fn sign(&self, hash: H256) -> Result<Signature, account_provider::SignError> { 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. /// Signing address.
pub fn address(&self) -> Address { pub fn address(&self) -> Option<Address> {
self.address.read().clone() self.address.clone()
} }
/// Check if the given address is the signing address. /// Check if the given address is the signing address.
pub fn is_address(&self, address: &Address) -> bool { 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. /// Vote accumulator.
votes: VoteCollector<ConsensusMessage>, votes: VoteCollector<ConsensusMessage>,
/// Used to sign messages and proposals. /// Used to sign messages and proposals.
signer: EngineSigner, signer: RwLock<EngineSigner>,
/// Message for the last PoLC. /// Message for the last PoLC.
lock_change: RwLock<Option<ConsensusMessage>>, lock_change: RwLock<Option<ConsensusMessage>>,
/// Last lock view. /// Last lock view.
@ -159,19 +159,22 @@ impl Tendermint {
let r = self.view.load(AtomicOrdering::SeqCst); let r = self.view.load(AtomicOrdering::SeqCst);
let s = *self.step.read(); let s = *self.step.read();
let vote_info = message_info_rlp(&VoteStep::new(h, r, s), block_hash); let vote_info = message_info_rlp(&VoteStep::new(h, r, s), block_hash);
match self.signer.sign(vote_info.sha3()).map(Into::into) { match (self.signer.read().address(), self.sign(vote_info.sha3()).map(Into::into)) {
Ok(signature) => { (Some(validator), Ok(signature)) => {
let message_rlp = message_full_rlp(&signature, &vote_info); let message_rlp = message_full_rlp(&signature, &vote_info);
let message = ConsensusMessage::new(signature, h, r, s, block_hash); let message = ConsensusMessage::new(signature, h, r, s, block_hash);
let validator = self.signer.address();
self.votes.vote(message.clone(), &validator); self.votes.vote(message.clone(), &validator);
debug!(target: "engine", "Generated {:?} as {}.", message, validator); debug!(target: "engine", "Generated {:?} as {}.", message, validator);
self.handle_valid_message(&message); self.handle_valid_message(&message);
Some(message_rlp) Some(message_rlp)
}, },
Err(e) => { (None, _) => {
trace!(target: "engine", "Could not sign the message {}", e); 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 None
}, },
} }
@ -272,7 +275,7 @@ impl Tendermint {
/// Check if current signer is the current proposer. /// Check if current signer is the current proposer.
fn is_signer_proposer(&self, bh: &H256) -> bool { fn is_signer_proposer(&self, bh: &H256) -> bool {
let proposer = self.view_proposer(bh, self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst)); 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 { fn is_height(&self, message: &ConsensusMessage) -> bool {
@ -420,7 +423,7 @@ impl Engine for Tendermint {
/// Should this node participate. /// Should this node participate.
fn seals_internally(&self) -> Option<bool> { 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. /// Attempt to seal generate a proposal seal.
@ -436,7 +439,7 @@ impl Engine for Tendermint {
let view = self.view.load(AtomicOrdering::SeqCst); let view = self.view.load(AtomicOrdering::SeqCst);
let bh = Some(header.bare_hash()); let bh = Some(header.bare_hash());
let vote_info = message_info_rlp(&VoteStep::new(height, view, Step::Propose), bh.clone()); 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. // Insert Propose vote.
debug!(target: "engine", "Submitting proposal {} at height {} view {}.", header.bare_hash(), height, view); 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); 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) { 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); self.to_step(Step::Propose);
} }
fn sign(&self, hash: H256) -> Result<Signature, Error> { 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) { fn stop(&self) {
@ -901,7 +904,7 @@ mod tests {
#[test] #[test]
fn seal_submission() { fn seal_submission() {
use ethkey::{Generator, Random}; use ethkey::{Generator, Random};
use types::transaction::{Transaction, Action}; use transaction::{Transaction, Action};
use client::BlockChainClient; use client::BlockChainClient;
let tap = Arc::new(AccountProvider::transient_provider()); 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", trace!(target: "engine", "obtained proof for initial set: {} validators, {} bytes",
validators.len(), proof.len()); validators.len(), proof.len());
info!(target: "engine", "Signal for switch to contract-based validator set.");
info!(target: "engine", "Initial contract validators: {:?}", validators);
proof proof
}) })
} }
@ -231,9 +234,7 @@ impl ValidatorSet for ValidatorSafeContract {
.map(|out| (out, Vec::new()))) // generate no proofs in general .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> { 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.
self.provider.finalize_change(caller) self.provider.finalize_change(caller)
.wait() .wait()
.map_err(::engines::EngineError::FailedSystemCall) .map_err(::engines::EngineError::FailedSystemCall)
@ -271,8 +272,9 @@ impl ValidatorSet for ValidatorSafeContract {
None => ::engines::EpochChange::Unsure(::engines::Unsure::NeedsReceipts), None => ::engines::EpochChange::Unsure(::engines::Unsure::NeedsReceipts),
Some(receipts) => match self.extract_from_event(bloom, header, receipts) { Some(receipts) => match self.extract_from_event(bloom, header, receipts) {
None => ::engines::EpochChange::No, None => ::engines::EpochChange::No,
Some(_) => { Some(list) => {
debug!(target: "engine", "signalling transition within contract"); info!(target: "engine", "Signal for transition within contract. New list: {:?}",
&*list);
let proof = encode_proof(&header, receipts); let proof = encode_proof(&header, receipts);
::engines::EpochChange::Yes(::engines::Proof::Known(proof)) ::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_header, state_items) = decode_first_proof(&rlp)?;
let old_hash = old_header.hash(); let old_hash = old_header.hash();
let env_info = ::env_info::EnvInfo { let env_info = ::evm::env_info::EnvInfo {
number: old_header.number(), number: old_header.number(),
author: *old_header.author(), author: *old_header.author(),
difficulty: *old_header.difficulty(), difficulty: *old_header.difficulty(),

View File

@ -22,13 +22,12 @@ use header::BlockNumber;
use basic_types::LogBloom; use basic_types::LogBloom;
use client::Error as ClientError; use client::Error as ClientError;
use ipc::binary::{BinaryConvertError, BinaryConvertable}; use ipc::binary::{BinaryConvertError, BinaryConvertable};
use types::block_import_error::BlockImportError;
use snapshot::Error as SnapshotError; use snapshot::Error as SnapshotError;
use engines::EngineError; use engines::EngineError;
use ethkey::Error as EthkeyError; use ethkey::Error as EthkeyError;
use account_provider::SignError as AccountsError; use account_provider::SignError as AccountsError;
pub use types::executed::{ExecutionError, CallError}; pub use executed::{ExecutionError, CallError};
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
/// Errors concerning transaction processing. /// Errors concerning transaction processing.
@ -239,6 +238,53 @@ impl fmt::Display for ImportError {
f.write_fmt(format_args!("Block import error ({})", msg)) 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)] #[derive(Debug)]
/// General error type which should be capable of representing all errors in ethcore. /// 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 util::*;
use block::*; use block::*;
use builtin::Builtin; use builtin::Builtin;
use env_info::EnvInfo; use evm::env_info::EnvInfo;
use error::{BlockError, Error, TransactionError}; use error::{BlockError, Error, TransactionError};
use header::{Header, BlockNumber}; use header::{Header, BlockNumber};
use state::CleanupMode; use state::CleanupMode;
@ -29,7 +29,7 @@ use engines::{self, Engine};
use evm::Schedule; use evm::Schedule;
use ethjson; use ethjson;
use rlp::{self, UntrustedRlp}; 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 /// Parity tries to round block.gas_limit to multiple of this constant
pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]); 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.eip160_transition,
block_number >= self.ethash_params.eip161abc_transition, block_number >= self.ethash_params.eip161abc_transition,
block_number >= self.ethash_params.eip161d_transition); block_number >= self.ethash_params.eip161d_transition);
schedule.apply_params(block_number, self.params());
self.params().update_schedule(block_number, &mut schedule);
schedule schedule
} }
} }
@ -1027,7 +1028,7 @@ mod tests {
#[test] #[test]
fn rejects_transactions_below_min_gas_price() { fn rejects_transactions_below_min_gas_price() {
use ethkey::{Generator, Random}; use ethkey::{Generator, Random};
use types::transaction::{Transaction, Action}; use transaction::{Transaction, Action};
let spec = new_homestead_test(); let spec = new_homestead_test();
let mut ethparams = get_default_ethash_params(); let mut ethparams = get_default_ethash_params();

View File

@ -17,58 +17,15 @@
//! Transaction execution format module. //! Transaction execution format module.
use util::{Bytes, U256, Address, U512, trie}; use util::{Bytes, U256, Address, U512, trie};
use rlp::*;
use evm; use evm;
use trace::{VMTrace, FlatTrace}; use trace::{VMTrace, FlatTrace};
use types::log_entry::LogEntry; use log_entry::LogEntry;
use types::state_diff::StateDiff; use state_diff::StateDiff;
use std::fmt; 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. /// Transaction execution receipt.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Executed { pub struct Executed {
/// True if the outer call/create resulted in an exceptional exit. /// True if the outer call/create resulted in an exceptional exit.
pub exception: Option<evm::Error>, pub exception: Option<evm::Error>,
@ -112,7 +69,6 @@ pub struct Executed {
/// Result of executing the transaction. /// Result of executing the transaction.
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub enum ExecutionError { pub enum ExecutionError {
/// Returned when there gas paid for transaction execution is /// Returned when there gas paid for transaction execution is
/// lower than base gas required. /// lower than base gas required.
@ -192,7 +148,6 @@ impl fmt::Display for ExecutionError {
/// Result of executing the transaction. /// Result of executing the transaction.
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub enum CallError { pub enum CallError {
/// Couldn't find the transaction in the chain. /// Couldn't find the transaction in the chain.
TransactionNotFound, TransactionNotFound,
@ -230,29 +185,3 @@ impl fmt::Display for CallError {
/// Transaction execution result. /// Transaction execution result.
pub type ExecutionResult = Result<Executed, ExecutionError>; 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. //! Transaction Execution environment.
use util::*; use util::*;
use action_params::{ActionParams, ActionValue}; use evm::action_params::{ActionParams, ActionValue};
use state::{Backend as StateBackend, State, Substate, CleanupMode}; use state::{Backend as StateBackend, State, Substate, CleanupMode};
use engines::Engine; use engines::Engine;
use types::executed::CallType; use evm::CallType;
use env_info::EnvInfo; use evm::env_info::EnvInfo;
use error::ExecutionError; use error::ExecutionError;
use evm::{self, wasm, Factory, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData, CleanDustMode}; use evm::{self, wasm, Factory, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData, CleanDustMode};
use externalities::*; use externalities::*;
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer}; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
use transaction::{Action, SignedTransaction}; use transaction::{Action, SignedTransaction};
use crossbeam; 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 /// 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) /// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132)
@ -602,8 +602,8 @@ mod tests {
use super::*; use super::*;
use util::{H256, U256, U512, Address, FromStr}; use util::{H256, U256, U512, Address, FromStr};
use util::bytes::BytesRef; use util::bytes::BytesRef;
use action_params::{ActionParams, ActionValue}; use evm::action_params::{ActionParams, ActionValue};
use env_info::EnvInfo; use evm::env_info::EnvInfo;
use evm::{Factory, VMType, CreateContractAddress}; use evm::{Factory, VMType, CreateContractAddress};
use error::ExecutionError; use error::ExecutionError;
use state::{Substate, CleanupMode}; use state::{Substate, CleanupMode};
@ -613,7 +613,7 @@ mod tests {
use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer}; use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer};
use transaction::{Action, Transaction}; use transaction::{Action, Transaction};
use types::executed::CallType; use evm::CallType;
#[test] #[test]
fn test_contract_address() { fn test_contract_address() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -804,9 +804,15 @@ impl MinerService for Miner {
// | Make sure to release the locks before calling that method. | // | Make sure to release the locks before calling that method. |
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
self.engine.set_signer(ap.clone(), address, password); self.engine.set_signer(ap.clone(), address, password);
Ok(())
} else {
warn!(target: "miner", "No account provider");
Err(AccountError::NotFound)
} }
} else {
warn!(target: "miner", "Cannot set engine signer on a PoW chain.");
Err(AccountError::InappropriateChain)
} }
Ok(())
} }
fn set_extra_data(&self, extra_data: Bytes) { fn set_extra_data(&self, extra_data: Bytes) {
@ -1085,6 +1091,10 @@ impl MinerService for Miner {
self.transaction_queue.read().last_nonce(address) self.transaction_queue.read().last_nonce(address)
} }
fn can_produce_work_package(&self) -> bool {
self.engine.seals_internally().is_none()
}
/// Update sealing if required. /// Update sealing if required.
/// Prepare the block and work if the Engine does not seal internally. /// Prepare the block and work if the Engine does not seal internally.
fn update_sealing(&self, chain: &MiningBlockChainClient) { fn update_sealing(&self, chain: &MiningBlockChainClient) {
@ -1113,7 +1123,7 @@ impl MinerService for Miner {
} }
} }
fn is_sealing(&self) -> bool { fn is_currently_sealing(&self) -> bool {
self.sealing_work.lock().queue.is_in_use() self.sealing_work.lock().queue.is_in_use()
} }
@ -1270,9 +1280,9 @@ mod tests {
use ethkey::{Generator, Random}; use ethkey::{Generator, Random};
use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult}; use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult};
use header::BlockNumber; use header::BlockNumber;
use types::transaction::{SignedTransaction, Transaction, PendingTransaction, Action}; use transaction::{SignedTransaction, Transaction, PendingTransaction, Action};
use spec::Spec; use spec::Spec;
use tests::helpers::{generate_dummy_client}; use tests::helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts};
#[test] #[test]
fn should_prepare_block_to_seal() { fn should_prepare_block_to_seal() {
@ -1440,4 +1450,22 @@ mod tests {
assert!(miner.pending_block().is_none()); assert!(miner.pending_block().is_none());
assert_eq!(client.chain_info().best_block_number, 4 as BlockNumber); assert_eq!(client.chain_info().best_block_number, 4 as BlockNumber);
} }
#[test]
fn should_fail_setting_engine_signer_on_pow() {
let spec = Spec::new_pow_test_spec;
let tap = Arc::new(AccountProvider::transient_provider());
let addr = tap.insert_account("1".sha3().into(), "").unwrap();
let client = generate_dummy_client_with_spec_and_accounts(spec, Some(tap.clone()));
assert!(match client.miner().set_engine_signer(addr, "".into()) { Err(AccountError::InappropriateChain) => true, _ => false })
}
#[test]
fn should_fail_setting_engine_signer_without_account_provider() {
let spec = Spec::new_instant;
let tap = Arc::new(AccountProvider::transient_provider());
let addr = tap.insert_account("1".sha3().into(), "").unwrap();
let client = generate_dummy_client_with_spec_and_accounts(spec, None);
assert!(match client.miner().set_engine_signer(addr, "".into()) { Err(AccountError::NotFound) => true, _ => false });
}
} }

View File

@ -136,6 +136,9 @@ pub trait MinerService : Send + Sync {
/// Called when blocks are imported to chain, updates transactions queue. /// Called when blocks are imported to chain, updates transactions queue.
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]);
/// PoW chain - can produce work package
fn can_produce_work_package(&self) -> bool;
/// New chain head event. Restart mining operation. /// New chain head event. Restart mining operation.
fn update_sealing(&self, chain: &MiningBlockChainClient); fn update_sealing(&self, chain: &MiningBlockChainClient);
@ -176,7 +179,7 @@ pub trait MinerService : Send + Sync {
fn last_nonce(&self, address: &Address) -> Option<U256>; fn last_nonce(&self, address: &Address) -> Option<U256>;
/// Is it currently sealing? /// Is it currently sealing?
fn is_sealing(&self) -> bool; fn is_currently_sealing(&self) -> bool;
/// Suggested gas price. /// Suggested gas price.
fn sensible_gas_price(&self) -> U256; fn sensible_gas_price(&self) -> U256;

View File

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

View File

@ -20,10 +20,10 @@ use rustc_hex::FromHex;
use super::genesis::Genesis; use super::genesis::Genesis;
use super::seal::Generic as GenericSeal; use super::seal::Generic as GenericSeal;
use action_params::{ActionValue, ActionParams}; use evm::action_params::{ActionValue, ActionParams};
use builtin::Builtin; use builtin::Builtin;
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT}; use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT};
use env_info::EnvInfo; use evm::env_info::EnvInfo;
use error::Error; use error::Error;
use ethereum; use ethereum;
use ethjson; use ethjson;
@ -36,7 +36,7 @@ use state_db::StateDB;
use state::{Backend, State, Substate}; use state::{Backend, State, Substate};
use state::backend::Basic as BasicBackend; use state::backend::Basic as BasicBackend;
use trace::{NoopTracer, NoopVMTracer}; use trace::{NoopTracer, NoopVMTracer};
use types::executed::CallType; use evm::CallType;
use util::*; use util::*;
/// Parameters common to all engines. /// Parameters common to all engines.
@ -87,6 +87,31 @@ pub struct CommonParams {
pub wasm: bool, 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 { impl From<ethjson::spec::Params> for CommonParams {
fn from(p: ethjson::spec::Params) -> Self { fn from(p: ethjson::spec::Params) -> Self {
CommonParams { CommonParams {
@ -451,6 +476,9 @@ impl Spec {
/// Create a new Spec with BasicAuthority which uses multiple validator sets changing with height. /// Create a new Spec with BasicAuthority which uses multiple validator sets changing with height.
/// Account with secrets "0".sha3() is the validator for block 1 and with "1".sha3() onwards. /// Account with secrets "0".sha3() is the validator for block 1 and with "1".sha3() onwards.
pub fn new_validator_multi() -> Self { load_bundled!("validator_multi") } pub fn new_validator_multi() -> Self { load_bundled!("validator_multi") }
/// Create a new spec for a PoW chain
pub fn new_pow_test_spec() -> Self { load_bundled!("ethereum/olympic") }
} }
#[cfg(test)] #[cfg(test)]

View File

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

View File

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

View File

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

View File

@ -22,21 +22,24 @@ mod db;
mod executive_tracer; mod executive_tracer;
mod import; mod import;
mod noop_tracer; 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::config::Config;
pub use self::db::TraceDB; 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::noop_tracer::{NoopTracer, NoopVMTracer};
pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer}; pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer};
pub use types::trace_types::filter::{Filter, AddressesFilter};
pub use self::import::ImportRequest; pub use self::import::ImportRequest;
pub use self::localized::LocalizedTrace; 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 util::{Bytes, Address, U256, H256, DBTransaction};
use self::trace::{Call, Create}; use self::trace::{Call, Create};
use action_params::ActionParams; use evm::action_params::ActionParams;
use header::BlockNumber; use header::BlockNumber;
/// This trait is used by executive to build traces. /// This trait is used by executive to build traces.

View File

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

View File

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

View File

@ -23,13 +23,12 @@ use util::sha3::Hashable;
use util::bloom::Bloomable; use util::bloom::Bloomable;
use basic_types::LogBloom; use basic_types::LogBloom;
use trace::flat::FlatTrace; use trace::flat::FlatTrace;
use types::trace_types::trace::{Action, Res}; use super::trace::{Action, Res};
/// Addresses filter. /// Addresses filter.
/// ///
/// Used to create bloom possibilities and match filters. /// Used to create bloom possibilities and match filters.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "ipc", binary)]
pub struct AddressesFilter { pub struct AddressesFilter {
list: Vec<Address> list: Vec<Address>
} }
@ -76,7 +75,6 @@ impl AddressesFilter {
} }
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "ipc", binary)]
/// Traces filter. /// Traces filter.
pub struct Filter { pub struct Filter {
/// Block range. /// Block range.
@ -143,7 +141,7 @@ mod tests {
use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide}; use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide};
use trace::flat::FlatTrace; use trace::flat::FlatTrace;
use trace::{Filter, AddressesFilter, TraceError}; use trace::{Filter, AddressesFilter, TraceError};
use types::executed::CallType; use evm::CallType;
#[test] #[test]
fn empty_trace_filter_bloom_possibilities() { 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. /// Parent and children indexes refer to positions in this vector.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct FlatTrace { pub struct FlatTrace {
/// Type of action performed by a transaction. /// Type of action performed by a transaction.
pub action: Action, pub action: Action,
@ -164,7 +163,7 @@ mod tests {
use rlp::*; use rlp::*;
use super::{FlatBlockTraces, FlatTransactionTraces, FlatTrace}; use super::{FlatBlockTraces, FlatTransactionTraces, FlatTrace};
use trace::trace::{Action, Res, CallResult, Call, Suicide}; use trace::trace::{Action, Res, CallResult, Call, Suicide};
use types::executed::CallType; use evm::CallType;
#[test] #[test]
fn encode_flat_transaction_traces() { fn encode_flat_transaction_traces() {

View File

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

View File

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

View File

@ -32,9 +32,8 @@ pub const UNSIGNED_SENDER: Address = ::util::H160([0xff; 20]);
/// System sender address for internal state updates. /// 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]); 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. /// Transaction action type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Action { pub enum Action {
/// Create creates new contract. /// Create creates new contract.
Create, Create,
@ -59,7 +58,6 @@ impl Decodable for Action {
/// Transaction activation condition. /// Transaction activation condition.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub enum Condition { pub enum Condition {
/// Valid at this block number or later. /// Valid at this block number or later.
Number(BlockNumber), Number(BlockNumber),
@ -70,7 +68,6 @@ pub enum Condition {
/// A set of information describing an externally-originating message call /// A set of information describing an externally-originating message call
/// or contract creation operation. /// or contract creation operation.
#[derive(Default, Debug, Clone, PartialEq, Eq)] #[derive(Default, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Transaction { pub struct Transaction {
/// Nonce. /// Nonce.
pub nonce: U256, pub nonce: U256,
@ -241,9 +238,8 @@ impl Transaction {
} }
} }
/// Signed transaction information. /// Signed transaction information without verified signature.
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct UnverifiedTransaction { pub struct UnverifiedTransaction {
/// Plain Transaction. /// Plain Transaction.
unsigned: Transaction, unsigned: Transaction,
@ -470,7 +466,6 @@ impl SignedTransaction {
/// Signed Transaction that is a part of canon blockchain. /// Signed Transaction that is a part of canon blockchain.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct LocalizedTransaction { pub struct LocalizedTransaction {
/// Signed part. /// Signed part.
pub signed: UnverifiedTransaction, pub signed: UnverifiedTransaction,
@ -511,7 +506,6 @@ impl Deref for LocalizedTransaction {
/// Queued transaction with additional information. /// Queued transaction with additional information.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct PendingTransaction { pub struct PendingTransaction {
/// Signed transaction data. /// Signed transaction data.
pub transaction: SignedTransaction, pub transaction: SignedTransaction,
@ -544,91 +538,97 @@ impl From<SignedTransaction> for PendingTransaction {
} }
} }
#[test] #[cfg(test)]
fn sender_test() { mod tests {
let t: UnverifiedTransaction = decode(&::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); use super::*;
assert_eq!(t.data, b""); use util::{Hashable, U256};
assert_eq!(t.gas, U256::from(0x5208u64));
assert_eq!(t.gas_price, U256::from(0x01u64)); #[test]
assert_eq!(t.nonce, U256::from(0x00u64)); fn sender_test() {
if let Action::Call(ref to) = t.action { let t: UnverifiedTransaction = decode(&::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
assert_eq!(*to, "095e7baea6a6c7c4c2dfeb977efac326af552d87".into()); assert_eq!(t.data, b"");
} else { panic!(); } assert_eq!(t.gas, U256::from(0x5208u64));
assert_eq!(t.value, U256::from(0x0au64)); assert_eq!(t.gas_price, U256::from(0x01u64));
assert_eq!(public_to_address(&t.recover_public().unwrap()), "0f65fe9276bc9a24ae7083ae28e2660ef72df99e".into()); assert_eq!(t.nonce, U256::from(0x00u64));
assert_eq!(t.network_id(), None); if let Action::Call(ref to) = t.action {
} assert_eq!(*to, "095e7baea6a6c7c4c2dfeb977efac326af552d87".into());
} else { panic!(); }
#[test] assert_eq!(t.value, U256::from(0x0au64));
fn signing() { assert_eq!(public_to_address(&t.recover_public().unwrap()), "0f65fe9276bc9a24ae7083ae28e2660ef72df99e".into());
use ethkey::{Random, Generator}; assert_eq!(t.network_id(), None);
}
let key = Random.generate().unwrap();
let t = Transaction { #[test]
action: Action::Create, fn signing() {
nonce: U256::from(42), use ethkey::{Random, Generator};
gas_price: U256::from(3000),
gas: U256::from(50_000), let key = Random.generate().unwrap();
value: U256::from(1), let t = Transaction {
data: b"Hello!".to_vec() action: Action::Create,
}.sign(&key.secret(), None); nonce: U256::from(42),
assert_eq!(Address::from(key.public().sha3()), t.sender()); gas_price: U256::from(3000),
assert_eq!(t.network_id(), None); gas: U256::from(50_000),
} value: U256::from(1),
data: b"Hello!".to_vec()
#[test] }.sign(&key.secret(), None);
fn fake_signing() { assert_eq!(Address::from(key.public().sha3()), t.sender());
let t = Transaction { assert_eq!(t.network_id(), None);
action: Action::Create, }
nonce: U256::from(42),
gas_price: U256::from(3000), #[test]
gas: U256::from(50_000), fn fake_signing() {
value: U256::from(1), let t = Transaction {
data: b"Hello!".to_vec() action: Action::Create,
}.fake_sign(Address::from(0x69)); nonce: U256::from(42),
assert_eq!(Address::from(0x69), t.sender()); gas_price: U256::from(3000),
assert_eq!(t.network_id(), None); gas: U256::from(50_000),
value: U256::from(1),
let t = t.clone(); data: b"Hello!".to_vec()
assert_eq!(Address::from(0x69), t.sender()); }.fake_sign(Address::from(0x69));
assert_eq!(t.network_id(), None); assert_eq!(Address::from(0x69), t.sender());
} assert_eq!(t.network_id(), None);
#[test] let t = t.clone();
fn should_recover_from_network_specific_signing() { assert_eq!(Address::from(0x69), t.sender());
use ethkey::{Random, Generator}; assert_eq!(t.network_id(), None);
let key = Random.generate().unwrap(); }
let t = Transaction {
action: Action::Create, #[test]
nonce: U256::from(42), fn should_recover_from_network_specific_signing() {
gas_price: U256::from(3000), use ethkey::{Random, Generator};
gas: U256::from(50_000), let key = Random.generate().unwrap();
value: U256::from(1), let t = Transaction {
data: b"Hello!".to_vec() action: Action::Create,
}.sign(&key.secret(), Some(69)); nonce: U256::from(42),
assert_eq!(Address::from(key.public().sha3()), t.sender()); gas_price: U256::from(3000),
assert_eq!(t.network_id(), Some(69)); gas: U256::from(50_000),
} value: U256::from(1),
data: b"Hello!".to_vec()
#[test] }.sign(&key.secret(), Some(69));
fn should_agree_with_vitalik() { assert_eq!(Address::from(key.public().sha3()), t.sender());
use rustc_hex::FromHex; assert_eq!(t.network_id(), Some(69));
}
let test_vector = |tx_data: &str, address: &'static str| {
let signed = decode(&FromHex::from_hex(tx_data).unwrap()); #[test]
let signed = SignedTransaction::new(signed).unwrap(); fn should_agree_with_vitalik() {
assert_eq!(signed.sender(), address.into()); use rustc_hex::FromHex;
flushln!("networkid: {:?}", signed.network_id());
}; let test_vector = |tx_data: &str, address: &'static str| {
let signed = decode(&FromHex::from_hex(tx_data).unwrap());
test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"); let signed = SignedTransaction::new(signed).unwrap();
test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112"); assert_eq!(signed.sender(), address.into());
test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be"); flushln!("networkid: {:?}", signed.network_id());
test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0"); };
test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554");
test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4"); test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce");
test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35"); test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112");
test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332"); test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be");
test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029"); test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0");
test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"); test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554");
test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4");
test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35");
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,
}
}
}

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