diff --git a/Cargo.lock b/Cargo.lock
index 8fdbfa351..a17bc4413 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -70,7 +70,6 @@ dependencies = [
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -149,15 +148,6 @@ dependencies = [
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "cookie"
-version = "0.1.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "cookie"
version = "0.2.4"
@@ -225,15 +215,13 @@ dependencies = [
[[package]]
name = "eth-secp256k1"
version = "0.5.4"
-source = "git+https://github.com/ethcore/rust-secp256k1#b6fdd43bbcf6d46adb72a92dd1632a0fc834cbf5"
+source = "git+https://github.com/ethcore/rust-secp256k1#a9a0b1be1f39560ca86e8fc8e55e205a753ff25c"
dependencies = [
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -388,9 +376,8 @@ dependencies = [
"eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)",
"ethcore-devtools 1.3.0",
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "igd 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "json-tests 0.1.0",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -401,12 +388,13 @@ dependencies = [
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.1.0",
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "table 0.1.0",
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "using_queue 0.1.0",
"vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -506,26 +494,6 @@ name = "httparse"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "hyper"
-version = "0.6.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cookie 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "language-tags 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "hyper"
version = "0.8.1"
@@ -579,10 +547,10 @@ dependencies = [
[[package]]
name = "igd"
-version = "0.4.2"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "hyper 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)",
"xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -609,14 +577,6 @@ dependencies = [
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "json-tests"
-version = "0.1.0"
-dependencies = [
- "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "jsonrpc-core"
version = "2.0.7"
@@ -647,11 +607,6 @@ dependencies = [
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "language-tags"
-version = "0.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "language-tags"
version = "0.2.2"
@@ -685,15 +640,6 @@ dependencies = [
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "mime"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "mime"
version = "0.2.0"
@@ -898,7 +844,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parity-dapps"
version = "0.3.0"
-source = "git+https://github.com/ethcore/parity-dapps-rs.git#8cc812c26c903cf5764ce0f4cc3f2a7c3ddb0dc2"
+source = "git+https://github.com/ethcore/parity-dapps-rs.git#8ce18c014d8b69fa31fb203b68ff240091d77a23"
dependencies = [
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1154,14 +1100,6 @@ dependencies = [
"nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "serde"
-version = "0.6.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "serde"
version = "0.7.9"
@@ -1253,6 +1191,10 @@ dependencies = [
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "table"
+version = "0.1.0"
+
[[package]]
name = "target_info"
version = "0.1.0"
@@ -1359,16 +1301,6 @@ name = "unicode-xid"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "url"
-version = "0.2.38"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "url"
version = "0.5.9"
@@ -1390,20 +1322,15 @@ dependencies = [
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "using_queue"
+version = "0.1.0"
+
[[package]]
name = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "uuid"
-version = "0.1.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "uuid"
version = "0.2.1"
diff --git a/README.md b/README.md
index d605fa87c..fa20af4d0 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,11 @@
# [Parity](https://ethcore.io/parity.html)
### Fast, light, and robust Ethereum implementation
-[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/trogdoro/xiki][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url]
+[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/ethcore/parity][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url]
+
+[Internal Documentation][doc-url]
+
+Be sure to check out [our wiki][wiki-url] for more information.
[travis-image]: https://travis-ci.org/ethcore/parity.svg?branch=master
[travis-url]: https://travis-ci.org/ethcore/parity
@@ -11,8 +15,8 @@
[gitter-url]: https://gitter.im/ethcore/parity?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg
[license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html
-
-[Internal Documentation](http://ethcore.github.io/parity/ethcore/index.html)
+[doc-url]: http://ethcore.github.io/parity/ethcore/index.html
+[wiki-url]: https://github.com/ethcore/parity/wiki
----
diff --git a/dapps/build.rs b/dapps/build.rs
index 2bef33059..0776c03ec 100644
--- a/dapps/build.rs
+++ b/dapps/build.rs
@@ -25,8 +25,8 @@ mod inner {
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
- let src = Path::new("./src/api/mod.rs.in");
- let dst = Path::new(&out_dir).join("mod.rs");
+ let src = Path::new("./src/api/types.rs.in");
+ let dst = Path::new(&out_dir).join("types.rs");
let mut registry = syntex::Registry::new();
diff --git a/dapps/src/api/api.rs b/dapps/src/api/api.rs
index 95b01d442..ab3632074 100644
--- a/dapps/src/api/api.rs
+++ b/dapps/src/api/api.rs
@@ -15,38 +15,16 @@
// along with Parity. If not, see .
use std::sync::Arc;
-use endpoint::{Endpoint, Endpoints, EndpointInfo, Handler, EndpointPath};
-
-use api::response::as_json;
+use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
+use api::types::{App, ApiError};
+use api::response::{as_json, as_json_error};
+use hyper::{server, net, Decoder, Encoder, Next};
+#[derive(Clone)]
pub struct RestApi {
endpoints: Arc,
}
-#[derive(Debug, PartialEq, Serialize, Deserialize)]
-pub struct App {
- pub id: String,
- pub name: String,
- pub description: String,
- pub version: String,
- pub author: String,
- #[serde(rename="iconUrl")]
- pub icon_url: String,
-}
-
-impl App {
- fn from_info(id: &str, info: &EndpointInfo) -> Self {
- App {
- id: id.to_owned(),
- name: info.name.to_owned(),
- description: info.description.to_owned(),
- version: info.version.to_owned(),
- author: info.author.to_owned(),
- icon_url: info.icon_url.to_owned(),
- }
- }
-}
-
impl RestApi {
pub fn new(endpoints: Arc) -> Box {
Box::new(RestApi {
@@ -63,7 +41,39 @@ impl RestApi {
impl Endpoint for RestApi {
fn to_handler(&self, _path: EndpointPath) -> Box {
- as_json(&self.list_apps())
+ Box::new(RestApiRouter {
+ api: self.clone(),
+ handler: as_json_error(&ApiError {
+ code: "404".into(),
+ title: "Not Found".into(),
+ detail: "Resource you requested has not been found.".into(),
+ }),
+ })
}
}
+struct RestApiRouter {
+ api: RestApi,
+ handler: Box,
+}
+
+impl server::Handler for RestApiRouter {
+
+ fn on_request(&mut self, _request: server::Request) -> Next {
+ self.handler = as_json(&self.api.list_apps());
+ Next::write()
+ }
+
+ fn on_request_readable(&mut self, decoder: &mut Decoder) -> Next {
+ self.handler.on_request_readable(decoder)
+ }
+
+ fn on_response(&mut self, res: &mut server::Response) -> Next {
+ self.handler.on_response(res)
+ }
+
+ fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next {
+ self.handler.on_response_writable(encoder)
+ }
+
+}
diff --git a/dapps/src/api/mod.rs b/dapps/src/api/mod.rs
index 088d7f6b2..402e84257 100644
--- a/dapps/src/api/mod.rs
+++ b/dapps/src/api/mod.rs
@@ -16,13 +16,12 @@
//! REST API
-#![warn(missing_docs)]
#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))]
#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))]
-#[cfg(feature = "serde_macros")]
-include!("mod.rs.in");
-
-#[cfg(not(feature = "serde_macros"))]
-include!(concat!(env!("OUT_DIR"), "/mod.rs"));
+mod api;
+mod response;
+mod types;
+pub use self::api::RestApi;
+pub use self::types::App;
diff --git a/dapps/src/api/response.rs b/dapps/src/api/response.rs
index 345b8a6ee..ba0922e7a 100644
--- a/dapps/src/api/response.rs
+++ b/dapps/src/api/response.rs
@@ -16,8 +16,13 @@
use serde::Serialize;
use serde_json;
-use endpoint::{ContentHandler, Handler};
+use endpoint::Handler;
+use handlers::ContentHandler;
pub fn as_json(val: &T) -> Box {
- Box::new(ContentHandler::new(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
+ Box::new(ContentHandler::ok(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
+}
+
+pub fn as_json_error(val: &T) -> Box {
+ Box::new(ContentHandler::not_found(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
}
diff --git a/util/json-tests/src/util.rs b/dapps/src/api/types.rs
similarity index 80%
rename from util/json-tests/src/util.rs
rename to dapps/src/api/types.rs
index f8beb269a..d99d767eb 100644
--- a/util/json-tests/src/util.rs
+++ b/dapps/src/api/types.rs
@@ -14,11 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use rustc_serialize::hex::FromHex;
+#[cfg(feature = "serde_macros")]
+include!("types.rs.in");
+
+#[cfg(not(feature = "serde_macros"))]
+include!(concat!(env!("OUT_DIR"), "/types.rs"));
+
-pub fn hex_or_string(s: &str) -> Vec {
- match s.starts_with("0x") {
- true => s[2..].from_hex().unwrap(),
- false => From::from(s)
- }
-}
diff --git a/dapps/src/api/types.rs.in b/dapps/src/api/types.rs.in
new file mode 100644
index 000000000..72a8cd221
--- /dev/null
+++ b/dapps/src/api/types.rs.in
@@ -0,0 +1,51 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+use endpoint::EndpointInfo;
+
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub struct App {
+ pub id: String,
+ pub name: String,
+ pub description: String,
+ pub version: String,
+ pub author: String,
+ #[serde(rename="iconUrl")]
+ pub icon_url: String,
+}
+
+impl App {
+ /// Creates `App` instance from `EndpointInfo` and `id`.
+ pub fn from_info(id: &str, info: &EndpointInfo) -> Self {
+ App {
+ id: id.to_owned(),
+ name: info.name.to_owned(),
+ description: info.description.to_owned(),
+ version: info.version.to_owned(),
+ author: info.author.to_owned(),
+ icon_url: info.icon_url.to_owned(),
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub struct ApiError {
+ pub code: String,
+ pub title: String,
+ pub detail: String,
+}
+
+
diff --git a/dapps/src/endpoint.rs b/dapps/src/endpoint.rs
index 075211e58..ba2116e1c 100644
--- a/dapps/src/endpoint.rs
+++ b/dapps/src/endpoint.rs
@@ -16,11 +16,7 @@
//! URL Endpoint traits
-use hyper::status::StatusCode;
-use hyper::{header, server, Decoder, Encoder, Next};
-use hyper::net::HttpStream;
-
-use std::io::Write;
+use hyper::{server, net};
use std::collections::BTreeMap;
#[derive(Debug, PartialEq, Default, Clone)]
@@ -42,58 +38,8 @@ pub struct EndpointInfo {
pub trait Endpoint : Send + Sync {
fn info(&self) -> Option<&EndpointInfo> { None }
- fn to_handler(&self, path: EndpointPath) -> Box + Send>;
+ fn to_handler(&self, path: EndpointPath) -> Box + Send>;
}
pub type Endpoints = BTreeMap>;
-pub type Handler = server::Handler + Send;
-
-pub struct ContentHandler {
- content: String,
- mimetype: String,
- write_pos: usize,
-}
-
-impl ContentHandler {
- pub fn new(content: String, mimetype: String) -> Self {
- ContentHandler {
- content: content,
- mimetype: mimetype,
- write_pos: 0
- }
- }
-}
-
-impl server::Handler for ContentHandler {
- fn on_request(&mut self, _request: server::Request) -> Next {
- Next::write()
- }
-
- fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next {
- Next::write()
- }
-
- fn on_response(&mut self, res: &mut server::Response) -> Next {
- res.set_status(StatusCode::Ok);
- res.headers_mut().set(header::ContentType(self.mimetype.parse().unwrap()));
- Next::write()
- }
-
- fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next {
- let bytes = self.content.as_bytes();
- if self.write_pos == bytes.len() {
- return Next::end();
- }
-
- match encoder.write(&bytes[self.write_pos..]) {
- Ok(bytes) => {
- self.write_pos += bytes;
- Next::write()
- },
- Err(e) => match e.kind() {
- ::std::io::ErrorKind::WouldBlock => Next::write(),
- _ => Next::end()
- },
- }
- }
-}
+pub type Handler = server::Handler + Send;
diff --git a/dapps/src/handlers/auth.rs b/dapps/src/handlers/auth.rs
new file mode 100644
index 000000000..7f72f7cf8
--- /dev/null
+++ b/dapps/src/handlers/auth.rs
@@ -0,0 +1,44 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+//! Authorization Handlers
+
+use hyper::{server, Decoder, Encoder, Next};
+use hyper::net::HttpStream;
+use hyper::status::StatusCode;
+
+pub struct AuthRequiredHandler;
+
+impl server::Handler for AuthRequiredHandler {
+ fn on_request(&mut self, _request: server::Request) -> Next {
+ Next::write()
+ }
+
+ fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next {
+ Next::write()
+ }
+
+ fn on_response(&mut self, res: &mut server::Response) -> Next {
+ res.set_status(StatusCode::Unauthorized);
+ res.headers_mut().set_raw("WWW-Authenticate", vec![b"Basic realm=\"Parity\"".to_vec()]);
+ Next::write()
+ }
+
+ fn on_response_writable(&mut self, _encoder: &mut Encoder) -> Next {
+ Next::end()
+ }
+}
+
diff --git a/dapps/src/handlers/content.rs b/dapps/src/handlers/content.rs
new file mode 100644
index 000000000..a589e5492
--- /dev/null
+++ b/dapps/src/handlers/content.rs
@@ -0,0 +1,92 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+//! Simple Content Handler
+
+use std::io::Write;
+use hyper::{header, server, Decoder, Encoder, Next};
+use hyper::net::HttpStream;
+use hyper::status::StatusCode;
+
+pub struct ContentHandler {
+ code: StatusCode,
+ content: String,
+ mimetype: String,
+ write_pos: usize,
+}
+
+impl ContentHandler {
+ pub fn ok(content: String, mimetype: String) -> Self {
+ ContentHandler {
+ code: StatusCode::Ok,
+ content: content,
+ mimetype: mimetype,
+ write_pos: 0
+ }
+ }
+
+ pub fn not_found(content: String, mimetype: String) -> Self {
+ ContentHandler {
+ code: StatusCode::NotFound,
+ content: content,
+ mimetype: mimetype,
+ write_pos: 0
+ }
+ }
+
+ pub fn new(code: StatusCode, content: String, mimetype: String) -> Self {
+ ContentHandler {
+ code: code,
+ content: content,
+ mimetype: mimetype,
+ write_pos: 0,
+ }
+ }
+}
+
+impl server::Handler for ContentHandler {
+ fn on_request(&mut self, _request: server::Request) -> Next {
+ Next::write()
+ }
+
+ fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next {
+ Next::write()
+ }
+
+ fn on_response(&mut self, res: &mut server::Response) -> Next {
+ res.set_status(self.code);
+ res.headers_mut().set(header::ContentType(self.mimetype.parse().unwrap()));
+ Next::write()
+ }
+
+ fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next {
+ let bytes = self.content.as_bytes();
+ if self.write_pos == bytes.len() {
+ return Next::end();
+ }
+
+ match encoder.write(&bytes[self.write_pos..]) {
+ Ok(bytes) => {
+ self.write_pos += bytes;
+ Next::write()
+ },
+ Err(e) => match e.kind() {
+ ::std::io::ErrorKind::WouldBlock => Next::write(),
+ _ => Next::end()
+ },
+ }
+ }
+}
diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs
new file mode 100644
index 000000000..933538655
--- /dev/null
+++ b/dapps/src/handlers/mod.rs
@@ -0,0 +1,25 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+//! Hyper handlers implementations.
+
+mod auth;
+mod content;
+mod redirect;
+
+pub use self::auth::AuthRequiredHandler;
+pub use self::content::ContentHandler;
+pub use self::redirect::Redirection;
diff --git a/dapps/src/router/redirect.rs b/dapps/src/handlers/redirect.rs
similarity index 100%
rename from dapps/src/router/redirect.rs
rename to dapps/src/handlers/redirect.rs
diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs
index 22b075afd..1c550fb07 100644
--- a/dapps/src/lib.rs
+++ b/dapps/src/lib.rs
@@ -59,6 +59,7 @@ mod endpoint;
mod apps;
mod page;
mod router;
+mod handlers;
mod rpc;
mod api;
mod proxypac;
diff --git a/dapps/src/proxypac.rs b/dapps/src/proxypac.rs
index 9d91d58f0..aaa68dc0c 100644
--- a/dapps/src/proxypac.rs
+++ b/dapps/src/proxypac.rs
@@ -16,7 +16,8 @@
//! Serving ProxyPac file
-use endpoint::{Endpoint, Handler, ContentHandler, EndpointPath};
+use endpoint::{Endpoint, Handler, EndpointPath};
+use handlers::ContentHandler;
use apps::DAPPS_DOMAIN;
pub struct ProxyPac;
@@ -41,7 +42,7 @@ function FindProxyForURL(url, host) {{
}}
"#,
DAPPS_DOMAIN, path.host, path.port);
- Box::new(ContentHandler::new(content, "application/javascript".to_owned()))
+ Box::new(ContentHandler::ok(content, "application/javascript".to_owned()))
}
}
diff --git a/dapps/src/router/auth.rs b/dapps/src/router/auth.rs
index 9459d0719..d18424a00 100644
--- a/dapps/src/router/auth.rs
+++ b/dapps/src/router/auth.rs
@@ -16,24 +16,23 @@
//! HTTP Authorization implementations
-use std::io::Write;
use std::collections::HashMap;
-use hyper::{header, server, Decoder, Encoder, Next};
-use hyper::net::HttpStream;
-use hyper::status::StatusCode;
+use hyper::{server, net, header, status};
+use endpoint::Handler;
+use handlers::{AuthRequiredHandler, ContentHandler};
/// Authorization result
pub enum Authorized {
/// Authorization was successful.
Yes,
/// Unsuccessful authorization. Handler for further work is returned.
- No(Box + Send>),
+ No(Box),
}
/// Authorization interface
pub trait Authorization : Send + Sync {
/// Checks if authorization is valid.
- fn is_authorized(&self, req: &server::Request)-> Authorized;
+ fn is_authorized(&self, req: &server::Request)-> Authorized;
}
/// HTTP Basic Authorization handler
@@ -45,18 +44,22 @@ pub struct HttpBasicAuth {
pub struct NoAuth;
impl Authorization for NoAuth {
- fn is_authorized(&self, _req: &server::Request)-> Authorized {
+ fn is_authorized(&self, _req: &server::Request)-> Authorized {
Authorized::Yes
}
}
impl Authorization for HttpBasicAuth {
- fn is_authorized(&self, req: &server::Request) -> Authorized {
+ fn is_authorized(&self, req: &server::Request) -> Authorized {
let auth = self.check_auth(&req);
match auth {
Access::Denied => {
- Authorized::No(Box::new(UnauthorizedHandler { write_pos: 0 }))
+ Authorized::No(Box::new(ContentHandler::new(
+ status::StatusCode::Unauthorized,
+ "Unauthorized
".into(),
+ "text/html".into(),
+ )))
},
Access::AuthRequired => {
Authorized::No(Box::new(AuthRequiredHandler))
@@ -89,7 +92,7 @@ impl HttpBasicAuth {
self.users.get(&username.to_owned()).map_or(false, |pass| pass == password)
}
- fn check_auth(&self, req: &server::Request) -> Access {
+ fn check_auth(&self, req: &server::Request) -> Access {
match req.headers().get::>() {
Some(&header::Authorization(
header::Basic { ref username, password: Some(ref password) }
@@ -99,63 +102,3 @@ impl HttpBasicAuth {
}
}
}
-
-pub struct UnauthorizedHandler {
- write_pos: usize,
-}
-
-impl server::Handler for UnauthorizedHandler {
- fn on_request(&mut self, _request: server::Request) -> Next {
- Next::write()
- }
-
- fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next {
- Next::write()
- }
-
- fn on_response(&mut self, res: &mut server::Response) -> Next {
- res.set_status(StatusCode::Unauthorized);
- Next::write()
- }
-
- fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next {
- let response = "Unauthorized".as_bytes();
-
- if self.write_pos == response.len() {
- return Next::end();
- }
-
- match encoder.write(&response[self.write_pos..]) {
- Ok(bytes) => {
- self.write_pos += bytes;
- Next::write()
- },
- Err(e) => match e.kind() {
- ::std::io::ErrorKind::WouldBlock => Next::write(),
- _ => Next::end()
- },
- }
- }
-}
-
-pub struct AuthRequiredHandler;
-
-impl server::Handler for AuthRequiredHandler {
- fn on_request(&mut self, _request: server::Request) -> Next {
- Next::write()
- }
-
- fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next {
- Next::write()
- }
-
- fn on_response(&mut self, res: &mut server::Response) -> Next {
- res.set_status(StatusCode::Unauthorized);
- res.headers_mut().set_raw("WWW-Authenticate", vec![b"Basic realm=\"Parity\"".to_vec()]);
- Next::write()
- }
-
- fn on_response_writable(&mut self, _encoder: &mut Encoder) -> Next {
- Next::end()
- }
-}
diff --git a/dapps/src/router/mod.rs b/dapps/src/router/mod.rs
index 0cb0d38d0..f04c8b614 100644
--- a/dapps/src/router/mod.rs
+++ b/dapps/src/router/mod.rs
@@ -18,7 +18,6 @@
//! Processes request handling authorization and dispatching it to proper application.
mod url;
-mod redirect;
pub mod auth;
use DAPPS_DOMAIN;
@@ -33,7 +32,7 @@ use apps;
use endpoint::{Endpoint, Endpoints, EndpointPath};
use self::url::Url;
use self::auth::{Authorization, Authorized};
-use self::redirect::Redirection;
+use handlers::Redirection;
/// Special endpoints are accessible on every domain (every dapp)
#[derive(Debug, PartialEq, Hash, Eq)]
diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml
index 0ea0023d6..acdcd667a 100644
--- a/ethcore/Cargo.toml
+++ b/ethcore/Cargo.toml
@@ -43,3 +43,4 @@ json-tests = []
test-heavy = []
dev = ["clippy"]
default = []
+benches = []
diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs
index 2db4ffcc0..5119b2e33 100644
--- a/ethcore/src/account.rs
+++ b/ethcore/src/account.rs
@@ -127,7 +127,7 @@ impl Account {
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
- (Filth::Clean, H256::from(db.get(key.bytes()).map_or(U256::zero(), |v| -> U256 {decode(v)})))
+ (Filth::Clean, H256::from(db.get(key).map_or(U256::zero(), |v| -> U256 {decode(v)})))
}).1.clone()
}
diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs
index 4b2246b21..252c17b34 100644
--- a/ethcore/src/blockchain/blockchain.rs
+++ b/ethcore/src/blockchain/blockchain.rs
@@ -30,7 +30,7 @@ use blockchain::best_block::BestBlock;
use types::tree_route::TreeRoute;
use blockchain::update::ExtrasUpdate;
use blockchain::{CacheSize, ImportRoute, Config};
-use db::{Writable, Readable, CacheUpdatePolicy};
+use db::{Writable, Readable, CacheUpdatePolicy, Key};
const LOG_BLOOMS_LEVELS: usize = 3;
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
@@ -295,7 +295,22 @@ impl BlockChain {
// load best block
let best_block_hash = match bc.extras_db.get(b"best").unwrap() {
- Some(best) => H256::from_slice(&best),
+ Some(best) => {
+ let best = H256::from_slice(&best);
+ let mut b = best.clone();
+ while !bc.blocks_db.get(&b).unwrap().is_some() {
+ // track back to the best block we have in the blocks database
+ let extras: BlockDetails = bc.extras_db.read(&b).unwrap();
+ type DetailsKey = Key;
+ bc.extras_db.delete(&(DetailsKey::key(&b))).unwrap();
+ b = extras.parent;
+ }
+ if b != best {
+ info!("Restored mismatched best block. Was: {}, new: {}", best.hex(), b.hex());
+ bc.extras_db.put(b"best", &b).unwrap();
+ }
+ b
+ }
None => {
// best block does not exist
// we need to insert genesis into the cache
diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs
index 4f17901b7..f1c260970 100644
--- a/ethcore/src/client/client.rs
+++ b/ethcore/src/client/client.rs
@@ -17,11 +17,12 @@
//! Blockchain database client.
use std::path::PathBuf;
-use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
+use std::time::Instant;
+use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering};
use util::*;
use util::panics::*;
use views::BlockView;
-use error::{Error, ImportError, ExecutionError, BlockError, ImportResult};
+use error::{ImportError, ExecutionError, BlockError, ImportResult};
use header::{BlockNumber};
use state::State;
use spec::Spec;
@@ -38,7 +39,9 @@ use filter::Filter;
use log_entry::LocalizedLogEntry;
use block_queue::{BlockQueue, BlockQueueInfo};
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
-use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, DatabaseCompactionProfile, BlockChainClient, MiningBlockChainClient, TraceFilter, CallAnalytics};
+use client::{BlockID, TransactionID, UncleID, TraceId, Mode, ClientConfig, DatabaseCompactionProfile,
+ BlockChainClient, MiningBlockChainClient, TraceFilter, CallAnalytics, TransactionImportError,
+ BlockImportError, TransactionImportResult};
use client::Error as ClientError;
use env_info::EnvInfo;
use executive::{Executive, Executed, TransactOptions, contract_address};
@@ -49,9 +52,10 @@ use trace;
pub use types::blockchain_info::BlockChainInfo;
pub use types::block_status::BlockStatus;
use evm::Factory as EvmFactory;
-use miner::{Miner, MinerService, TransactionImportResult, AccountDetails};
+use miner::{Miner, MinerService, AccountDetails};
const MAX_TX_QUEUE_SIZE: usize = 4096;
+const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2;
impl fmt::Display for BlockChainInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -81,9 +85,24 @@ impl ClientReport {
}
}
+struct SleepState {
+ last_activity: Option,
+ last_autosleep: Option,
+}
+
+impl SleepState {
+ fn new(awake: bool) -> Self {
+ SleepState {
+ last_activity: match awake { false => None, true => Some(Instant::now()) },
+ last_autosleep: match awake { false => Some(Instant::now()), true => None },
+ }
+ }
+}
+
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
pub struct Client {
+ mode: Mode,
chain: Arc,
tracedb: Arc>,
engine: Arc>,
@@ -96,6 +115,8 @@ pub struct Client {
vm_factory: Arc,
trie_factory: TrieFactory,
miner: Arc,
+ sleep_state: Mutex,
+ liveness: AtomicBool,
io_channel: IoChannel,
queue_transactions: AtomicUsize,
}
@@ -132,9 +153,8 @@ impl Client {
spec: Spec,
path: &Path,
miner: Arc,
- message_channel: IoChannel)
- -> Result, ClientError>
- {
+ message_channel: IoChannel
+ ) -> Result, ClientError> {
let path = get_db_path(path, config.pruning, spec.genesis_header().hash());
let gb = spec.genesis_block();
let chain = Arc::new(BlockChain::new(config.blockchain, &gb, &path));
@@ -165,7 +185,11 @@ impl Client {
let panic_handler = PanicHandler::new_in_arc();
panic_handler.forward_from(&block_queue);
+ let awake = match config.mode { Mode::Dark(..) => false, _ => true };
let client = Client {
+ sleep_state: Mutex::new(SleepState::new(awake)),
+ liveness: AtomicBool::new(awake),
+ mode: config.mode,
chain: chain,
tracedb: tracedb,
engine: engine,
@@ -181,7 +205,6 @@ impl Client {
io_channel: message_channel,
queue_transactions: AtomicUsize::new(0),
};
-
Ok(Arc::new(client))
}
@@ -447,9 +470,41 @@ impl Client {
}
/// Tick the client.
+ // TODO: manage by real events.
pub fn tick(&self) {
self.chain.collect_garbage();
self.block_queue.collect_garbage();
+
+ match self.mode {
+ Mode::Dark(timeout) => {
+ let mut ss = self.sleep_state.lock().unwrap();
+ if let Some(t) = ss.last_activity {
+ if Instant::now() > t + timeout {
+ self.sleep();
+ ss.last_activity = None;
+ }
+ }
+ }
+ Mode::Passive(timeout, wakeup_after) => {
+ let mut ss = self.sleep_state.lock().unwrap();
+ let now = Instant::now();
+ if let Some(t) = ss.last_activity {
+ if now > t + timeout {
+ self.sleep();
+ ss.last_activity = None;
+ ss.last_autosleep = Some(now);
+ }
+ }
+ if let Some(t) = ss.last_autosleep {
+ if now > t + wakeup_after {
+ self.wake_up();
+ ss.last_activity = Some(now);
+ ss.last_autosleep = None;
+ }
+ }
+ }
+ _ => {}
+ }
}
/// Set up the cache behaviour.
@@ -485,6 +540,29 @@ impl Client {
})
}
}
+
+ fn wake_up(&self) {
+ if !self.liveness.load(AtomicOrdering::Relaxed) {
+ self.liveness.store(true, AtomicOrdering::Relaxed);
+ self.io_channel.send(NetworkIoMessage::User(SyncMessage::StartNetwork)).unwrap();
+ trace!(target: "mode", "wake_up: Waking.");
+ }
+ }
+
+ fn sleep(&self) {
+ if self.liveness.load(AtomicOrdering::Relaxed) {
+ // only sleep if the import queue is mostly empty.
+ if self.queue_info().total_queue_size() <= MAX_QUEUE_SIZE_TO_SLEEP_ON {
+ self.liveness.store(false, AtomicOrdering::Relaxed);
+ self.io_channel.send(NetworkIoMessage::User(SyncMessage::StopNetwork)).unwrap();
+ trace!(target: "mode", "sleep: Sleeping.");
+ } else {
+ trace!(target: "mode", "sleep: Cannot sleep - syncing ongoing.");
+ // TODO: Consider uncommenting.
+ //*self.last_activity.lock().unwrap() = Some(Instant::now());
+ }
+ }
+ }
}
impl BlockChainClient for Client {
@@ -526,6 +604,12 @@ impl BlockChainClient for Client {
ret
}
+ fn keep_alive(&self) {
+ if self.mode != Mode::Active {
+ self.wake_up();
+ (*self.sleep_state.lock().unwrap()).last_activity = Some(Instant::now());
+ }
+ }
fn block_header(&self, id: BlockID) -> Option {
Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec()))
@@ -654,17 +738,17 @@ impl BlockChainClient for Client {
self.chain.block_receipts(hash).map(|receipts| rlp::encode(&receipts).to_vec())
}
- fn import_block(&self, bytes: Bytes) -> ImportResult {
+ fn import_block(&self, bytes: Bytes) -> Result {
{
let header = BlockView::new(&bytes).header_view();
if self.chain.is_known(&header.sha3()) {
- return Err(ImportError::AlreadyInChain.into());
+ return Err(BlockImportError::Import(ImportError::AlreadyInChain));
}
if self.block_status(BlockID::Hash(header.parent_hash())) == BlockStatus::Unknown {
- return Err(BlockError::UnknownParent(header.parent_hash()).into());
+ return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash())));
}
}
- self.block_queue.import_block(bytes)
+ Ok(try!(self.block_queue.import_block(bytes)))
}
fn queue_info(&self) -> BlockQueueInfo {
@@ -778,12 +862,16 @@ impl BlockChainClient for Client {
self.build_last_hashes(self.chain.best_block_hash())
}
- fn import_transactions(&self, transactions: Vec) -> Vec> {
+ fn import_transactions(&self, transactions: Vec) -> Vec> {
let fetch_account = |a: &Address| AccountDetails {
nonce: self.latest_nonce(a),
balance: self.latest_balance(a),
};
- self.miner.import_transactions(self, transactions, fetch_account)
+
+ self.miner.import_transactions(self, transactions, &fetch_account)
+ .into_iter()
+ .map(|res| res.map_err(|e| e.into()))
+ .collect()
}
fn queue_transactions(&self, transactions: Vec) {
diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs
index 6cb34c151..1010ce656 100644
--- a/ethcore/src/client/config.rs
+++ b/ethcore/src/client/config.rs
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+pub use std::time::Duration;
pub use block_queue::BlockQueueConfig;
pub use blockchain::Config as BlockChainConfig;
pub use trace::{Config as TraceConfig, Switch};
@@ -35,6 +36,23 @@ impl Default for DatabaseCompactionProfile {
fn default() -> Self { DatabaseCompactionProfile::Default }
}
+/// Operating mode for the client.
+#[derive(Debug, Eq, PartialEq)]
+pub enum Mode {
+ /// Always on.
+ Active,
+ /// Goes offline after RLP is inactive for some (given) time, but
+ /// comes back online after a while of inactivity.
+ Passive(Duration, Duration),
+ /// Goes offline after RLP is inactive for some (given) time and
+ /// stays inactive.
+ Dark(Duration),
+}
+
+impl Default for Mode {
+ fn default() -> Self { Mode::Active }
+}
+
/// Client configuration. Includes configs for all sub-systems.
#[derive(Debug, Default)]
pub struct ClientConfig {
@@ -56,6 +74,8 @@ pub struct ClientConfig {
pub db_cache_size: Option,
/// State db compaction profile
pub db_compaction: DatabaseCompactionProfile,
+ /// Operating mode
+ pub mode: Mode,
/// Type of block verifier used by client.
pub verifier_type: VerifierType,
}
diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs
index 27a1d3265..b81efe43a 100644
--- a/ethcore/src/client/mod.rs
+++ b/ethcore/src/client/mod.rs
@@ -23,7 +23,7 @@ mod test_client;
mod trace;
pub use self::client::*;
-pub use self::config::{ClientConfig, DatabaseCompactionProfile, BlockQueueConfig, BlockChainConfig, Switch, VMType};
+pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockQueueConfig, BlockChainConfig, Switch, VMType};
pub use self::error::Error;
pub use types::ids::*;
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
@@ -47,8 +47,8 @@ use error::{ImportResult, ExecutionError};
use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
use evm::Factory as EvmFactory;
-use miner::{TransactionImportResult};
-use error::Error as EthError;
+pub use block_import_error::BlockImportError;
+pub use transaction_import::{TransactionImportResult, TransactionImportError};
/// Options concerning what analytics we run on the call.
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
@@ -63,6 +63,11 @@ pub struct CallAnalytics {
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send {
+
+ /// Should be called by any external-facing interface when actively using the client.
+ /// To minimise chatter, there's no need to call more than once every 30s.
+ fn keep_alive(&self) {}
+
/// Get raw block header data by block id.
fn block_header(&self, id: BlockID) -> Option;
@@ -145,7 +150,7 @@ pub trait BlockChainClient : Sync + Send {
fn block_receipts(&self, hash: &H256) -> Option;
/// Import a block into the blockchain.
- fn import_block(&self, bytes: Bytes) -> ImportResult;
+ fn import_block(&self, bytes: Bytes) -> Result;
/// Get block queue information.
fn queue_info(&self) -> BlockQueueInfo;
@@ -188,7 +193,7 @@ pub trait BlockChainClient : Sync + Send {
fn last_hashes(&self) -> LastHashes;
/// import transactions from network/other 3rd party
- fn import_transactions(&self, transactions: Vec) -> Vec>;
+ fn import_transactions(&self, transactions: Vec) -> Vec>;
/// Queue transactions for importing.
fn queue_transactions(&self, transactions: Vec);
diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs
index be90d9b67..1e51719c0 100644
--- a/ethcore/src/client/test_client.rs
+++ b/ethcore/src/client/test_client.rs
@@ -20,7 +20,9 @@ use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder};
use util::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use blockchain::TreeRoute;
-use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics};
+use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
+ TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics,
+ TransactionImportError, BlockImportError};
use header::{Header as BlockHeader, BlockNumber};
use filter::Filter;
use log_entry::LocalizedLogEntry;
@@ -38,7 +40,6 @@ use error::{ExecutionError};
use trace::LocalizedTrace;
use miner::{TransactionImportResult, AccountDetails};
-use error::Error as EthError;
/// Test client.
pub struct TestBlockChainClient {
@@ -402,7 +403,7 @@ impl BlockChainClient for TestBlockChainClient {
None
}
- fn import_block(&self, b: Bytes) -> ImportResult {
+ fn import_block(&self, b: Bytes) -> Result {
let header = Rlp::new(&b).val_at::(0);
let h = header.hash();
let number: usize = header.number as usize;
@@ -487,7 +488,7 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!();
}
- fn import_transactions(&self, transactions: Vec) -> Vec> {
+ fn import_transactions(&self, transactions: Vec) -> Vec> {
let nonces = self.nonces.read().unwrap();
let balances = self.balances.read().unwrap();
let fetch_account = |a: &Address| AccountDetails {
@@ -496,6 +497,9 @@ impl BlockChainClient for TestBlockChainClient {
};
self.miner.import_transactions(self, transactions, &fetch_account)
+ .into_iter()
+ .map(|res| res.map_err(|e| e.into()))
+ .collect()
}
fn queue_transactions(&self, transactions: Vec) {
diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs
index 92d3cbe6b..8c37e98ef 100644
--- a/ethcore/src/error.rs
+++ b/ethcore/src/error.rs
@@ -20,10 +20,11 @@ use util::*;
use header::BlockNumber;
use basic_types::LogBloom;
use client::Error as ClientError;
-
pub use types::executed::ExecutionError;
+use ipc::binary::{BinaryConvertError, BinaryConvertable};
+use types::block_import_error::BlockImportError;
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
/// Errors concerning transaction processing.
pub enum TransactionError {
/// Transaction is already imported to the queue
@@ -312,6 +313,21 @@ impl From for Error {
}
}
+impl From for Error {
+ fn from(err: BlockImportError) -> Error {
+ match err {
+ BlockImportError::Block(e) => Error::Block(e),
+ BlockImportError::Import(e) => Error::Import(e),
+ BlockImportError::Other(s) => Error::Util(UtilError::SimpleString(s)),
+ }
+ }
+}
+
+binary_fixed_size!(BlockError);
+binary_fixed_size!(ImportError);
+binary_fixed_size!(TransactionError);
+
+
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
/*#![feature(concat_idents)]
macro_rules! assimilate {
diff --git a/ethcore/src/evm/benches/mod.rs b/ethcore/src/evm/benches/mod.rs
new file mode 100644
index 000000000..8ef730d88
--- /dev/null
+++ b/ethcore/src/evm/benches/mod.rs
@@ -0,0 +1,126 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+//! benchmarking for EVM
+//! should be started with:
+//! ```bash
+//! multirust run nightly cargo bench
+//! ```
+
+extern crate test;
+
+use self::test::{Bencher, black_box};
+
+use common::*;
+use evm::{self, Factory, VMType};
+use evm::tests::FakeExt;
+
+#[bench]
+fn simple_loop_log0_usize(b: &mut Bencher) {
+ simple_loop_log0(U256::from(::std::usize::MAX), b)
+}
+
+#[bench]
+fn simple_loop_log0_u256(b: &mut Bencher) {
+ simple_loop_log0(!U256::zero(), b)
+}
+
+fn simple_loop_log0(gas: U256, b: &mut Bencher) {
+ let mut vm = Factory::new(VMType::Interpreter).create(gas);
+ let mut ext = FakeExt::new();
+
+ let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
+ let code = black_box(
+ "62ffffff5b600190036000600fa0600357".from_hex().unwrap()
+ );
+
+ b.iter(|| {
+ let mut params = ActionParams::default();
+ params.address = address.clone();
+ params.gas = gas;
+ params.code = Some(code.clone());
+
+ result(vm.exec(params, &mut ext))
+ });
+}
+
+#[bench]
+fn mem_gas_calculation_same_usize(b: &mut Bencher) {
+ mem_gas_calculation_same(U256::from(::std::usize::MAX), b)
+}
+
+#[bench]
+fn mem_gas_calculation_same_u256(b: &mut Bencher) {
+ mem_gas_calculation_same(!U256::zero(), b)
+}
+
+fn mem_gas_calculation_same(gas: U256, b: &mut Bencher) {
+ let mut vm = Factory::new(VMType::Interpreter).create(gas);
+ let mut ext = FakeExt::new();
+
+ let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
+
+ b.iter(|| {
+ let code = black_box(
+ "6110006001556001546000555b610fff805560016000540380600055600c57".from_hex().unwrap()
+ );
+
+ let mut params = ActionParams::default();
+ params.address = address.clone();
+ params.gas = gas;
+ params.code = Some(code.clone());
+
+ result(vm.exec(params, &mut ext))
+ });
+}
+
+#[bench]
+fn mem_gas_calculation_increasing_usize(b: &mut Bencher) {
+ mem_gas_calculation_increasing(U256::from(::std::usize::MAX), b)
+}
+
+#[bench]
+fn mem_gas_calculation_increasing_u256(b: &mut Bencher) {
+ mem_gas_calculation_increasing(!U256::zero(), b)
+}
+
+fn mem_gas_calculation_increasing(gas: U256, b: &mut Bencher) {
+ let mut vm = Factory::new(VMType::Interpreter).create(gas);
+ let mut ext = FakeExt::new();
+
+ let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
+
+ b.iter(|| {
+ let code = black_box(
+ "6110006001556001546000555b610fff60005401805560016000540380600055600c57".from_hex().unwrap()
+ );
+
+ let mut params = ActionParams::default();
+ params.address = address.clone();
+ params.gas = gas;
+ params.code = Some(code.clone());
+
+ result(vm.exec(params, &mut ext))
+ });
+}
+
+fn result(r: evm::Result) -> U256 {
+ match r {
+ Ok(evm::GasLeft::Known(v)) => v,
+ Ok(evm::GasLeft::NeedsReturn(v, _)) => v,
+ _ => U256::zero(),
+ }
+}
diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs
index 740774f38..43919034e 100644
--- a/ethcore/src/evm/evm.rs
+++ b/ethcore/src/evm/evm.rs
@@ -95,6 +95,61 @@ impl<'a> Finalize for Result> {
}
}
+pub trait CostType: ops::Mul