Merge branch 'master' into accountdb_migration
This commit is contained in:
commit
aaf9490c91
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -245,6 +245,7 @@ dependencies = [
|
|||||||
"ethcore-devtools 1.3.0",
|
"ethcore-devtools 1.3.0",
|
||||||
"ethcore-ipc 1.3.0",
|
"ethcore-ipc 1.3.0",
|
||||||
"ethcore-ipc-codegen 1.3.0",
|
"ethcore-ipc-codegen 1.3.0",
|
||||||
|
"ethcore-ipc-nano 1.3.0",
|
||||||
"ethcore-util 1.3.0",
|
"ethcore-util 1.3.0",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"ethstore 0.1.0",
|
"ethstore 0.1.0",
|
||||||
@ -256,6 +257,7 @@ dependencies = [
|
|||||||
"rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"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)",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"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)",
|
||||||
]
|
]
|
||||||
@ -281,6 +283,7 @@ dependencies = [
|
|||||||
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_codegen 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)",
|
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -330,6 +333,7 @@ dependencies = [
|
|||||||
"ethash 1.3.0",
|
"ethash 1.3.0",
|
||||||
"ethcore 1.3.0",
|
"ethcore 1.3.0",
|
||||||
"ethcore-devtools 1.3.0",
|
"ethcore-devtools 1.3.0",
|
||||||
|
"ethcore-ipc 1.3.0",
|
||||||
"ethcore-util 1.3.0",
|
"ethcore-util 1.3.0",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"ethsync 1.3.0",
|
"ethsync 1.3.0",
|
||||||
|
@ -13,6 +13,7 @@ log = "0.3"
|
|||||||
jsonrpc-core = "2.0"
|
jsonrpc-core = "2.0"
|
||||||
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
|
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
|
||||||
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
|
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
|
||||||
|
unicase = "1.3"
|
||||||
url = "1.0"
|
url = "1.0"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
serde = "0.7.0"
|
serde = "0.7.0"
|
||||||
|
@ -15,20 +15,23 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
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};
|
use hyper::{server, net, Decoder, Encoder, Next};
|
||||||
|
use api::types::{App, ApiError};
|
||||||
|
use api::response::{as_json, as_json_error, ping_response};
|
||||||
|
use handlers::extract_url;
|
||||||
|
use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RestApi {
|
pub struct RestApi {
|
||||||
|
local_domain: String,
|
||||||
endpoints: Arc<Endpoints>,
|
endpoints: Arc<Endpoints>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RestApi {
|
impl RestApi {
|
||||||
pub fn new(endpoints: Arc<Endpoints>) -> Box<Endpoint> {
|
pub fn new(local_domain: String, endpoints: Arc<Endpoints>) -> Box<Endpoint> {
|
||||||
Box::new(RestApi {
|
Box::new(RestApi {
|
||||||
endpoints: endpoints
|
local_domain: local_domain,
|
||||||
|
endpoints: endpoints,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,9 +62,28 @@ struct RestApiRouter {
|
|||||||
|
|
||||||
impl server::Handler<net::HttpStream> for RestApiRouter {
|
impl server::Handler<net::HttpStream> for RestApiRouter {
|
||||||
|
|
||||||
fn on_request(&mut self, _request: server::Request<net::HttpStream>) -> Next {
|
fn on_request(&mut self, request: server::Request<net::HttpStream>) -> Next {
|
||||||
self.handler = as_json(&self.api.list_apps());
|
let url = extract_url(&request);
|
||||||
Next::write()
|
if url.is_none() {
|
||||||
|
// Just return 404 if we can't parse URL
|
||||||
|
return Next::write();
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = url.expect("Check for None is above; qed");
|
||||||
|
let endpoint = url.path.get(1).map(|v| v.as_str());
|
||||||
|
|
||||||
|
let handler = endpoint.and_then(|v| match v {
|
||||||
|
"apps" => Some(as_json(&self.api.list_apps())),
|
||||||
|
"ping" => Some(ping_response(&self.api.local_domain)),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Overwrite default
|
||||||
|
if let Some(h) = handler {
|
||||||
|
self.handler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.handler.on_request(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_request_readable(&mut self, decoder: &mut Decoder<net::HttpStream>) -> Next {
|
fn on_request_readable(&mut self, decoder: &mut Decoder<net::HttpStream>) -> Next {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use endpoint::Handler;
|
use endpoint::Handler;
|
||||||
use handlers::ContentHandler;
|
use handlers::{ContentHandler, EchoHandler};
|
||||||
|
|
||||||
pub fn as_json<T : Serialize>(val: &T) -> Box<Handler> {
|
pub fn as_json<T : Serialize>(val: &T) -> Box<Handler> {
|
||||||
Box::new(ContentHandler::ok(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
|
Box::new(ContentHandler::ok(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
|
||||||
@ -26,3 +26,11 @@ pub fn as_json<T : Serialize>(val: &T) -> Box<Handler> {
|
|||||||
pub fn as_json_error<T : Serialize>(val: &T) -> Box<Handler> {
|
pub fn as_json_error<T : Serialize>(val: &T) -> Box<Handler> {
|
||||||
Box::new(ContentHandler::not_found(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
|
Box::new(ContentHandler::not_found(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ping_response(local_domain: &str) -> Box<Handler> {
|
||||||
|
Box::new(EchoHandler::cors(vec![
|
||||||
|
format!("http://{}", local_domain),
|
||||||
|
// Allow CORS calls also for localhost
|
||||||
|
format!("http://{}", local_domain.replace("127.0.0.1", "localhost")),
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
@ -19,5 +19,3 @@ include!("types.rs.in");
|
|||||||
|
|
||||||
#[cfg(not(feature = "serde_macros"))]
|
#[cfg(not(feature = "serde_macros"))]
|
||||||
include!(concat!(env!("OUT_DIR"), "/types.rs"));
|
include!(concat!(env!("OUT_DIR"), "/types.rs"));
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,4 +48,3 @@ pub struct ApiError {
|
|||||||
pub detail: String,
|
pub detail: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
148
dapps/src/handlers/echo.rs
Normal file
148
dapps/src/handlers/echo.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Echo Handler
|
||||||
|
|
||||||
|
use std::io::Read;
|
||||||
|
use hyper::{header, server, Decoder, Encoder, Next};
|
||||||
|
use hyper::method::Method;
|
||||||
|
use hyper::net::HttpStream;
|
||||||
|
use unicase::UniCase;
|
||||||
|
use super::ContentHandler;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
/// Type of Cross-Origin request
|
||||||
|
enum Cors {
|
||||||
|
/// Not a Cross-Origin request - no headers needed
|
||||||
|
No,
|
||||||
|
/// Cross-Origin request with valid Origin
|
||||||
|
Allowed(String),
|
||||||
|
/// Cross-Origin request with invalid Origin
|
||||||
|
Forbidden,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EchoHandler {
|
||||||
|
safe_origins: Vec<String>,
|
||||||
|
content: String,
|
||||||
|
cors: Cors,
|
||||||
|
handler: Option<ContentHandler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EchoHandler {
|
||||||
|
|
||||||
|
pub fn cors(safe_origins: Vec<String>) -> Self {
|
||||||
|
EchoHandler {
|
||||||
|
safe_origins: safe_origins,
|
||||||
|
content: String::new(),
|
||||||
|
cors: Cors::Forbidden,
|
||||||
|
handler: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cors_header(&self, origin: Option<String>) -> Cors {
|
||||||
|
fn origin_is_allowed(origin: &str, safe_origins: &[String]) -> bool {
|
||||||
|
for safe in safe_origins {
|
||||||
|
if origin.starts_with(safe) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
match origin {
|
||||||
|
Some(ref origin) if origin_is_allowed(origin, &self.safe_origins) => {
|
||||||
|
Cors::Allowed(origin.clone())
|
||||||
|
},
|
||||||
|
None => Cors::No,
|
||||||
|
_ => Cors::Forbidden,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl server::Handler<HttpStream> for EchoHandler {
|
||||||
|
fn on_request(&mut self, request: server::Request<HttpStream>) -> Next {
|
||||||
|
let origin = request.headers().get_raw("origin")
|
||||||
|
.and_then(|list| list.get(0))
|
||||||
|
.and_then(|origin| String::from_utf8(origin.clone()).ok());
|
||||||
|
|
||||||
|
self.cors = self.cors_header(origin);
|
||||||
|
|
||||||
|
// Don't even read the payload if origin is forbidden!
|
||||||
|
if let Cors::Forbidden = self.cors {
|
||||||
|
self.handler = Some(ContentHandler::ok(String::new(), "text/plain".into()));
|
||||||
|
Next::write()
|
||||||
|
} else {
|
||||||
|
Next::read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
|
||||||
|
match decoder.read_to_string(&mut self.content) {
|
||||||
|
Ok(0) => {
|
||||||
|
self.handler = Some(ContentHandler::ok(self.content.clone(), "application/json".into()));
|
||||||
|
Next::write()
|
||||||
|
},
|
||||||
|
Ok(_) => Next::read(),
|
||||||
|
Err(e) => match e.kind() {
|
||||||
|
::std::io::ErrorKind::WouldBlock => Next::read(),
|
||||||
|
_ => Next::end(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
||||||
|
if let Cors::Allowed(ref domain) = self.cors {
|
||||||
|
let mut headers = res.headers_mut();
|
||||||
|
headers.set(header::Allow(vec![Method::Options, Method::Post, Method::Get]));
|
||||||
|
headers.set(header::AccessControlAllowHeaders(vec![
|
||||||
|
UniCase("origin".to_owned()),
|
||||||
|
UniCase("content-type".to_owned()),
|
||||||
|
UniCase("accept".to_owned()),
|
||||||
|
]));
|
||||||
|
headers.set(header::AccessControlAllowOrigin::Value(domain.clone()));
|
||||||
|
}
|
||||||
|
self.handler.as_mut().unwrap().on_response(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
|
||||||
|
self.handler.as_mut().unwrap().on_response_writable(encoder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_correct_cors_value() {
|
||||||
|
// given
|
||||||
|
let safe_origins = vec!["chrome-extension://".to_owned(), "http://localhost:8080".to_owned()];
|
||||||
|
let cut = EchoHandler {
|
||||||
|
safe_origins: safe_origins,
|
||||||
|
content: String::new(),
|
||||||
|
cors: Cors::No,
|
||||||
|
handler: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// when
|
||||||
|
let res1 = cut.cors_header(Some("http://ethcore.io".into()));
|
||||||
|
let res2 = cut.cors_header(Some("http://localhost:8080".into()));
|
||||||
|
let res3 = cut.cors_header(Some("chrome-extension://deadbeefcafe".into()));
|
||||||
|
let res4 = cut.cors_header(None);
|
||||||
|
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(res1, Cors::Forbidden);
|
||||||
|
assert_eq!(res2, Cors::Allowed("http://localhost:8080".into()));
|
||||||
|
assert_eq!(res3, Cors::Allowed("chrome-extension://deadbeefcafe".into()));
|
||||||
|
assert_eq!(res4, Cors::No);
|
||||||
|
}
|
@ -17,9 +17,41 @@
|
|||||||
//! Hyper handlers implementations.
|
//! Hyper handlers implementations.
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
|
mod echo;
|
||||||
mod content;
|
mod content;
|
||||||
mod redirect;
|
mod redirect;
|
||||||
|
|
||||||
pub use self::auth::AuthRequiredHandler;
|
pub use self::auth::AuthRequiredHandler;
|
||||||
|
pub use self::echo::EchoHandler;
|
||||||
pub use self::content::ContentHandler;
|
pub use self::content::ContentHandler;
|
||||||
pub use self::redirect::Redirection;
|
pub use self::redirect::Redirection;
|
||||||
|
|
||||||
|
use url::Url;
|
||||||
|
use hyper::{server, header, net, uri};
|
||||||
|
|
||||||
|
pub fn extract_url(req: &server::Request<net::HttpStream>) -> Option<Url> {
|
||||||
|
match *req.uri() {
|
||||||
|
uri::RequestUri::AbsoluteUri(ref url) => {
|
||||||
|
match Url::from_generic_url(url.clone()) {
|
||||||
|
Ok(url) => Some(url),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uri::RequestUri::AbsolutePath(ref path) => {
|
||||||
|
// Attempt to prepend the Host header (mandatory in HTTP/1.1)
|
||||||
|
let url_string = match req.headers().get::<header::Host>() {
|
||||||
|
Some(ref host) => {
|
||||||
|
format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path)
|
||||||
|
},
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Url::parse(&url_string) {
|
||||||
|
Ok(url) => Some(url),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -45,8 +45,9 @@
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate url;
|
extern crate url as url_lib;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
|
extern crate unicase;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate jsonrpc_core;
|
extern crate jsonrpc_core;
|
||||||
@ -63,6 +64,7 @@ mod handlers;
|
|||||||
mod rpc;
|
mod rpc;
|
||||||
mod api;
|
mod api;
|
||||||
mod proxypac;
|
mod proxypac;
|
||||||
|
mod url;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@ -121,7 +123,7 @@ impl Server {
|
|||||||
let special = Arc::new({
|
let special = Arc::new({
|
||||||
let mut special = HashMap::new();
|
let mut special = HashMap::new();
|
||||||
special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, panic_handler.clone()));
|
special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, panic_handler.clone()));
|
||||||
special.insert(router::SpecialEndpoint::Api, api::RestApi::new(endpoints.clone()));
|
special.insert(router::SpecialEndpoint::Api, api::RestApi::new(format!("{}", addr), endpoints.clone()));
|
||||||
special.insert(router::SpecialEndpoint::Utils, apps::utils());
|
special.insert(router::SpecialEndpoint::Utils, apps::utils());
|
||||||
special
|
special
|
||||||
});
|
});
|
||||||
|
@ -17,22 +17,18 @@
|
|||||||
//! Router implementation
|
//! Router implementation
|
||||||
//! Processes request handling authorization and dispatching it to proper application.
|
//! Processes request handling authorization and dispatching it to proper application.
|
||||||
|
|
||||||
mod url;
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
|
||||||
use DAPPS_DOMAIN;
|
use DAPPS_DOMAIN;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use url::Host;
|
use url::{Url, Host};
|
||||||
use hyper;
|
use hyper::{self, server, Next, Encoder, Decoder};
|
||||||
use hyper::{server, uri, header};
|
|
||||||
use hyper::{Next, Encoder, Decoder};
|
|
||||||
use hyper::net::HttpStream;
|
use hyper::net::HttpStream;
|
||||||
use apps;
|
use apps;
|
||||||
use endpoint::{Endpoint, Endpoints, EndpointPath};
|
use endpoint::{Endpoint, Endpoints, EndpointPath};
|
||||||
use self::url::Url;
|
use handlers::{Redirection, extract_url};
|
||||||
use self::auth::{Authorization, Authorized};
|
use self::auth::{Authorization, Authorized};
|
||||||
use handlers::Redirection;
|
|
||||||
|
|
||||||
/// 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)]
|
||||||
@ -123,32 +119,6 @@ impl<A: Authorization> Router<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_url(req: &server::Request<HttpStream>) -> Option<Url> {
|
|
||||||
match *req.uri() {
|
|
||||||
uri::RequestUri::AbsoluteUri(ref url) => {
|
|
||||||
match Url::from_generic_url(url.clone()) {
|
|
||||||
Ok(url) => Some(url),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
uri::RequestUri::AbsolutePath(ref path) => {
|
|
||||||
// Attempt to prepend the Host header (mandatory in HTTP/1.1)
|
|
||||||
let url_string = match req.headers().get::<header::Host>() {
|
|
||||||
Some(ref host) => {
|
|
||||||
format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path)
|
|
||||||
},
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
match Url::parse(&url_string) {
|
|
||||||
Ok(url) => Some(url),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_endpoint(url: &Option<Url>) -> (Option<EndpointPath>, SpecialEndpoint) {
|
fn extract_endpoint(url: &Option<Url>) -> (Option<EndpointPath>, SpecialEndpoint) {
|
||||||
fn special_endpoint(url: &Url) -> SpecialEndpoint {
|
fn special_endpoint(url: &Url) -> SpecialEndpoint {
|
||||||
if url.path.len() <= 1 {
|
if url.path.len() <= 1 {
|
||||||
|
@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
//! HTTP/HTTPS URL type. Based on URL type from Iron library.
|
//! HTTP/HTTPS URL type. Based on URL type from Iron library.
|
||||||
|
|
||||||
use url::Host;
|
use url_lib::{self};
|
||||||
use url::{self};
|
pub use url_lib::Host;
|
||||||
|
|
||||||
/// HTTP/HTTPS URL type for Iron.
|
/// HTTP/HTTPS URL type for Iron.
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct Url {
|
pub struct Url {
|
||||||
/// Raw url of url
|
/// Raw url of url
|
||||||
pub raw: url::Url,
|
pub raw: url_lib::Url,
|
||||||
|
|
||||||
/// The host field of the URL, probably a domain.
|
/// The host field of the URL, probably a domain.
|
||||||
pub host: Host,
|
pub host: Host,
|
||||||
@ -62,14 +62,14 @@ impl Url {
|
|||||||
/// See: http://url.spec.whatwg.org/#special-scheme
|
/// See: http://url.spec.whatwg.org/#special-scheme
|
||||||
pub fn parse(input: &str) -> Result<Url, String> {
|
pub fn parse(input: &str) -> Result<Url, String> {
|
||||||
// Parse the string using rust-url, then convert.
|
// Parse the string using rust-url, then convert.
|
||||||
match url::Url::parse(input) {
|
match url_lib::Url::parse(input) {
|
||||||
Ok(raw_url) => Url::from_generic_url(raw_url),
|
Ok(raw_url) => Url::from_generic_url(raw_url),
|
||||||
Err(e) => Err(format!("{}", e))
|
Err(e) => Err(format!("{}", e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `Url` from a `rust-url` `Url`.
|
/// Create a `Url` from a `rust-url` `Url`.
|
||||||
pub fn from_generic_url(raw_url: url::Url) -> Result<Url, String> {
|
pub fn from_generic_url(raw_url: url_lib::Url) -> Result<Url, String> {
|
||||||
// Map empty usernames to None.
|
// Map empty usernames to None.
|
||||||
let username = match raw_url.username() {
|
let username = match raw_url.username() {
|
||||||
"" => None,
|
"" => None,
|
@ -31,6 +31,8 @@ bloomchain = "0.1"
|
|||||||
"ethcore-ipc" = { path = "../ipc/rpc" }
|
"ethcore-ipc" = { path = "../ipc/rpc" }
|
||||||
rayon = "0.3.1"
|
rayon = "0.3.1"
|
||||||
ethstore = { path = "../ethstore" }
|
ethstore = { path = "../ethstore" }
|
||||||
|
semver = "0.2"
|
||||||
|
ethcore-ipc-nano = { path = "../ipc/nano" }
|
||||||
|
|
||||||
[dependencies.hyper]
|
[dependencies.hyper]
|
||||||
git = "https://github.com/ethcore/hyper"
|
git = "https://github.com/ethcore/hyper"
|
||||||
|
@ -30,4 +30,18 @@ fn main() {
|
|||||||
codegen::register(&mut registry);
|
codegen::register(&mut registry);
|
||||||
registry.expand("", &src, &dst).unwrap();
|
registry.expand("", &src, &dst).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// client interface
|
||||||
|
{
|
||||||
|
let src = Path::new("src/client/client.rs");
|
||||||
|
let intermediate = Path::new(&out_dir).join("client.intermediate.rs.in");
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
codegen::register(&mut registry);
|
||||||
|
registry.expand("", &src, &intermediate).unwrap();
|
||||||
|
|
||||||
|
let dst = Path::new(&out_dir).join("client.ipc.rs");
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
codegen::register(&mut registry);
|
||||||
|
registry.expand("", &intermediate, &dst).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0x118c30",
|
"frontierCompatibilityModeLimit": "0x118c30"
|
||||||
"daoRescueSoftFork": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,7 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0x118c30",
|
"frontierCompatibilityModeLimit": "0x118c30"
|
||||||
"daoRescueSoftFork": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0x118c30",
|
"frontierCompatibilityModeLimit": "0x118c30"
|
||||||
"daoRescueSoftFork": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
|
"frontierCompatibilityModeLimit": "0xffffffffffffffff"
|
||||||
"daoRescueSoftFork": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": 0,
|
"frontierCompatibilityModeLimit": 0
|
||||||
"daoRescueSoftFork": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": 0,
|
"frontierCompatibilityModeLimit": 0
|
||||||
"daoRescueSoftFork": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar": "",
|
"registrar": "",
|
||||||
"frontierCompatibilityModeLimit": "0x789b0",
|
"frontierCompatibilityModeLimit": "0x789b0"
|
||||||
"daoRescueSoftFork": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
"durationLimit": "0x08",
|
"durationLimit": "0x08",
|
||||||
"blockReward": "0x14D1120D7B160000",
|
"blockReward": "0x14D1120D7B160000",
|
||||||
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
|
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
|
||||||
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
|
"frontierCompatibilityModeLimit": "0xffffffffffffffff"
|
||||||
"daoRescueSoftFork": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -203,7 +203,6 @@ mod tests {
|
|||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
difficulty: 0.into(),
|
difficulty: 0.into(),
|
||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
dao_rescue_block_gas_limit: None,
|
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into(),
|
gas_limit: 0.into(),
|
||||||
});
|
});
|
||||||
@ -254,7 +253,7 @@ mod tests {
|
|||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
|
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
|
||||||
assert!(b.try_seal(engine.deref(), seal).is_ok());
|
assert!(b.try_seal(engine.deref(), seal).is_ok());
|
||||||
|
@ -183,7 +183,6 @@ pub struct OpenBlock<'x> {
|
|||||||
engine: &'x Engine,
|
engine: &'x Engine,
|
||||||
vm_factory: &'x EvmFactory,
|
vm_factory: &'x EvmFactory,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
dao_rescue_block_gas_limit: Option<U256>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
|
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
|
||||||
@ -195,7 +194,6 @@ pub struct ClosedBlock {
|
|||||||
block: ExecutedBlock,
|
block: ExecutedBlock,
|
||||||
uncle_bytes: Bytes,
|
uncle_bytes: Bytes,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
dao_rescue_block_gas_limit: Option<U256>,
|
|
||||||
unclosed_state: State,
|
unclosed_state: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +225,6 @@ impl<'x> OpenBlock<'x> {
|
|||||||
db: Box<JournalDB>,
|
db: Box<JournalDB>,
|
||||||
parent: &Header,
|
parent: &Header,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
dao_rescue_block_gas_limit: Option<U256>,
|
|
||||||
author: Address,
|
author: Address,
|
||||||
gas_range_target: (U256, U256),
|
gas_range_target: (U256, U256),
|
||||||
extra_data: Bytes,
|
extra_data: Bytes,
|
||||||
@ -238,7 +235,6 @@ impl<'x> OpenBlock<'x> {
|
|||||||
engine: engine,
|
engine: engine,
|
||||||
vm_factory: vm_factory,
|
vm_factory: vm_factory,
|
||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
dao_rescue_block_gas_limit: dao_rescue_block_gas_limit,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
r.block.base.header.parent_hash = parent.hash();
|
r.block.base.header.parent_hash = parent.hash();
|
||||||
@ -295,7 +291,6 @@ impl<'x> OpenBlock<'x> {
|
|||||||
/// Get the environment info concerning this block.
|
/// Get the environment info concerning this block.
|
||||||
pub fn env_info(&self) -> EnvInfo {
|
pub fn env_info(&self) -> EnvInfo {
|
||||||
// TODO: memoise.
|
// TODO: memoise.
|
||||||
const SOFT_FORK_BLOCK: u64 = 1_800_000;
|
|
||||||
EnvInfo {
|
EnvInfo {
|
||||||
number: self.block.base.header.number,
|
number: self.block.base.header.number,
|
||||||
author: self.block.base.header.author.clone(),
|
author: self.block.base.header.author.clone(),
|
||||||
@ -304,7 +299,6 @@ impl<'x> OpenBlock<'x> {
|
|||||||
last_hashes: self.last_hashes.clone(), // TODO: should be a reference.
|
last_hashes: self.last_hashes.clone(), // TODO: should be a reference.
|
||||||
gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
|
gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
|
||||||
gas_limit: self.block.base.header.gas_limit.clone(),
|
gas_limit: self.block.base.header.gas_limit.clone(),
|
||||||
dao_rescue_block_gas_limit: if self.block.base.header.number == SOFT_FORK_BLOCK { Some(self.block.base.header.gas_limit) } else { self.dao_rescue_block_gas_limit },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +345,6 @@ impl<'x> OpenBlock<'x> {
|
|||||||
block: s.block,
|
block: s.block,
|
||||||
uncle_bytes: uncle_bytes,
|
uncle_bytes: uncle_bytes,
|
||||||
last_hashes: s.last_hashes,
|
last_hashes: s.last_hashes,
|
||||||
dao_rescue_block_gas_limit: s.dao_rescue_block_gas_limit,
|
|
||||||
unclosed_state: unclosed_state,
|
unclosed_state: unclosed_state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -411,7 +404,6 @@ impl ClosedBlock {
|
|||||||
engine: engine,
|
engine: engine,
|
||||||
vm_factory: vm_factory,
|
vm_factory: vm_factory,
|
||||||
last_hashes: self.last_hashes,
|
last_hashes: self.last_hashes,
|
||||||
dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,7 +473,6 @@ pub fn enact(
|
|||||||
db: Box<JournalDB>,
|
db: Box<JournalDB>,
|
||||||
parent: &Header,
|
parent: &Header,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
dao_rescue_block_gas_limit: Option<U256>,
|
|
||||||
vm_factory: &EvmFactory,
|
vm_factory: &EvmFactory,
|
||||||
trie_factory: TrieFactory,
|
trie_factory: TrieFactory,
|
||||||
) -> Result<LockedBlock, Error> {
|
) -> Result<LockedBlock, Error> {
|
||||||
@ -492,7 +483,7 @@ pub fn enact(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut b = try!(OpenBlock::new(engine, vm_factory, trie_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
|
let mut b = try!(OpenBlock::new(engine, vm_factory, trie_factory, tracing, db, parent, last_hashes, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
|
||||||
b.set_difficulty(*header.difficulty());
|
b.set_difficulty(*header.difficulty());
|
||||||
b.set_gas_limit(*header.gas_limit());
|
b.set_gas_limit(*header.gas_limit());
|
||||||
b.set_timestamp(header.timestamp());
|
b.set_timestamp(header.timestamp());
|
||||||
@ -510,13 +501,12 @@ pub fn enact_bytes(
|
|||||||
db: Box<JournalDB>,
|
db: Box<JournalDB>,
|
||||||
parent: &Header,
|
parent: &Header,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
dao_rescue_block_gas_limit: Option<U256>,
|
|
||||||
vm_factory: &EvmFactory,
|
vm_factory: &EvmFactory,
|
||||||
trie_factory: TrieFactory,
|
trie_factory: TrieFactory,
|
||||||
) -> Result<LockedBlock, Error> {
|
) -> Result<LockedBlock, Error> {
|
||||||
let block = BlockView::new(block_bytes);
|
let block = BlockView::new(block_bytes);
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)
|
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, vm_factory, trie_factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
||||||
@ -528,12 +518,11 @@ pub fn enact_verified(
|
|||||||
db: Box<JournalDB>,
|
db: Box<JournalDB>,
|
||||||
parent: &Header,
|
parent: &Header,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
dao_rescue_block_gas_limit: Option<U256>,
|
|
||||||
vm_factory: &EvmFactory,
|
vm_factory: &EvmFactory,
|
||||||
trie_factory: TrieFactory,
|
trie_factory: TrieFactory,
|
||||||
) -> Result<LockedBlock, Error> {
|
) -> Result<LockedBlock, Error> {
|
||||||
let view = BlockView::new(&block.bytes);
|
let view = BlockView::new(&block.bytes);
|
||||||
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)
|
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, vm_factory, trie_factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@ -545,12 +534,11 @@ pub fn enact_and_seal(
|
|||||||
db: Box<JournalDB>,
|
db: Box<JournalDB>,
|
||||||
parent: &Header,
|
parent: &Header,
|
||||||
last_hashes: LastHashes,
|
last_hashes: LastHashes,
|
||||||
dao_rescue_block_gas_limit: Option<U256>,
|
|
||||||
vm_factory: &EvmFactory,
|
vm_factory: &EvmFactory,
|
||||||
trie_factory: TrieFactory,
|
trie_factory: TrieFactory,
|
||||||
) -> Result<SealedBlock, Error> {
|
) -> Result<SealedBlock, Error> {
|
||||||
let header = BlockView::new(block_bytes).header_view();
|
let header = BlockView::new(block_bytes).header_view();
|
||||||
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)).seal(engine, header.seal())))
|
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, vm_factory, trie_factory)).seal(engine, header.seal())))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -570,7 +558,7 @@ mod tests {
|
|||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
let _ = b.seal(engine.deref(), vec![]);
|
let _ = b.seal(engine.deref(), vec![]);
|
||||||
}
|
}
|
||||||
@ -586,7 +574,7 @@ mod tests {
|
|||||||
let mut db = db_result.take();
|
let mut db = db_result.take();
|
||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
|
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
|
||||||
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
|
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
|
||||||
let orig_bytes = b.rlp_bytes();
|
let orig_bytes = b.rlp_bytes();
|
||||||
let orig_db = b.drain();
|
let orig_db = b.drain();
|
||||||
@ -594,7 +582,7 @@ mod tests {
|
|||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
let mut db = db_result.take();
|
let mut db = db_result.take();
|
||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap();
|
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default(), Default::default()).unwrap();
|
||||||
|
|
||||||
assert_eq!(e.rlp_bytes(), orig_bytes);
|
assert_eq!(e.rlp_bytes(), orig_bytes);
|
||||||
|
|
||||||
@ -614,7 +602,7 @@ mod tests {
|
|||||||
let mut db = db_result.take();
|
let mut db = db_result.take();
|
||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let mut uncle1_header = Header::new();
|
let mut uncle1_header = Header::new();
|
||||||
uncle1_header.extra_data = b"uncle1".to_vec();
|
uncle1_header.extra_data = b"uncle1".to_vec();
|
||||||
let mut uncle2_header = Header::new();
|
let mut uncle2_header = Header::new();
|
||||||
@ -629,7 +617,7 @@ mod tests {
|
|||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
let mut db = db_result.take();
|
let mut db = db_result.take();
|
||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap();
|
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default(), Default::default()).unwrap();
|
||||||
|
|
||||||
let bytes = e.rlp_bytes();
|
let bytes = e.rlp_bytes();
|
||||||
assert_eq!(bytes, orig_bytes);
|
assert_eq!(bytes, orig_bytes);
|
||||||
|
@ -28,6 +28,8 @@ use service::*;
|
|||||||
use client::BlockStatus;
|
use client::BlockStatus;
|
||||||
use util::panics::*;
|
use util::panics::*;
|
||||||
|
|
||||||
|
pub use types::block_queue_info::BlockQueueInfo;
|
||||||
|
|
||||||
known_heap_size!(0, UnverifiedBlock, VerifyingBlock, PreverifiedBlock);
|
known_heap_size!(0, UnverifiedBlock, VerifyingBlock, PreverifiedBlock);
|
||||||
|
|
||||||
const MIN_MEM_LIMIT: usize = 16384;
|
const MIN_MEM_LIMIT: usize = 16384;
|
||||||
@ -53,22 +55,6 @@ impl Default for BlockQueueConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block queue status
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BlockQueueInfo {
|
|
||||||
/// Number of queued blocks pending verification
|
|
||||||
pub unverified_queue_size: usize,
|
|
||||||
/// Number of verified queued blocks pending import
|
|
||||||
pub verified_queue_size: usize,
|
|
||||||
/// Number of blocks being verified
|
|
||||||
pub verifying_queue_size: usize,
|
|
||||||
/// Configured maximum number of blocks in the queue
|
|
||||||
pub max_queue_size: usize,
|
|
||||||
/// Configured maximum number of bytes to use
|
|
||||||
pub max_mem_use: usize,
|
|
||||||
/// Heap memory used in bytes
|
|
||||||
pub mem_used: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockQueueInfo {
|
impl BlockQueueInfo {
|
||||||
/// The total size of the queues.
|
/// The total size of the queues.
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
use util::numbers::{U256,H256};
|
use util::numbers::{U256,H256};
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
|
|
||||||
use util::bytes::{FromRawBytesVariable, FromBytesError, ToBytesWithMap};
|
|
||||||
|
|
||||||
/// Brief info about inserted block.
|
/// Brief info about inserted block.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BlockInfo {
|
pub struct BlockInfo {
|
||||||
@ -54,43 +52,3 @@ pub struct BranchBecomingCanonChainData {
|
|||||||
/// Hashes of the blocks which were invalidated.
|
/// Hashes of the blocks which were invalidated.
|
||||||
pub retracted: Vec<H256>,
|
pub retracted: Vec<H256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromRawBytesVariable for BranchBecomingCanonChainData {
|
|
||||||
fn from_bytes_variable(bytes: &[u8]) -> Result<BranchBecomingCanonChainData, FromBytesError> {
|
|
||||||
type Tuple = (Vec<H256>, Vec<H256>, H256);
|
|
||||||
let (enacted, retracted, ancestor) = try!(Tuple::from_bytes_variable(bytes));
|
|
||||||
Ok(BranchBecomingCanonChainData { ancestor: ancestor, enacted: enacted, retracted: retracted })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromRawBytesVariable for BlockLocation {
|
|
||||||
fn from_bytes_variable(bytes: &[u8]) -> Result<BlockLocation, FromBytesError> {
|
|
||||||
match bytes[0] {
|
|
||||||
0 => Ok(BlockLocation::CanonChain),
|
|
||||||
1 => Ok(BlockLocation::Branch),
|
|
||||||
2 => Ok(BlockLocation::BranchBecomingCanonChain(
|
|
||||||
try!(BranchBecomingCanonChainData::from_bytes_variable(&bytes[1..bytes.len()])))),
|
|
||||||
_ => Err(FromBytesError::UnknownMarker)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToBytesWithMap for BranchBecomingCanonChainData {
|
|
||||||
fn to_bytes_map(&self) -> Vec<u8> {
|
|
||||||
(&self.enacted, &self.retracted, &self.ancestor).to_bytes_map()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToBytesWithMap for BlockLocation {
|
|
||||||
fn to_bytes_map(&self) -> Vec<u8> {
|
|
||||||
match *self {
|
|
||||||
BlockLocation::CanonChain => vec![0u8],
|
|
||||||
BlockLocation::Branch => vec![1u8],
|
|
||||||
BlockLocation::BranchBecomingCanonChain(ref data) => {
|
|
||||||
let mut bytes = (&data.enacted, &data.retracted, &data.ancestor).to_bytes_map();
|
|
||||||
bytes.insert(0, 2u8);
|
|
||||||
bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -14,16 +14,35 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Blockchain database client.
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::collections::{HashSet, HashMap};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::mem;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::*;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::fmt;
|
||||||
|
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering};
|
|
||||||
use util::*;
|
// util
|
||||||
|
use util::numbers::*;
|
||||||
use util::panics::*;
|
use util::panics::*;
|
||||||
|
use util::network::*;
|
||||||
|
use util::io::*;
|
||||||
|
use util::rlp;
|
||||||
|
use util::sha3::*;
|
||||||
|
use util::{Bytes};
|
||||||
|
use util::rlp::{RlpStream, Rlp, UntrustedRlp};
|
||||||
|
use util::journaldb;
|
||||||
|
use util::journaldb::JournalDB;
|
||||||
|
use util::kvdb::*;
|
||||||
|
use util::{Applyable, Stream, View, PerfTimer, Itertools, Colour};
|
||||||
|
|
||||||
|
// other
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
use error::{ImportError, ExecutionError, BlockError, ImportResult};
|
use error::{ImportError, ExecutionError, BlockError, ImportResult};
|
||||||
use header::{BlockNumber};
|
use header::BlockNumber;
|
||||||
use state::State;
|
use state::State;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use engine::Engine;
|
use engine::Engine;
|
||||||
@ -35,24 +54,29 @@ use verification::{PreverifiedBlock, Verifier};
|
|||||||
use block::*;
|
use block::*;
|
||||||
use transaction::{LocalizedTransaction, SignedTransaction, Action};
|
use transaction::{LocalizedTransaction, SignedTransaction, Action};
|
||||||
use blockchain::extras::TransactionAddress;
|
use blockchain::extras::TransactionAddress;
|
||||||
use filter::Filter;
|
use types::filter::Filter;
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use block_queue::{BlockQueue, BlockQueueInfo};
|
use block_queue::{BlockQueue, BlockQueueInfo};
|
||||||
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
||||||
use client::{BlockID, TransactionID, UncleID, TraceId, Mode, ClientConfig, DatabaseCompactionProfile,
|
use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig,
|
||||||
BlockChainClient, MiningBlockChainClient, TraceFilter, CallAnalytics, TransactionImportError,
|
DatabaseCompactionProfile, BlockChainClient, MiningBlockChainClient,
|
||||||
BlockImportError, TransactionImportResult};
|
TraceFilter, CallAnalytics, BlockImportError, Mode};
|
||||||
use client::Error as ClientError;
|
use client::Error as ClientError;
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use executive::{Executive, Executed, TransactOptions, contract_address};
|
use executive::{Executive, Executed, TransactOptions, contract_address};
|
||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
pub use blockchain::CacheSize as BlockChainCacheSize;
|
|
||||||
use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase};
|
use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase};
|
||||||
use trace;
|
use trace;
|
||||||
|
use evm::Factory as EvmFactory;
|
||||||
|
use miner::{Miner, MinerService};
|
||||||
|
use util::TrieFactory;
|
||||||
|
use ipc::IpcConfig;
|
||||||
|
use ipc::binary::{BinaryConvertError};
|
||||||
|
|
||||||
|
// re-export
|
||||||
pub use types::blockchain_info::BlockChainInfo;
|
pub use types::blockchain_info::BlockChainInfo;
|
||||||
pub use types::block_status::BlockStatus;
|
pub use types::block_status::BlockStatus;
|
||||||
use evm::Factory as EvmFactory;
|
pub use blockchain::CacheSize as BlockChainCacheSize;
|
||||||
use miner::{Miner, MinerService, AccountDetails};
|
|
||||||
|
|
||||||
const MAX_TX_QUEUE_SIZE: usize = 4096;
|
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;
|
||||||
@ -119,6 +143,7 @@ pub struct Client {
|
|||||||
liveness: AtomicBool,
|
liveness: AtomicBool,
|
||||||
io_channel: IoChannel<NetSyncMessage>,
|
io_channel: IoChannel<NetSyncMessage>,
|
||||||
queue_transactions: AtomicUsize,
|
queue_transactions: AtomicUsize,
|
||||||
|
previous_enode: Mutex<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const HISTORY: u64 = 1200;
|
const HISTORY: u64 = 1200;
|
||||||
@ -204,6 +229,7 @@ impl Client {
|
|||||||
miner: miner,
|
miner: miner,
|
||||||
io_channel: message_channel,
|
io_channel: message_channel,
|
||||||
queue_transactions: AtomicUsize::new(0),
|
queue_transactions: AtomicUsize::new(0),
|
||||||
|
previous_enode: Mutex::new(None),
|
||||||
};
|
};
|
||||||
Ok(Arc::new(client))
|
Ok(Arc::new(client))
|
||||||
}
|
}
|
||||||
@ -258,7 +284,7 @@ impl Client {
|
|||||||
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
|
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
|
||||||
let db = self.state_db.lock().unwrap().boxed_clone();
|
let db = self.state_db.lock().unwrap().boxed_clone();
|
||||||
|
|
||||||
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory, self.trie_factory.clone());
|
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, &self.vm_factory, self.trie_factory.clone());
|
||||||
if let Err(e) = enact_result {
|
if let Err(e) = enact_result {
|
||||||
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
return Err(());
|
return Err(());
|
||||||
@ -409,12 +435,8 @@ impl Client {
|
|||||||
pub fn import_queued_transactions(&self, transactions: &[Bytes]) -> usize {
|
pub fn import_queued_transactions(&self, transactions: &[Bytes]) -> usize {
|
||||||
let _timer = PerfTimer::new("import_queued_transactions");
|
let _timer = PerfTimer::new("import_queued_transactions");
|
||||||
self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst);
|
self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst);
|
||||||
let fetch_account = |a: &Address| AccountDetails {
|
let txs = transactions.iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
|
||||||
nonce: self.latest_nonce(a),
|
let results = self.miner.import_external_transactions(self, txs);
|
||||||
balance: self.latest_balance(a),
|
|
||||||
};
|
|
||||||
let tx = transactions.iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
|
|
||||||
let results = self.miner.import_transactions(self, tx, fetch_account);
|
|
||||||
results.len()
|
results.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +476,7 @@ impl Client {
|
|||||||
HeaderView::new(&self.best_block_header()).state_root(),
|
HeaderView::new(&self.best_block_header()).state_root(),
|
||||||
self.engine.account_start_nonce(),
|
self.engine.account_start_nonce(),
|
||||||
self.trie_factory.clone())
|
self.trie_factory.clone())
|
||||||
.expect("State root of best block header always valid.")
|
.expect("State root of best block header always valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get info on the cache.
|
/// Get info on the cache.
|
||||||
@ -563,8 +585,22 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Notify us that the network has been started.
|
||||||
|
pub fn network_started(&self, url: &String) {
|
||||||
|
let mut previous_enode = self.previous_enode.lock().unwrap();
|
||||||
|
if let Some(ref u) = *previous_enode {
|
||||||
|
if u == url {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*previous_enode = Some(url.clone());
|
||||||
|
info!(target: "mode", "Public node URL: {}", url.apply(Colour::White.bold()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Ipc)]
|
||||||
|
#[ipc(client_ident="RemoteClient")]
|
||||||
impl BlockChainClient for Client {
|
impl BlockChainClient for Client {
|
||||||
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
||||||
let header = self.block_header(BlockID::Latest).unwrap();
|
let header = self.block_header(BlockID::Latest).unwrap();
|
||||||
@ -578,7 +614,6 @@ impl BlockChainClient for Client {
|
|||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
gas_used: U256::zero(),
|
gas_used: U256::zero(),
|
||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit(view.parent_hash()),
|
|
||||||
};
|
};
|
||||||
// that's just a copy of the state.
|
// that's just a copy of the state.
|
||||||
let mut state = self.state();
|
let mut state = self.state();
|
||||||
@ -802,8 +837,8 @@ impl BlockChainClient for Client {
|
|||||||
receipt.logs.into_iter()
|
receipt.logs.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|tuple| filter.matches(&tuple.1))
|
.filter(|tuple| filter.matches(&tuple.1))
|
||||||
.map(|(i, log)| LocalizedLogEntry {
|
.map(|(i, log)| LocalizedLogEntry {
|
||||||
entry: log,
|
entry: log,
|
||||||
block_hash: hash.clone(),
|
block_hash: hash.clone(),
|
||||||
block_number: number,
|
block_number: number,
|
||||||
transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new),
|
transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new),
|
||||||
@ -813,7 +848,6 @@ impl BlockChainClient for Client {
|
|||||||
.collect::<Vec<LocalizedLogEntry>>()
|
.collect::<Vec<LocalizedLogEntry>>()
|
||||||
})
|
})
|
||||||
.collect::<Vec<LocalizedLogEntry>>()
|
.collect::<Vec<LocalizedLogEntry>>()
|
||||||
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -862,18 +896,6 @@ impl BlockChainClient for Client {
|
|||||||
self.build_last_hashes(self.chain.best_block_hash())
|
self.build_last_hashes(self.chain.best_block_hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>> {
|
|
||||||
let fetch_account = |a: &Address| AccountDetails {
|
|
||||||
nonce: self.latest_nonce(a),
|
|
||||||
balance: self.latest_balance(a),
|
|
||||||
};
|
|
||||||
|
|
||||||
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<Bytes>) {
|
fn queue_transactions(&self, transactions: Vec<Bytes>) {
|
||||||
if self.queue_transactions.load(AtomicOrdering::Relaxed) > MAX_TX_QUEUE_SIZE {
|
if self.queue_transactions.load(AtomicOrdering::Relaxed) > MAX_TX_QUEUE_SIZE {
|
||||||
debug!("Ignoring {} transactions: queue is full", transactions.len());
|
debug!("Ignoring {} transactions: queue is full", transactions.len());
|
||||||
@ -908,7 +930,6 @@ impl MiningBlockChainClient for Client {
|
|||||||
self.state_db.lock().unwrap().boxed_clone(),
|
self.state_db.lock().unwrap().boxed_clone(),
|
||||||
&self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),
|
&self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),
|
||||||
self.build_last_hashes(h.clone()),
|
self.build_last_hashes(h.clone()),
|
||||||
self.dao_rescue_block_gas_limit(h.clone()),
|
|
||||||
author,
|
author,
|
||||||
gas_range_target,
|
gas_range_target,
|
||||||
extra_data,
|
extra_data,
|
||||||
@ -970,3 +991,5 @@ impl MayPanic for Client {
|
|||||||
self.panic_handler.on_panic(closure);
|
self.panic_handler.on_panic(closure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IpcConfig for Client { }
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
//! Blockchain database client.
|
//! Blockchain database client.
|
||||||
|
|
||||||
mod client;
|
|
||||||
mod config;
|
mod config;
|
||||||
mod error;
|
mod error;
|
||||||
mod test_client;
|
mod test_client;
|
||||||
@ -27,7 +26,7 @@ pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockQueue
|
|||||||
pub use self::error::Error;
|
pub use self::error::Error;
|
||||||
pub use types::ids::*;
|
pub use types::ids::*;
|
||||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||||
pub use self::trace::Filter as TraceFilter;
|
pub use types::trace_filter::Filter as TraceFilter;
|
||||||
pub use executive::{Executed, Executive, TransactOptions};
|
pub use executive::{Executed, Executive, TransactOptions};
|
||||||
pub use env_info::{LastHashes, EnvInfo};
|
pub use env_info::{LastHashes, EnvInfo};
|
||||||
|
|
||||||
@ -42,23 +41,21 @@ use header::{BlockNumber};
|
|||||||
use transaction::{LocalizedTransaction, SignedTransaction};
|
use transaction::{LocalizedTransaction, SignedTransaction};
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use views::{HeaderView, BlockView};
|
use views::{BlockView};
|
||||||
use error::{ImportResult, ExecutionError};
|
use error::{ImportResult, ExecutionError};
|
||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
use evm::Factory as EvmFactory;
|
use evm::Factory as EvmFactory;
|
||||||
|
pub use types::call_analytics::CallAnalytics;
|
||||||
pub use block_import_error::BlockImportError;
|
pub use block_import_error::BlockImportError;
|
||||||
pub use transaction_import::{TransactionImportResult, TransactionImportError};
|
pub use transaction_import::TransactionImportResult;
|
||||||
|
pub use transaction_import::TransactionImportError;
|
||||||
|
|
||||||
/// Options concerning what analytics we run on the call.
|
pub mod client {
|
||||||
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
|
//! Blockchain database client.
|
||||||
pub struct CallAnalytics {
|
|
||||||
/// Make a transaction trace.
|
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
|
||||||
pub transaction_tracing: bool,
|
include!(concat!(env!("OUT_DIR"), "/client.ipc.rs"));
|
||||||
/// Make a VM trace.
|
|
||||||
pub vm_tracing: bool,
|
|
||||||
/// Make a diff.
|
|
||||||
pub state_diffing: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
||||||
@ -192,9 +189,6 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
/// Get last hashes starting from best block.
|
/// Get last hashes starting from best block.
|
||||||
fn last_hashes(&self) -> LastHashes;
|
fn last_hashes(&self) -> LastHashes;
|
||||||
|
|
||||||
/// import transactions from network/other 3rd party
|
|
||||||
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>>;
|
|
||||||
|
|
||||||
/// Queue transactions for importing.
|
/// Queue transactions for importing.
|
||||||
fn queue_transactions(&self, transactions: Vec<Bytes>);
|
fn queue_transactions(&self, transactions: Vec<Bytes>);
|
||||||
|
|
||||||
@ -226,28 +220,6 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get `Some` gas limit of SOFT_FORK_BLOCK, or `None` if chain is not yet that long.
|
|
||||||
fn dao_rescue_block_gas_limit(&self, chain_hash: H256) -> Option<U256> {
|
|
||||||
const SOFT_FORK_BLOCK: u64 = 1800000;
|
|
||||||
// shortcut if the canon chain is already known.
|
|
||||||
if self.chain_info().best_block_number > SOFT_FORK_BLOCK + 1000 {
|
|
||||||
return self.block_header(BlockID::Number(SOFT_FORK_BLOCK)).map(|header| HeaderView::new(&header).gas_limit());
|
|
||||||
}
|
|
||||||
// otherwise check according to `chain_hash`.
|
|
||||||
if let Some(mut header) = self.block_header(BlockID::Hash(chain_hash)) {
|
|
||||||
if HeaderView::new(&header).number() < SOFT_FORK_BLOCK {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
while HeaderView::new(&header).number() != SOFT_FORK_BLOCK {
|
|
||||||
header = self.block_header(BlockID::Hash(HeaderView::new(&header).parent_hash())).expect("chain is complete; parent of chain entry must be in chain; qed");
|
|
||||||
}
|
|
||||||
Some(HeaderView::new(&header).gas_limit())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extended client interface used for mining
|
/// Extended client interface used for mining
|
||||||
|
@ -22,7 +22,7 @@ use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
|
|||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
|
use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
|
||||||
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics,
|
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics,
|
||||||
TransactionImportError, BlockImportError};
|
BlockImportError};
|
||||||
use header::{Header as BlockHeader, BlockNumber};
|
use header::{Header as BlockHeader, BlockNumber};
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
@ -36,11 +36,9 @@ use spec::Spec;
|
|||||||
use block_queue::BlockQueueInfo;
|
use block_queue::BlockQueueInfo;
|
||||||
use block::{OpenBlock, SealedBlock};
|
use block::{OpenBlock, SealedBlock};
|
||||||
use executive::Executed;
|
use executive::Executed;
|
||||||
use error::{ExecutionError};
|
use error::ExecutionError;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
|
|
||||||
use miner::{TransactionImportResult, AccountDetails};
|
|
||||||
|
|
||||||
/// Test client.
|
/// Test client.
|
||||||
pub struct TestBlockChainClient {
|
pub struct TestBlockChainClient {
|
||||||
/// Blocks.
|
/// Blocks.
|
||||||
@ -275,6 +273,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn latest_nonce(&self, address: &Address) -> U256 {
|
||||||
|
self.nonce(address, BlockID::Latest).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn code(&self, address: &Address) -> Option<Bytes> {
|
fn code(&self, address: &Address) -> Option<Bytes> {
|
||||||
self.code.read().unwrap().get(address).cloned()
|
self.code.read().unwrap().get(address).cloned()
|
||||||
}
|
}
|
||||||
@ -287,6 +289,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn latest_balance(&self, address: &Address) -> U256 {
|
||||||
|
self.balance(address, BlockID::Latest).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn storage_at(&self, address: &Address, position: &H256, id: BlockID) -> Option<H256> {
|
fn storage_at(&self, address: &Address, position: &H256, id: BlockID) -> Option<H256> {
|
||||||
if let BlockID::Latest = id {
|
if let BlockID::Latest = id {
|
||||||
Some(self.storage.read().unwrap().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new))
|
Some(self.storage.read().unwrap().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new))
|
||||||
@ -488,24 +494,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>> {
|
|
||||||
let nonces = self.nonces.read().unwrap();
|
|
||||||
let balances = self.balances.read().unwrap();
|
|
||||||
let fetch_account = |a: &Address| AccountDetails {
|
|
||||||
nonce: nonces[a],
|
|
||||||
balance: balances[a],
|
|
||||||
};
|
|
||||||
|
|
||||||
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<Bytes>) {
|
fn queue_transactions(&self, transactions: Vec<Bytes>) {
|
||||||
// import right here
|
// import right here
|
||||||
let tx = transactions.into_iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
|
let txs = transactions.into_iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
|
||||||
self.import_transactions(tx);
|
self.miner.import_external_transactions(self, txs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
|
|
||||||
//! Bridge between Tracedb and Blockchain.
|
//! Bridge between Tracedb and Blockchain.
|
||||||
|
|
||||||
use std::ops::Range;
|
use util::{H256};
|
||||||
use util::{Address, H256};
|
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use trace::DatabaseExtras as TraceDatabaseExtras;
|
use trace::DatabaseExtras as TraceDatabaseExtras;
|
||||||
use blockchain::{BlockChain, BlockProvider};
|
use blockchain::{BlockChain, BlockProvider};
|
||||||
use blockchain::extras::TransactionAddress;
|
use blockchain::extras::TransactionAddress;
|
||||||
use super::BlockID;
|
pub use types::trace_filter::Filter;
|
||||||
|
|
||||||
impl TraceDatabaseExtras for BlockChain {
|
impl TraceDatabaseExtras for BlockChain {
|
||||||
fn block_hash(&self, block_number: BlockNumber) -> Option<H256> {
|
fn block_hash(&self, block_number: BlockNumber) -> Option<H256> {
|
||||||
@ -26,13 +25,3 @@ impl TraceDatabaseExtras for BlockChain {
|
|||||||
.map(|tx| tx.hash())
|
.map(|tx| tx.hash())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Easy to use trace filter.
|
|
||||||
pub struct Filter {
|
|
||||||
/// Range of filtering.
|
|
||||||
pub range: Range<BlockID>,
|
|
||||||
/// From address.
|
|
||||||
pub from_address: Vec<Address>,
|
|
||||||
/// To address.
|
|
||||||
pub to_address: Vec<Address>,
|
|
||||||
}
|
|
||||||
|
@ -39,9 +39,6 @@ pub struct EnvInfo {
|
|||||||
pub last_hashes: LastHashes,
|
pub last_hashes: LastHashes,
|
||||||
/// The gas used.
|
/// The gas used.
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
|
|
||||||
/// Block gas limit at DAO rescue block SOFT_FORK_BLOCK or None if not yet there.
|
|
||||||
pub dao_rescue_block_gas_limit: Option<U256>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for EnvInfo {
|
impl Default for EnvInfo {
|
||||||
@ -54,7 +51,6 @@ impl Default for EnvInfo {
|
|||||||
gas_limit: 0.into(),
|
gas_limit: 0.into(),
|
||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
dao_rescue_block_gas_limit: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +66,6 @@ impl From<ethjson::vm::Env> for EnvInfo {
|
|||||||
timestamp: e.timestamp.into(),
|
timestamp: e.timestamp.into(),
|
||||||
last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
|
last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
|
||||||
gas_used: U256::zero(),
|
gas_used: U256::zero(),
|
||||||
dao_rescue_block_gas_limit: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,9 @@ use util::*;
|
|||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use basic_types::LogBloom;
|
use basic_types::LogBloom;
|
||||||
use client::Error as ClientError;
|
use client::Error as ClientError;
|
||||||
pub use types::executed::ExecutionError;
|
|
||||||
use ipc::binary::{BinaryConvertError, BinaryConvertable};
|
use ipc::binary::{BinaryConvertError, BinaryConvertable};
|
||||||
use types::block_import_error::BlockImportError;
|
use types::block_import_error::BlockImportError;
|
||||||
|
pub use types::executed::ExecutionError;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
/// Errors concerning transaction processing.
|
/// Errors concerning transaction processing.
|
||||||
@ -327,7 +327,6 @@ binary_fixed_size!(BlockError);
|
|||||||
binary_fixed_size!(ImportError);
|
binary_fixed_size!(ImportError);
|
||||||
binary_fixed_size!(TransactionError);
|
binary_fixed_size!(TransactionError);
|
||||||
|
|
||||||
|
|
||||||
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
|
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
|
||||||
/*#![feature(concat_idents)]
|
/*#![feature(concat_idents)]
|
||||||
macro_rules! assimilate {
|
macro_rules! assimilate {
|
||||||
|
@ -39,8 +39,6 @@ pub struct EthashParams {
|
|||||||
pub registrar: Address,
|
pub registrar: Address,
|
||||||
/// Homestead transition block number.
|
/// Homestead transition block number.
|
||||||
pub frontier_compatibility_mode_limit: u64,
|
pub frontier_compatibility_mode_limit: u64,
|
||||||
/// Enable the soft-fork logic.
|
|
||||||
pub dao_rescue_soft_fork: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::EthashParams> for EthashParams {
|
impl From<ethjson::spec::EthashParams> for EthashParams {
|
||||||
@ -53,7 +51,6 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
|
|||||||
block_reward: p.block_reward.into(),
|
block_reward: p.block_reward.into(),
|
||||||
registrar: p.registrar.into(),
|
registrar: p.registrar.into(),
|
||||||
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.into(),
|
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.into(),
|
||||||
dao_rescue_soft_fork: p.dao_rescue_soft_fork.into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,11 +99,7 @@ impl Engine for Ethash {
|
|||||||
if env_info.number < self.ethash_params.frontier_compatibility_mode_limit {
|
if env_info.number < self.ethash_params.frontier_compatibility_mode_limit {
|
||||||
Schedule::new_frontier()
|
Schedule::new_frontier()
|
||||||
} else {
|
} else {
|
||||||
let mut s = Schedule::new_homestead();
|
Schedule::new_homestead()
|
||||||
if self.ethash_params.dao_rescue_soft_fork {
|
|
||||||
s.reject_dao_transactions = env_info.dao_rescue_block_gas_limit.map_or(false, |x| x <= 4_000_000.into());
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +318,7 @@ mod tests {
|
|||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close();
|
let b = b.close();
|
||||||
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
|
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
|
||||||
}
|
}
|
||||||
@ -340,7 +333,7 @@ mod tests {
|
|||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let mut uncle = Header::new();
|
let mut uncle = Header::new();
|
||||||
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
|
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
|
||||||
uncle.author = uncle_author.clone();
|
uncle.author = uncle_author.clone();
|
||||||
@ -369,7 +362,6 @@ mod tests {
|
|||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into(),
|
gas_limit: 0.into(),
|
||||||
dao_rescue_block_gas_limit: None,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(schedule.stack_limit > 0);
|
assert!(schedule.stack_limit > 0);
|
||||||
@ -382,7 +374,6 @@ mod tests {
|
|||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into(),
|
gas_limit: 0.into(),
|
||||||
dao_rescue_block_gas_limit: None,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(!schedule.have_delegate_call);
|
assert!(!schedule.have_delegate_call);
|
||||||
|
@ -33,11 +33,8 @@ use super::spec::*;
|
|||||||
pub fn new_olympic() -> Spec { Spec::load(include_bytes!("../../res/ethereum/olympic.json")) }
|
pub fn new_olympic() -> Spec { Spec::load(include_bytes!("../../res/ethereum/olympic.json")) }
|
||||||
|
|
||||||
/// Create a new Frontier mainnet chain spec.
|
/// Create a new Frontier mainnet chain spec.
|
||||||
pub fn new_frontier(dao_rescue: bool) -> Spec {
|
pub fn new_frontier() -> Spec {
|
||||||
Spec::load(match dao_rescue {
|
Spec::load(include_bytes!("../../res/ethereum/frontier.json"))
|
||||||
true => include_bytes!("../../res/ethereum/frontier_dao_rescue.json"),
|
|
||||||
false => include_bytes!("../../res/ethereum/frontier.json"),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Frontier chain spec as though it never changes to Homestead.
|
/// Create a new Frontier chain spec as though it never changes to Homestead.
|
||||||
@ -89,7 +86,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn frontier() {
|
fn frontier() {
|
||||||
let frontier = new_frontier(true);
|
let frontier = new_frontier();
|
||||||
|
|
||||||
assert_eq!(frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap());
|
assert_eq!(frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap());
|
||||||
let genesis = frontier.genesis_block();
|
let genesis = frontier.genesis_block();
|
||||||
|
@ -319,7 +319,6 @@ mod tests {
|
|||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: 0.into(),
|
gas_used: 0.into(),
|
||||||
gas_limit: 0.into(),
|
gas_limit: 0.into(),
|
||||||
dao_rescue_block_gas_limit: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +95,8 @@ extern crate rayon;
|
|||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate ethash;
|
extern crate ethash;
|
||||||
pub extern crate ethstore;
|
pub extern crate ethstore;
|
||||||
|
extern crate semver;
|
||||||
|
extern crate ethcore_ipc_nano as nanoipc;
|
||||||
|
|
||||||
#[cfg(test)] extern crate ethcore_devtools as devtools;
|
#[cfg(test)] extern crate ethcore_devtools as devtools;
|
||||||
#[cfg(feature = "jit" )] extern crate evmjit;
|
#[cfg(feature = "jit" )] extern crate evmjit;
|
||||||
@ -106,7 +108,6 @@ pub mod block_queue;
|
|||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod ethereum;
|
pub mod ethereum;
|
||||||
pub mod filter;
|
|
||||||
pub mod header;
|
pub mod header;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
|
@ -20,7 +20,6 @@ use std::time::{Instant, Duration};
|
|||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use util::using_queue::{UsingQueue, GetAction};
|
use util::using_queue::{UsingQueue, GetAction};
|
||||||
use util::Colour::White;
|
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use views::{BlockView, HeaderView};
|
use views::{BlockView, HeaderView};
|
||||||
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
|
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
|
||||||
@ -316,6 +315,19 @@ impl Miner {
|
|||||||
!have_work
|
!have_work
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_transactions_to_queue(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, origin: TransactionOrigin, transaction_queue: &mut TransactionQueue) ->
|
||||||
|
Vec<Result<TransactionImportResult, Error>> {
|
||||||
|
|
||||||
|
let fetch_account = |a: &Address| AccountDetails {
|
||||||
|
nonce: chain.latest_nonce(a),
|
||||||
|
balance: chain.latest_balance(a),
|
||||||
|
};
|
||||||
|
|
||||||
|
transactions.into_iter()
|
||||||
|
.map(|tx| transaction_queue.add(tx, &fetch_account, origin))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Are we allowed to do a non-mandatory reseal?
|
/// Are we allowed to do a non-mandatory reseal?
|
||||||
fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock().unwrap() }
|
fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock().unwrap() }
|
||||||
}
|
}
|
||||||
@ -356,7 +368,6 @@ impl MinerService for Miner {
|
|||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
gas_used: U256::zero(),
|
gas_used: U256::zero(),
|
||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
dao_rescue_block_gas_limit: chain.dao_rescue_block_gas_limit(header.parent_hash().clone()),
|
|
||||||
};
|
};
|
||||||
// that's just a copy of the state.
|
// that's just a copy of the state.
|
||||||
let mut state = block.state().clone();
|
let mut state = block.state().clone();
|
||||||
@ -479,27 +490,24 @@ impl MinerService for Miner {
|
|||||||
self.gas_range_target.read().unwrap().1
|
self.gas_range_target.read().unwrap().1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
|
fn import_external_transactions(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>) ->
|
||||||
Vec<Result<TransactionImportResult, Error>>
|
Vec<Result<TransactionImportResult, Error>> {
|
||||||
where T: Fn(&Address) -> AccountDetails {
|
|
||||||
let results: Vec<Result<TransactionImportResult, Error>> = {
|
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
||||||
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
let results = self.add_transactions_to_queue(chain, transactions, TransactionOrigin::External,
|
||||||
transactions.into_iter()
|
&mut transaction_queue);
|
||||||
.map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External))
|
|
||||||
.collect()
|
if !results.is_empty() && self.options.reseal_on_external_tx && self.tx_reseal_allowed() {
|
||||||
};
|
|
||||||
if !results.is_empty() && self.options.reseal_on_external_tx && self.tx_reseal_allowed() {
|
|
||||||
self.update_sealing(chain);
|
self.update_sealing(chain);
|
||||||
}
|
}
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_own_transaction<T>(
|
fn import_own_transaction(
|
||||||
&self,
|
&self,
|
||||||
chain: &MiningBlockChainClient,
|
chain: &MiningBlockChainClient,
|
||||||
transaction: SignedTransaction,
|
transaction: SignedTransaction,
|
||||||
fetch_account: T
|
) -> Result<TransactionImportResult, Error> {
|
||||||
) -> Result<TransactionImportResult, Error> where T: Fn(&Address) -> AccountDetails {
|
|
||||||
|
|
||||||
let hash = transaction.hash();
|
let hash = transaction.hash();
|
||||||
trace!(target: "own_tx", "Importing transaction: {:?}", transaction);
|
trace!(target: "own_tx", "Importing transaction: {:?}", transaction);
|
||||||
@ -507,7 +515,7 @@ impl MinerService for Miner {
|
|||||||
let imported = {
|
let imported = {
|
||||||
// Be sure to release the lock before we call enable_and_prepare_sealing
|
// Be sure to release the lock before we call enable_and_prepare_sealing
|
||||||
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
||||||
let import = transaction_queue.add(transaction, &fetch_account, TransactionOrigin::Local);
|
let import = self.add_transactions_to_queue(chain, vec![transaction], TransactionOrigin::Local, &mut transaction_queue).pop().unwrap();
|
||||||
|
|
||||||
match import {
|
match import {
|
||||||
Ok(ref res) => {
|
Ok(ref res) => {
|
||||||
@ -646,7 +654,7 @@ impl MinerService for Miner {
|
|||||||
let n = sealed.header().number();
|
let n = sealed.header().number();
|
||||||
let h = sealed.header().hash();
|
let h = sealed.header().hash();
|
||||||
try!(chain.import_sealed_block(sealed));
|
try!(chain.import_sealed_block(sealed));
|
||||||
info!(target: "miner", "Mined block imported OK. #{}: {}", paint(White.bold(), format!("{}", n)), paint(White.bold(), h.hex()));
|
info!(target: "miner", "Mined block imported OK. #{}: {}", format!("{}", n).apply(Colour::White.bold()), h.hex().apply(Colour::White.bold()));
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -658,7 +666,12 @@ impl MinerService for Miner {
|
|||||||
// Client should send message after commit to db and inserting to chain.
|
// Client should send message after commit to db and inserting to chain.
|
||||||
.expect("Expected in-chain blocks.");
|
.expect("Expected in-chain blocks.");
|
||||||
let block = BlockView::new(&block);
|
let block = BlockView::new(&block);
|
||||||
block.transactions()
|
let txs = block.transactions();
|
||||||
|
// populate sender
|
||||||
|
for tx in &txs {
|
||||||
|
let _sender = tx.sender();
|
||||||
|
}
|
||||||
|
txs
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
|
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
|
||||||
@ -675,14 +688,10 @@ impl MinerService for Miner {
|
|||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|h| fetch_transactions(chain, h));
|
.map(|h| fetch_transactions(chain, h));
|
||||||
out_of_chain.for_each(|txs| {
|
out_of_chain.for_each(|txs| {
|
||||||
// populate sender
|
let mut transaction_queue = self.transaction_queue.lock().unwrap();
|
||||||
for tx in &txs {
|
let _ = self.add_transactions_to_queue(
|
||||||
let _sender = tx.sender();
|
chain, txs, TransactionOrigin::External, &mut transaction_queue
|
||||||
}
|
);
|
||||||
let _ = self.import_transactions(chain, txs, |a| AccountDetails {
|
|
||||||
nonce: chain.latest_nonce(a),
|
|
||||||
balance: chain.latest_balance(a),
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
//! use ethcore::miner::{Miner, MinerService};
|
//! use ethcore::miner::{Miner, MinerService};
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let miner: Miner = Miner::with_spec(ethereum::new_frontier(true));
|
//! let miner: Miner = Miner::with_spec(ethereum::new_frontier());
|
||||||
//! // get status
|
//! // get status
|
||||||
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
||||||
//!
|
//!
|
||||||
@ -107,14 +107,12 @@ pub trait MinerService : Send + Sync {
|
|||||||
fn set_tx_gas_limit(&self, limit: U256);
|
fn set_tx_gas_limit(&self, limit: U256);
|
||||||
|
|
||||||
/// Imports transactions to transaction queue.
|
/// Imports transactions to transaction queue.
|
||||||
fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
|
fn import_external_transactions(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>) ->
|
||||||
Vec<Result<TransactionImportResult, Error>>
|
Vec<Result<TransactionImportResult, Error>>;
|
||||||
where T: Fn(&Address) -> AccountDetails, Self: Sized;
|
|
||||||
|
|
||||||
/// Imports own (node owner) transaction to queue.
|
/// Imports own (node owner) transaction to queue.
|
||||||
fn import_own_transaction<T>(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, fetch_account: T) ->
|
fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction) ->
|
||||||
Result<TransactionImportResult, Error>
|
Result<TransactionImportResult, Error>;
|
||||||
where T: Fn(&Address) -> AccountDetails, Self: Sized;
|
|
||||||
|
|
||||||
/// Returns hashes of transactions currently in pending
|
/// Returns hashes of transactions currently in pending
|
||||||
fn pending_transactions_hashes(&self) -> Vec<H256>;
|
fn pending_transactions_hashes(&self) -> Vec<H256>;
|
||||||
|
@ -198,6 +198,7 @@ struct VerifiedTransaction {
|
|||||||
/// transaction origin
|
/// transaction origin
|
||||||
origin: TransactionOrigin,
|
origin: TransactionOrigin,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerifiedTransaction {
|
impl VerifiedTransaction {
|
||||||
fn new(transaction: SignedTransaction, origin: TransactionOrigin) -> Result<Self, Error> {
|
fn new(transaction: SignedTransaction, origin: TransactionOrigin) -> Result<Self, Error> {
|
||||||
try!(transaction.sender());
|
try!(transaction.sender());
|
||||||
|
@ -72,7 +72,7 @@ impl fmt::Display for PodState {
|
|||||||
|
|
||||||
/// Calculate and return diff between `pre` state and `post` state.
|
/// Calculate and return diff between `pre` state and `post` state.
|
||||||
pub fn diff_pod(pre: &PodState, post: &PodState) -> StateDiff {
|
pub fn diff_pod(pre: &PodState, post: &PodState) -> StateDiff {
|
||||||
StateDiff(pre.get().keys().merge(post.get().keys()).filter_map(|acc| pod_account::diff_pod(pre.get().get(acc), post.get().get(acc)).map(|d|(acc.clone(), d))).collect())
|
StateDiff { raw: pre.get().keys().merge(post.get().keys()).filter_map(|acc| pod_account::diff_pod(pre.get().get(acc), post.get().get(acc)).map(|d|(acc.clone(), d))).collect() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -86,22 +86,22 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn create_delete() {
|
fn create_delete() {
|
||||||
let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]);
|
let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]);
|
||||||
assert_eq!(super::diff_pod(&a, &PodState::new()), StateDiff(map![
|
assert_eq!(super::diff_pod(&a, &PodState::new()), StateDiff { raw: map![
|
||||||
1.into() => AccountDiff{
|
1.into() => AccountDiff{
|
||||||
balance: Diff::Died(69.into()),
|
balance: Diff::Died(69.into()),
|
||||||
nonce: Diff::Died(0.into()),
|
nonce: Diff::Died(0.into()),
|
||||||
code: Diff::Died(vec![]),
|
code: Diff::Died(vec![]),
|
||||||
storage: map![],
|
storage: map![],
|
||||||
}
|
}
|
||||||
]));
|
]});
|
||||||
assert_eq!(super::diff_pod(&PodState::new(), &a), StateDiff(map![
|
assert_eq!(super::diff_pod(&PodState::new(), &a), StateDiff{ raw: map![
|
||||||
1.into() => AccountDiff{
|
1.into() => AccountDiff{
|
||||||
balance: Diff::Born(69.into()),
|
balance: Diff::Born(69.into()),
|
||||||
nonce: Diff::Born(0.into()),
|
nonce: Diff::Born(0.into()),
|
||||||
code: Diff::Born(vec![]),
|
code: Diff::Born(vec![]),
|
||||||
storage: map![],
|
storage: map![],
|
||||||
}
|
}
|
||||||
]));
|
]});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -111,22 +111,22 @@ mod test {
|
|||||||
1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]),
|
1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]),
|
||||||
2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
|
2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
|
||||||
]);
|
]);
|
||||||
assert_eq!(super::diff_pod(&a, &b), StateDiff(map![
|
assert_eq!(super::diff_pod(&a, &b), StateDiff { raw: map![
|
||||||
2.into() => AccountDiff{
|
2.into() => AccountDiff{
|
||||||
balance: Diff::Born(69.into()),
|
balance: Diff::Born(69.into()),
|
||||||
nonce: Diff::Born(0.into()),
|
nonce: Diff::Born(0.into()),
|
||||||
code: Diff::Born(vec![]),
|
code: Diff::Born(vec![]),
|
||||||
storage: map![],
|
storage: map![],
|
||||||
}
|
}
|
||||||
]));
|
]});
|
||||||
assert_eq!(super::diff_pod(&b, &a), StateDiff(map![
|
assert_eq!(super::diff_pod(&b, &a), StateDiff { raw: map![
|
||||||
2.into() => AccountDiff{
|
2.into() => AccountDiff{
|
||||||
balance: Diff::Died(69.into()),
|
balance: Diff::Died(69.into()),
|
||||||
nonce: Diff::Died(0.into()),
|
nonce: Diff::Died(0.into()),
|
||||||
code: Diff::Died(vec![]),
|
code: Diff::Died(vec![]),
|
||||||
storage: map![],
|
storage: map![],
|
||||||
}
|
}
|
||||||
]));
|
]});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -139,14 +139,14 @@ mod test {
|
|||||||
1.into() => PodAccount::new(69.into(), 1.into(), vec![], map![]),
|
1.into() => PodAccount::new(69.into(), 1.into(), vec![], map![]),
|
||||||
2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
|
2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![])
|
||||||
]);
|
]);
|
||||||
assert_eq!(super::diff_pod(&a, &b), StateDiff(map![
|
assert_eq!(super::diff_pod(&a, &b), StateDiff { raw: map![
|
||||||
1.into() => AccountDiff{
|
1.into() => AccountDiff{
|
||||||
balance: Diff::Same,
|
balance: Diff::Same,
|
||||||
nonce: Diff::Changed(0.into(), 1.into()),
|
nonce: Diff::Changed(0.into(), 1.into()),
|
||||||
code: Diff::Same,
|
code: Diff::Same,
|
||||||
storage: map![],
|
storage: map![],
|
||||||
}
|
}
|
||||||
]));
|
]});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
//! Creates and registers client and network services.
|
//! Creates and registers client and network services.
|
||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use util::Colour::{Yellow, White};
|
|
||||||
use util::panics::*;
|
use util::panics::*;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use error::*;
|
use error::*;
|
||||||
@ -72,7 +71,7 @@ impl ClientService {
|
|||||||
try!(net_service.start());
|
try!(net_service.start());
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Configured for {} using {} engine", paint(White.bold(), spec.name.clone()), paint(Yellow.bold(), spec.engine.name().to_owned()));
|
info!("Configured for {} using {} engine", spec.name.clone().apply(Colour::White.bold()), spec.engine.name().apply(Colour::Yellow.bold()));
|
||||||
let client = try!(Client::new(config, spec, db_path, miner, net_service.io().channel()));
|
let client = try!(Client::new(config, spec, db_path, miner, net_service.io().channel()));
|
||||||
panic_handler.forward_from(client.deref());
|
panic_handler.forward_from(client.deref());
|
||||||
let client_io = Arc::new(ClientIoHandler {
|
let client_io = Arc::new(ClientIoHandler {
|
||||||
@ -135,16 +134,14 @@ impl IoHandler<NetSyncMessage> for ClientIoHandler {
|
|||||||
|
|
||||||
#[cfg_attr(feature="dev", allow(single_match))]
|
#[cfg_attr(feature="dev", allow(single_match))]
|
||||||
fn message(&self, io: &IoContext<NetSyncMessage>, net_message: &NetSyncMessage) {
|
fn message(&self, io: &IoContext<NetSyncMessage>, net_message: &NetSyncMessage) {
|
||||||
if let UserMessage(ref message) = *net_message {
|
match *net_message {
|
||||||
match *message {
|
UserMessage(ref message) => match *message {
|
||||||
SyncMessage::BlockVerified => {
|
SyncMessage::BlockVerified => { self.client.import_verified_blocks(&io.channel()); }
|
||||||
self.client.import_verified_blocks(&io.channel());
|
SyncMessage::NewTransactions(ref transactions) => { self.client.import_queued_transactions(&transactions); }
|
||||||
},
|
_ => {} // ignore other messages
|
||||||
SyncMessage::NewTransactions(ref transactions) => {
|
},
|
||||||
self.client.import_queued_transactions(&transactions);
|
NetworkIoMessage::NetworkStarted(ref url) => { self.client.network_started(url); }
|
||||||
},
|
_ => {} // ignore other messages
|
||||||
_ => {}, // ignore other messages
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,6 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
|
|||||||
db,
|
db,
|
||||||
&last_header,
|
&last_header,
|
||||||
last_hashes.clone(),
|
last_hashes.clone(),
|
||||||
None,
|
|
||||||
author.clone(),
|
author.clone(),
|
||||||
(3141562.into(), 31415620.into()),
|
(3141562.into(), 31415620.into()),
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -16,3 +16,4 @@
|
|||||||
|
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
mod client;
|
mod client;
|
||||||
|
mod rpc;
|
||||||
|
71
ethcore/src/tests/rpc.rs
Normal file
71
ethcore/src/tests/rpc.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Client RPC tests
|
||||||
|
|
||||||
|
use nanoipc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{Ordering, AtomicBool};
|
||||||
|
use client::{Client, BlockChainClient, ClientConfig, RemoteClient, BlockID};
|
||||||
|
use tests::helpers::*;
|
||||||
|
use devtools::*;
|
||||||
|
use miner::Miner;
|
||||||
|
use crossbeam;
|
||||||
|
use common::IoChannel;
|
||||||
|
|
||||||
|
pub fn run_test_worker(scope: &crossbeam::Scope, stop: Arc<AtomicBool>, socket_path: &str) {
|
||||||
|
let socket_path = socket_path.to_owned();
|
||||||
|
scope.spawn(move || {
|
||||||
|
let temp = RandomTempPath::create_dir();
|
||||||
|
let client = Client::new(
|
||||||
|
ClientConfig::default(),
|
||||||
|
get_test_spec(),
|
||||||
|
temp.as_path(),
|
||||||
|
Arc::new(Miner::with_spec(get_test_spec())),
|
||||||
|
IoChannel::disconnected()).unwrap();
|
||||||
|
let mut worker = nanoipc::Worker::new(&client);
|
||||||
|
worker.add_reqrep(&socket_path).unwrap();
|
||||||
|
while !stop.load(Ordering::Relaxed) {
|
||||||
|
worker.poll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_handshake() {
|
||||||
|
crossbeam::scope(|scope| {
|
||||||
|
let stop_guard = StopGuard::new();
|
||||||
|
let socket_path = "ipc:///tmp/parity-client-rpc-10.ipc";
|
||||||
|
run_test_worker(scope, stop_guard.share(), socket_path);
|
||||||
|
let remote_client = nanoipc::init_client::<RemoteClient<_>>(socket_path).unwrap();
|
||||||
|
|
||||||
|
assert!(remote_client.handshake().is_ok());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_query_block() {
|
||||||
|
crossbeam::scope(|scope| {
|
||||||
|
let stop_guard = StopGuard::new();
|
||||||
|
let socket_path = "ipc:///tmp/parity-client-rpc-20.ipc";
|
||||||
|
run_test_worker(scope, stop_guard.share(), socket_path);
|
||||||
|
let remote_client = nanoipc::init_client::<RemoteClient<_>>(socket_path).unwrap();
|
||||||
|
|
||||||
|
let non_existant_block = remote_client.block_header(BlockID::Number(999));
|
||||||
|
|
||||||
|
assert!(non_existant_block.is_none());
|
||||||
|
})
|
||||||
|
}
|
@ -16,11 +16,17 @@
|
|||||||
|
|
||||||
//! Diff between two accounts.
|
//! Diff between two accounts.
|
||||||
|
|
||||||
use util::*;
|
use util::numbers::*;
|
||||||
|
use std::cmp::*;
|
||||||
|
use std::fmt;
|
||||||
|
use ipc::binary::{BinaryConvertError, BinaryConvertable};
|
||||||
|
use util::Bytes;
|
||||||
|
use std::collections::{VecDeque, BTreeMap};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone, Binary)]
|
||||||
/// Diff type for specifying a change (or not).
|
/// Diff type for specifying a change (or not).
|
||||||
pub enum Diff<T> where T: Eq {
|
pub enum Diff<T> where T: Eq + BinaryConvertable {
|
||||||
/// Both sides are the same.
|
/// Both sides are the same.
|
||||||
Same,
|
Same,
|
||||||
/// Left (pre, source) side doesn't include value, right side (post, destination) does.
|
/// Left (pre, source) side doesn't include value, right side (post, destination) does.
|
||||||
@ -31,7 +37,7 @@ pub enum Diff<T> where T: Eq {
|
|||||||
Died(T),
|
Died(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Diff<T> where T: Eq {
|
impl<T> Diff<T> where T: Eq + BinaryConvertable {
|
||||||
/// Construct new object with given `pre` and `post`.
|
/// Construct new object with given `pre` and `post`.
|
||||||
pub fn new(pre: T, post: T) -> Self { if pre == post { Diff::Same } else { Diff::Changed(pre, post) } }
|
pub fn new(pre: T, post: T) -> Self { if pre == post { Diff::Same } else { Diff::Changed(pre, post) } }
|
||||||
|
|
||||||
@ -45,7 +51,7 @@ impl<T> Diff<T> where T: Eq {
|
|||||||
pub fn is_same(&self) -> bool { match *self { Diff::Same => true, _ => false }}
|
pub fn is_same(&self) -> bool { match *self { Diff::Same => true, _ => false }}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone, Binary)]
|
||||||
/// Account diff.
|
/// Account diff.
|
||||||
pub struct AccountDiff {
|
pub struct AccountDiff {
|
||||||
/// Change in balance, allowed to be `Diff::Same`.
|
/// Change in balance, allowed to be `Diff::Same`.
|
||||||
@ -58,7 +64,7 @@ pub struct AccountDiff {
|
|||||||
pub storage: BTreeMap<H256, Diff<H256>>,
|
pub storage: BTreeMap<H256, Diff<H256>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone, Binary)]
|
||||||
/// Change in existance type.
|
/// Change in existance type.
|
||||||
// TODO: include other types of change.
|
// TODO: include other types of change.
|
||||||
pub enum Existance {
|
pub enum Existance {
|
||||||
@ -94,6 +100,8 @@ impl AccountDiff {
|
|||||||
|
|
||||||
// TODO: refactor into something nicer.
|
// TODO: refactor into something nicer.
|
||||||
fn interpreted_hash(u: &H256) -> String {
|
fn interpreted_hash(u: &H256) -> String {
|
||||||
|
use util::bytes::*;
|
||||||
|
|
||||||
if u <= &H256::from(0xffffffff) {
|
if u <= &H256::from(0xffffffff) {
|
||||||
format!("{} = 0x{:x}", U256::from(u.as_slice()).low_u32(), U256::from(u.as_slice()).low_u32())
|
format!("{} = 0x{:x}", U256::from(u.as_slice()).low_u32(), U256::from(u.as_slice()).low_u32())
|
||||||
} else if u <= &H256::from(u64::max_value()) {
|
} else if u <= &H256::from(u64::max_value()) {
|
||||||
@ -107,6 +115,8 @@ fn interpreted_hash(u: &H256) -> String {
|
|||||||
|
|
||||||
impl fmt::Display for AccountDiff {
|
impl fmt::Display for AccountDiff {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use util::bytes::*;
|
||||||
|
|
||||||
match self.nonce {
|
match self.nonce {
|
||||||
Diff::Born(ref x) => try!(write!(f, " non {}", x)),
|
Diff::Born(ref x) => try!(write!(f, " non {}", x)),
|
||||||
Diff::Changed(ref pre, ref post) => try!(write!(f, "#{} ({} {} {})", post, pre, if pre > post {"-"} else {"+"}, *max(pre, post) - * min(pre, post))),
|
Diff::Changed(ref pre, ref post) => try!(write!(f, "#{} ({} {} {})", post, pre, if pre > post {"-"} else {"+"}, *max(pre, post) - * min(pre, post))),
|
||||||
|
38
ethcore/src/types/block_queue_info.rs
Normal file
38
ethcore/src/types/block_queue_info.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Block queue info types
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use ipc::binary::BinaryConvertError;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
/// Block queue status
|
||||||
|
#[derive(Debug, Binary)]
|
||||||
|
pub struct BlockQueueInfo {
|
||||||
|
/// Number of queued blocks pending verification
|
||||||
|
pub unverified_queue_size: usize,
|
||||||
|
/// Number of verified queued blocks pending import
|
||||||
|
pub verified_queue_size: usize,
|
||||||
|
/// Number of blocks being verified
|
||||||
|
pub verifying_queue_size: usize,
|
||||||
|
/// Configured maximum number of blocks in the queue
|
||||||
|
pub max_queue_size: usize,
|
||||||
|
/// Configured maximum number of bytes to use
|
||||||
|
pub max_mem_use: usize,
|
||||||
|
/// Heap memory used in bytes
|
||||||
|
pub mem_used: usize,
|
||||||
|
}
|
32
ethcore/src/types/call_analytics.rs
Normal file
32
ethcore/src/types/call_analytics.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Call analytics related types
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use ipc::binary::{BinaryConvertError};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
/// Options concerning what analytics we run on the call.
|
||||||
|
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug, Binary)]
|
||||||
|
pub struct CallAnalytics {
|
||||||
|
/// Make a transaction trace.
|
||||||
|
pub transaction_tracing: bool,
|
||||||
|
/// Make a VM trace.
|
||||||
|
pub vm_tracing: bool,
|
||||||
|
/// Make a diff.
|
||||||
|
pub state_diffing: bool,
|
||||||
|
}
|
@ -27,7 +27,7 @@ use std::mem;
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
/// Transaction execution receipt.
|
/// Transaction execution receipt.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone, Binary)]
|
||||||
pub struct Executed {
|
pub struct Executed {
|
||||||
/// Gas paid up front for execution of transaction.
|
/// Gas paid up front for execution of transaction.
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
@ -20,8 +20,12 @@ use util::hash::*;
|
|||||||
use util::sha3::*;
|
use util::sha3::*;
|
||||||
use client::BlockID;
|
use client::BlockID;
|
||||||
use log_entry::LogEntry;
|
use log_entry::LogEntry;
|
||||||
|
use ipc::binary::BinaryConvertError;
|
||||||
|
use std::mem;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
/// Blockchain Filter.
|
/// Blockchain Filter.
|
||||||
|
#[derive(Binary)]
|
||||||
pub struct Filter {
|
pub struct Filter {
|
||||||
/// Blockchain will be searched from this block.
|
/// Blockchain will be searched from this block.
|
||||||
pub from_block: BlockID,
|
pub from_block: BlockID,
|
||||||
@ -39,12 +43,17 @@ pub struct Filter {
|
|||||||
///
|
///
|
||||||
/// If None, match all.
|
/// If None, match all.
|
||||||
/// If specified, log must contain one of these topics.
|
/// If specified, log must contain one of these topics.
|
||||||
pub topics: [Option<Vec<H256>>; 4],
|
pub topics: Vec<Option<Vec<H256>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Filter {
|
impl Clone for Filter {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let mut topics = [None, None, None, None];
|
let mut topics = [
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
];
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
topics[i] = self.topics[i].clone();
|
topics[i] = self.topics[i].clone();
|
||||||
}
|
}
|
||||||
@ -53,7 +62,7 @@ impl Clone for Filter {
|
|||||||
from_block: self.from_block.clone(),
|
from_block: self.from_block.clone(),
|
||||||
to_block: self.to_block.clone(),
|
to_block: self.to_block.clone(),
|
||||||
address: self.address.clone(),
|
address: self.address.clone(),
|
||||||
topics: topics
|
topics: topics[..].to_vec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +80,7 @@ impl Filter {
|
|||||||
_ => vec![H2048::new()]
|
_ => vec![H2048::new()]
|
||||||
};
|
};
|
||||||
|
|
||||||
self.topics.iter().fold(blooms, | bs, topic | match *topic {
|
self.topics.iter().fold(blooms, |bs, topic| match *topic {
|
||||||
None => bs,
|
None => bs,
|
||||||
Some(ref topics) => bs.into_iter().flat_map(|bloom| {
|
Some(ref topics) => bs.into_iter().flat_map(|bloom| {
|
||||||
topics.into_iter().map(|topic| {
|
topics.into_iter().map(|topic| {
|
||||||
@ -111,7 +120,7 @@ mod tests {
|
|||||||
from_block: BlockID::Earliest,
|
from_block: BlockID::Earliest,
|
||||||
to_block: BlockID::Latest,
|
to_block: BlockID::Latest,
|
||||||
address: None,
|
address: None,
|
||||||
topics: [None, None, None, None]
|
topics: vec![None, None, None, None],
|
||||||
};
|
};
|
||||||
|
|
||||||
let possibilities = none_filter.bloom_possibilities();
|
let possibilities = none_filter.bloom_possibilities();
|
||||||
@ -126,9 +135,11 @@ mod tests {
|
|||||||
from_block: BlockID::Earliest,
|
from_block: BlockID::Earliest,
|
||||||
to_block: BlockID::Latest,
|
to_block: BlockID::Latest,
|
||||||
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
|
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
|
||||||
topics: [
|
topics: vec![
|
||||||
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
||||||
None, None, None
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -142,10 +153,11 @@ mod tests {
|
|||||||
from_block: BlockID::Earliest,
|
from_block: BlockID::Earliest,
|
||||||
to_block: BlockID::Latest,
|
to_block: BlockID::Latest,
|
||||||
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
|
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
|
||||||
topics: [
|
topics: vec![
|
||||||
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
||||||
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
||||||
None, None
|
None,
|
||||||
|
None,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -162,7 +174,7 @@ mod tests {
|
|||||||
Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(),
|
Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(),
|
||||||
Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(),
|
Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(),
|
||||||
]),
|
]),
|
||||||
topics: [
|
topics: vec![
|
||||||
Some(vec![
|
Some(vec![
|
||||||
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(),
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(),
|
||||||
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()
|
||||||
@ -188,10 +200,11 @@ mod tests {
|
|||||||
from_block: BlockID::Earliest,
|
from_block: BlockID::Earliest,
|
||||||
to_block: BlockID::Latest,
|
to_block: BlockID::Latest,
|
||||||
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
|
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
|
||||||
topics: [
|
topics: vec![
|
||||||
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
||||||
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap()]),
|
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap()]),
|
||||||
None, None
|
None,
|
||||||
|
None,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
@ -47,6 +47,7 @@ pub enum TransactionID {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Uniquely identifies Trace.
|
/// Uniquely identifies Trace.
|
||||||
|
#[derive(Binary)]
|
||||||
pub struct TraceId {
|
pub struct TraceId {
|
||||||
/// Transaction
|
/// Transaction
|
||||||
pub transaction: TransactionID,
|
pub transaction: TransactionID,
|
||||||
|
@ -25,5 +25,9 @@ pub mod executed;
|
|||||||
pub mod block_status;
|
pub mod block_status;
|
||||||
pub mod account_diff;
|
pub mod account_diff;
|
||||||
pub mod state_diff;
|
pub mod state_diff;
|
||||||
|
pub mod block_queue_info;
|
||||||
|
pub mod filter;
|
||||||
|
pub mod trace_filter;
|
||||||
|
pub mod call_analytics;
|
||||||
pub mod transaction_import;
|
pub mod transaction_import;
|
||||||
pub mod block_import_error;
|
pub mod block_import_error;
|
||||||
|
@ -16,24 +16,32 @@
|
|||||||
|
|
||||||
//! State diff module.
|
//! State diff module.
|
||||||
|
|
||||||
use util::*;
|
use util::numbers::*;
|
||||||
use account_diff::*;
|
use account_diff::*;
|
||||||
|
use ipc::binary::BinaryConvertError;
|
||||||
|
use std::mem;
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::*;
|
||||||
|
use std::collections::{VecDeque, BTreeMap};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone, Binary)]
|
||||||
/// Expression for the delta between two system states. Encoded the
|
/// Expression for the delta between two system states. Encoded the
|
||||||
/// delta of every altered account.
|
/// delta of every altered account.
|
||||||
pub struct StateDiff (pub BTreeMap<Address, AccountDiff>);
|
pub struct StateDiff {
|
||||||
|
/// Raw diff key-value
|
||||||
|
pub raw: BTreeMap<Address, AccountDiff>
|
||||||
|
}
|
||||||
|
|
||||||
impl StateDiff {
|
impl StateDiff {
|
||||||
/// Get the actual data.
|
/// Get the actual data.
|
||||||
pub fn get(&self) -> &BTreeMap<Address, AccountDiff> {
|
pub fn get(&self) -> &BTreeMap<Address, AccountDiff> {
|
||||||
&self.0
|
&self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for StateDiff {
|
impl fmt::Display for StateDiff {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
for (add, acc) in &self.0 {
|
for (add, acc) in &self.raw {
|
||||||
try!(write!(f, "{} {}: {}", acc.existance(), add, acc));
|
try!(write!(f, "{} {}: {}", acc.existance(), add, acc));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -44,6 +52,6 @@ impl Deref for StateDiff {
|
|||||||
type Target = BTreeMap<Address, AccountDiff>;
|
type Target = BTreeMap<Address, AccountDiff>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
ethcore/src/types/trace_filter.rs
Normal file
35
ethcore/src/types/trace_filter.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Trace filter related types
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use ipc::binary::{BinaryConvertError};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::ops::Range;
|
||||||
|
use util::{Address};
|
||||||
|
use types::ids::BlockID;
|
||||||
|
|
||||||
|
/// Easy to use trace filter.
|
||||||
|
#[derive(Binary)]
|
||||||
|
pub struct Filter {
|
||||||
|
/// Range of filtering.
|
||||||
|
pub range: Range<BlockID>,
|
||||||
|
/// From address.
|
||||||
|
pub from_address: Vec<Address>,
|
||||||
|
/// To address.
|
||||||
|
pub to_address: Vec<Address>,
|
||||||
|
}
|
@ -17,9 +17,12 @@
|
|||||||
//! Tree route info type definition
|
//! Tree route info type definition
|
||||||
|
|
||||||
use util::numbers::H256;
|
use util::numbers::H256;
|
||||||
|
use ipc::BinaryConvertError;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
/// Represents a tree route between `from` block and `to` block:
|
/// Represents a tree route between `from` block and `to` block:
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Binary)]
|
||||||
pub struct TreeRoute {
|
pub struct TreeRoute {
|
||||||
/// A vector of hashes of all blocks, ordered from `from` to `to`.
|
/// A vector of hashes of all blocks, ordered from `from` to `to`.
|
||||||
pub blocks: Vec<H256>,
|
pub blocks: Vec<H256>,
|
||||||
|
@ -727,7 +727,6 @@ pub fn get_ipc_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]>
|
|||||||
fn client_ident_renamed(cx: &ExtCtxt, item: &ast::Item) -> Option<String> {
|
fn client_ident_renamed(cx: &ExtCtxt, item: &ast::Item) -> Option<String> {
|
||||||
for meta_items in item.attrs().iter().filter_map(get_ipc_meta_items) {
|
for meta_items in item.attrs().iter().filter_map(get_ipc_meta_items) {
|
||||||
for meta_item in meta_items {
|
for meta_item in meta_items {
|
||||||
let span = meta_item.span;
|
|
||||||
match meta_item.node {
|
match meta_item.node {
|
||||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"client_ident" => {
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"client_ident" => {
|
||||||
if let Ok(s) = get_str_from_lit(cx, name, lit) {
|
if let Ok(s) = get_str_from_lit(cx, name, lit) {
|
||||||
|
@ -707,7 +707,12 @@ fn binary_expr_variant(
|
|||||||
let buffer = &mut buffer[1..];
|
let buffer = &mut buffer[1..];
|
||||||
$write_expr
|
$write_expr
|
||||||
}),
|
}),
|
||||||
read: quote_arm!(cx, $variant_index_ident => { $read_expr } ),
|
read: quote_arm!(cx,
|
||||||
|
$variant_index_ident => {
|
||||||
|
let buffer = &buffer[1..];
|
||||||
|
$read_expr
|
||||||
|
}
|
||||||
|
),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ast::VariantData::Struct(ref fields, _) => {
|
ast::VariantData::Struct(ref fields, _) => {
|
||||||
@ -742,7 +747,12 @@ fn binary_expr_variant(
|
|||||||
let buffer = &mut buffer[1..];
|
let buffer = &mut buffer[1..];
|
||||||
$write_expr
|
$write_expr
|
||||||
}),
|
}),
|
||||||
read: quote_arm!(cx, $variant_index_ident => { $read_expr } ),
|
read: quote_arm!(cx,
|
||||||
|
$variant_index_ident => {
|
||||||
|
let buffer = &buffer[1..];
|
||||||
|
$read_expr
|
||||||
|
}
|
||||||
|
),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -315,6 +315,31 @@ impl BinaryConvertable for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> BinaryConvertable for Range<T> where T: BinaryConvertable {
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
mem::size_of::<T>() * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
|
||||||
|
Err(BinaryConvertError)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(&self, buffer: &mut[u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
|
||||||
|
try!(self.start.to_bytes(&mut buffer[..mem::size_of::<T>()], length_stack));
|
||||||
|
try!(self.end.to_bytes(&mut buffer[mem::size_of::<T>() + 1..], length_stack));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
|
||||||
|
Ok(try!(T::from_bytes(&buffer[..mem::size_of::<T>()], length_stack))..try!(T::from_bytes(&buffer[mem::size_of::<T>()+1..], length_stack)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len_params() -> usize {
|
||||||
|
assert_eq!(0, T::len_params());
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> BinaryConvertable for ::std::cell::RefCell<T> where T: BinaryConvertable {
|
impl<T> BinaryConvertable for ::std::cell::RefCell<T> where T: BinaryConvertable {
|
||||||
fn size(&self) -> usize {
|
fn size(&self) -> usize {
|
||||||
self.borrow().size()
|
self.borrow().size()
|
||||||
@ -539,8 +564,6 @@ binary_fixed_size!(U512);
|
|||||||
binary_fixed_size!(H256);
|
binary_fixed_size!(H256);
|
||||||
binary_fixed_size!(H2048);
|
binary_fixed_size!(H2048);
|
||||||
binary_fixed_size!(Address);
|
binary_fixed_size!(Address);
|
||||||
binary_fixed_size!(Range<usize>);
|
|
||||||
binary_fixed_size!(Range<u64>);
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn vec_serialize() {
|
fn vec_serialize() {
|
||||||
|
@ -91,7 +91,7 @@ pub fn invoke<W>(method_num: u16, params: &Option<Vec<u8>>, w: &mut W) where W:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// IpcSocket, read/write generalization
|
/// IpcSocket, read/write generalization
|
||||||
pub trait IpcSocket: Read + Write + Sync {
|
pub trait IpcSocket: Read + Write + Sync + Send {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Basically something that needs only socket to be spawned
|
/// Basically something that needs only socket to be spawned
|
||||||
|
@ -53,8 +53,7 @@ mod tests {
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit" : "0x",
|
"frontierCompatibilityModeLimit" : "0x"
|
||||||
"daoRescueSoftFork": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
|
@ -42,9 +42,6 @@ pub struct EthashParams {
|
|||||||
/// Homestead transition block number.
|
/// Homestead transition block number.
|
||||||
#[serde(rename="frontierCompatibilityModeLimit")]
|
#[serde(rename="frontierCompatibilityModeLimit")]
|
||||||
pub frontier_compatibility_mode_limit: Uint,
|
pub frontier_compatibility_mode_limit: Uint,
|
||||||
/// DAO rescue soft-fork?
|
|
||||||
#[serde(rename="daoRescueSoftFork")]
|
|
||||||
pub dao_rescue_soft_fork: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ethash engine deserialization.
|
/// Ethash engine deserialization.
|
||||||
@ -69,8 +66,7 @@ mod tests {
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0x42",
|
"frontierCompatibilityModeLimit": "0x42"
|
||||||
"daoRescueSoftFork": true
|
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
|
@ -63,8 +63,7 @@ mod tests {
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit" : "0x",
|
"frontierCompatibilityModeLimit" : "0x"
|
||||||
"daoRescueSoftFork": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -57,9 +57,8 @@ Operating Options:
|
|||||||
--fork POLICY Specifies the client's fork policy. POLICY must be
|
--fork POLICY Specifies the client's fork policy. POLICY must be
|
||||||
one of:
|
one of:
|
||||||
dogmatic - sticks rigidly to the standard chain.
|
dogmatic - sticks rigidly to the standard chain.
|
||||||
dao-soft - votes for the DAO-rescue soft-fork.
|
none - goes with whatever fork is decided but
|
||||||
normal - goes with whatever fork is decided but
|
votes for none. [default: none].
|
||||||
votes for none. [default: normal].
|
|
||||||
|
|
||||||
Account Options:
|
Account Options:
|
||||||
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
|
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
|
||||||
|
@ -49,8 +49,7 @@ pub struct Directories {
|
|||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
pub enum Policy {
|
pub enum Policy {
|
||||||
DaoSoft,
|
None,
|
||||||
Normal,
|
|
||||||
Dogmatic,
|
Dogmatic,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,33 +134,24 @@ impl Configuration {
|
|||||||
|
|
||||||
pub fn policy(&self) -> Policy {
|
pub fn policy(&self) -> Policy {
|
||||||
match self.args.flag_fork.as_str() {
|
match self.args.flag_fork.as_str() {
|
||||||
"dao-soft" => Policy::DaoSoft,
|
"none" => Policy::None,
|
||||||
"normal" => Policy::Normal,
|
|
||||||
"dogmatic" => Policy::Dogmatic,
|
"dogmatic" => Policy::Dogmatic,
|
||||||
x => die!("{}: Invalid value given for --policy option. Use --help for more info.", x)
|
x => die!("{}: Invalid value given for --policy option. Use --help for more info.", x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gas_floor_target(&self) -> U256 {
|
pub fn gas_floor_target(&self) -> U256 {
|
||||||
if self.policy() == Policy::DaoSoft {
|
let d = &self.args.flag_gas_floor_target;
|
||||||
3_141_592.into()
|
U256::from_dec_str(d).unwrap_or_else(|_| {
|
||||||
} else {
|
die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d)
|
||||||
let d = &self.args.flag_gas_floor_target;
|
})
|
||||||
U256::from_dec_str(d).unwrap_or_else(|_| {
|
|
||||||
die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gas_ceil_target(&self) -> U256 {
|
pub fn gas_ceil_target(&self) -> U256 {
|
||||||
if self.policy() == Policy::DaoSoft {
|
let d = &self.args.flag_gas_cap;
|
||||||
3_141_592.into()
|
U256::from_dec_str(d).unwrap_or_else(|_| {
|
||||||
} else {
|
die!("{}: Invalid target gas ceiling given. Must be a decimal unsigned 256-bit number.", d)
|
||||||
let d = &self.args.flag_gas_cap;
|
})
|
||||||
U256::from_dec_str(d).unwrap_or_else(|_| {
|
|
||||||
die!("{}: Invalid target gas ceiling given. Must be a decimal unsigned 256-bit number.", d)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gas_price(&self) -> U256 {
|
pub fn gas_price(&self) -> U256 {
|
||||||
@ -191,7 +181,7 @@ impl Configuration {
|
|||||||
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
|
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
|
||||||
let gas_per_tx: f32 = 21000.0;
|
let gas_per_tx: f32 = 21000.0;
|
||||||
let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx;
|
let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx;
|
||||||
info!("Using a conversion rate of Ξ1 = {} ({} wei/gas)", paint(White.bold(), format!("US${}", usd_per_eth)), paint(Yellow.bold(), format!("{}", wei_per_gas)));
|
info!("Using a conversion rate of Ξ1 = {} ({} wei/gas)", format!("US${}", usd_per_eth).apply(White.bold()), format!("{}", wei_per_gas).apply(Yellow.bold()));
|
||||||
U256::from_dec_str(&format!("{:.0}", wei_per_gas)).unwrap()
|
U256::from_dec_str(&format!("{:.0}", wei_per_gas)).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,7 +197,7 @@ impl Configuration {
|
|||||||
|
|
||||||
pub fn spec(&self) -> Spec {
|
pub fn spec(&self) -> Spec {
|
||||||
match self.chain().as_str() {
|
match self.chain().as_str() {
|
||||||
"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(self.policy() != Policy::Dogmatic),
|
"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(),
|
||||||
"morden" | "testnet" => ethereum::new_morden(),
|
"morden" | "testnet" => ethereum::new_morden(),
|
||||||
"olympic" => ethereum::new_olympic(),
|
"olympic" => ethereum::new_olympic(),
|
||||||
f => Spec::load(contents(f).unwrap_or_else(|_| {
|
f => Spec::load(contents(f).unwrap_or_else(|_| {
|
||||||
@ -352,7 +342,7 @@ impl Configuration {
|
|||||||
if let journaldb::Algorithm::Archive = client_config.pruning {
|
if let journaldb::Algorithm::Archive = client_config.pruning {
|
||||||
client_config.trie_spec = TrieSpec::Fat;
|
client_config.trie_spec = TrieSpec::Fat;
|
||||||
} else {
|
} else {
|
||||||
die!("Fatdb is not supported. Please rerun with --pruning=archive")
|
die!("Fatdb is not supported. Please re-run with --pruning=archive")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +357,7 @@ impl Configuration {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if self.args.flag_jitvm {
|
if self.args.flag_jitvm {
|
||||||
client_config.vm_type = VMType::jit().unwrap_or_else(|| die!("Parity built without jit vm."))
|
client_config.vm_type = VMType::jit().unwrap_or_else(|| die!("Parity is built without the JIT EVM."))
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!(target: "parity", "Using pruning strategy of {}", client_config.pruning);
|
trace!(target: "parity", "Using pruning strategy of {}", client_config.pruning);
|
||||||
@ -439,11 +429,11 @@ impl Configuration {
|
|||||||
fn geth_ipc_path(&self) -> String {
|
fn geth_ipc_path(&self) -> String {
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
r"\\.\pipe\geth.ipc".to_owned()
|
r"\\.\pipe\geth.ipc".to_owned()
|
||||||
}
|
} else {
|
||||||
else {
|
match self.args.flag_testnet {
|
||||||
if self.args.flag_testnet { path::ethereum::with_testnet("geth.ipc") }
|
true => path::ethereum::with_testnet("geth.ipc"),
|
||||||
else { path::ethereum::with_default("geth.ipc") }
|
false => path::ethereum::with_default("geth.ipc"),
|
||||||
.to_str().unwrap().to_owned()
|
}.to_str().unwrap().to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ use std::time::{Instant, Duration};
|
|||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use ethsync::{EthSync, SyncProvider};
|
use ethsync::{EthSync, SyncProvider};
|
||||||
use util::Uint;
|
use util::{Uint, NetworkService};
|
||||||
use ethcore::client::*;
|
use ethcore::client::*;
|
||||||
use number_prefix::{binary_prefix, Standalone, Prefixed};
|
use number_prefix::{binary_prefix, Standalone, Prefixed};
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ impl Informant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature="dev", allow(match_bool))]
|
#[cfg_attr(feature="dev", allow(match_bool))]
|
||||||
pub fn tick(&self, client: &Client, maybe_sync: Option<&EthSync>) {
|
pub fn tick<Message>(&self, client: &Client, maybe_sync: Option<(&EthSync, &NetworkService<Message>)>) where Message: Send + Sync + Clone + 'static {
|
||||||
let elapsed = self.last_tick.read().unwrap().elapsed();
|
let elapsed = self.last_tick.read().unwrap().elapsed();
|
||||||
if elapsed < Duration::from_secs(5) {
|
if elapsed < Duration::from_secs(5) {
|
||||||
return;
|
return;
|
||||||
@ -110,11 +110,13 @@ impl Informant {
|
|||||||
paint(Yellow.bold(), format!("{:3}", ((report.gas_processed - last_report.gas_processed) / From::from(elapsed.as_milliseconds() * 1000)).low_u64())),
|
paint(Yellow.bold(), format!("{:3}", ((report.gas_processed - last_report.gas_processed) / From::from(elapsed.as_milliseconds() * 1000)).low_u64())),
|
||||||
|
|
||||||
match maybe_sync {
|
match maybe_sync {
|
||||||
Some(sync) => {
|
Some((sync, net)) => {
|
||||||
let sync_info = sync.status();
|
let sync_info = sync.status();
|
||||||
format!("{}/{} peers {} ",
|
let net_config = net.config();
|
||||||
|
format!("{}/{}/{} peers {} ",
|
||||||
paint(Green.bold(), format!("{:2}", sync_info.num_active_peers)),
|
paint(Green.bold(), format!("{:2}", sync_info.num_active_peers)),
|
||||||
paint(Green.bold(), format!("{:2}", sync_info.num_peers)),
|
paint(Green.bold(), format!("{:2}", sync_info.num_peers)),
|
||||||
|
paint(Green.bold(), format!("{:2}", net_config.ideal_peers)),
|
||||||
paint(Cyan.bold(), format!("{:>8}", format!("#{}", sync_info.last_imported_block_number.unwrap_or(chain_info.best_block_number)))),
|
paint(Cyan.bold(), format!("{:>8}", format!("#{}", sync_info.last_imported_block_number.unwrap_or(chain_info.best_block_number)))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -128,7 +130,7 @@ impl Informant {
|
|||||||
paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(cache_info.total()))),
|
paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(cache_info.total()))),
|
||||||
paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(queue_info.mem_used))),
|
paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(queue_info.mem_used))),
|
||||||
match maybe_sync {
|
match maybe_sync {
|
||||||
Some(sync) => {
|
Some((sync, _)) => {
|
||||||
let sync_info = sync.status();
|
let sync_info = sync.status();
|
||||||
format!(" {} sync", paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(sync_info.mem_used))))
|
format!(" {} sync", paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(sync_info.mem_used))))
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,9 @@ impl IoHandler<NetSyncMessage> for ClientIoHandler {
|
|||||||
|
|
||||||
fn timeout(&self, _io: &IoContext<NetSyncMessage>, timer: TimerToken) {
|
fn timeout(&self, _io: &IoContext<NetSyncMessage>, timer: TimerToken) {
|
||||||
if let INFO_TIMER = timer {
|
if let INFO_TIMER = timer {
|
||||||
self.info.tick(&self.client, Some(&self.sync));
|
if let Some(net) = self.network.upgrade() {
|
||||||
|
self.info.tick(&self.client, Some((&self.sync, &net)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ use std::thread::sleep;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use rustc_serialize::hex::FromHex;
|
use rustc_serialize::hex::FromHex;
|
||||||
use ctrlc::CtrlC;
|
use ctrlc::CtrlC;
|
||||||
use util::{H256, ToPretty, NetworkConfiguration, PayloadInfo, Bytes, UtilError, paint, Colour, version};
|
use util::{H256, ToPretty, NetworkConfiguration, PayloadInfo, Bytes, UtilError, Colour, Applyable, version, journaldb};
|
||||||
use util::panics::{MayPanic, ForwardPanic, PanicHandler};
|
use util::panics::{MayPanic, ForwardPanic, PanicHandler};
|
||||||
use ethcore::client::{Mode, BlockID, BlockChainClient, ClientConfig, get_db_path, BlockImportError};
|
use ethcore::client::{Mode, BlockID, BlockChainClient, ClientConfig, get_db_path, BlockImportError};
|
||||||
use ethcore::error::{ImportError};
|
use ethcore::error::{ImportError};
|
||||||
@ -97,7 +97,7 @@ use rpc::RpcServer;
|
|||||||
use signer::{SignerServer, new_token};
|
use signer::{SignerServer, new_token};
|
||||||
use dapps::WebappServer;
|
use dapps::WebappServer;
|
||||||
use io_handler::ClientIoHandler;
|
use io_handler::ClientIoHandler;
|
||||||
use configuration::Configuration;
|
use configuration::{Policy, Configuration};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let conf = Configuration::parse();
|
let conf = Configuration::parse();
|
||||||
@ -188,10 +188,21 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
|||||||
// Raise fdlimit
|
// Raise fdlimit
|
||||||
unsafe { ::fdlimit::raise_fd_limit(); }
|
unsafe { ::fdlimit::raise_fd_limit(); }
|
||||||
|
|
||||||
info!("Starting {}", paint(Colour::White.bold(), format!("{}", version())));
|
info!("Starting {}", format!("{}", version()).apply(Colour::White.bold()));
|
||||||
|
info!("Using state DB journalling strategy {}", match client_config.pruning {
|
||||||
|
journaldb::Algorithm::Archive => "archive",
|
||||||
|
journaldb::Algorithm::EarlyMerge => "light",
|
||||||
|
journaldb::Algorithm::OverlayRecent => "fast",
|
||||||
|
journaldb::Algorithm::RefCounted => "basic",
|
||||||
|
}.apply(Colour::White.bold()));
|
||||||
|
|
||||||
let net_settings = conf.net_settings(&spec);
|
// Display warning about using experimental journaldb types
|
||||||
let sync_config = conf.sync_config(&spec);
|
match client_config.pruning {
|
||||||
|
journaldb::Algorithm::EarlyMerge | journaldb::Algorithm::RefCounted => {
|
||||||
|
warn!("Your chosen strategy is {}! You can re-run with --pruning to change.", "unstable".apply(Colour::Red.bold()));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
// Display warning about using unlock with signer
|
// Display warning about using unlock with signer
|
||||||
if conf.signer_enabled() && conf.args.flag_unlock.is_some() {
|
if conf.signer_enabled() && conf.args.flag_unlock.is_some() {
|
||||||
@ -199,6 +210,14 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
|||||||
warn!("NOTE that Signer will not ask you to confirm transactions from unlocked account.");
|
warn!("NOTE that Signer will not ask you to confirm transactions from unlocked account.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check fork settings.
|
||||||
|
if conf.policy() != Policy::None {
|
||||||
|
warn!("Value given for --policy, yet no proposed forks exist. Ignoring.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let net_settings = conf.net_settings(&spec);
|
||||||
|
let sync_config = conf.sync_config(&spec);
|
||||||
|
|
||||||
// Secret Store
|
// Secret Store
|
||||||
let account_service = Arc::new(conf.account_service());
|
let account_service = Arc::new(conf.account_service());
|
||||||
|
|
||||||
@ -466,7 +485,7 @@ fn execute_import(conf: Configuration) {
|
|||||||
Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { trace!("Skipping block already in chain."); }
|
Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { trace!("Skipping block already in chain."); }
|
||||||
Err(e) => die!("Cannot import block: {:?}", e)
|
Err(e) => die!("Cannot import block: {:?}", e)
|
||||||
}
|
}
|
||||||
informant.tick(client.deref(), None);
|
informant.tick::<&'static ()>(client.deref(), None);
|
||||||
};
|
};
|
||||||
|
|
||||||
match format {
|
match format {
|
||||||
|
@ -14,11 +14,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate ansi_term;
|
|
||||||
use self::ansi_term::Colour::White;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use util::{Colour, Applyable};
|
||||||
use util::panics::{PanicHandler, ForwardPanic};
|
use util::panics::{PanicHandler, ForwardPanic};
|
||||||
use util::path::restrict_permissions_owner;
|
use util::path::restrict_permissions_owner;
|
||||||
use die::*;
|
use die::*;
|
||||||
@ -67,7 +66,7 @@ pub fn new_token(path: String) -> io::Result<()> {
|
|||||||
let mut codes = try!(signer::AuthCodes::from_file(&path));
|
let mut codes = try!(signer::AuthCodes::from_file(&path));
|
||||||
let code = try!(codes.generate_new());
|
let code = try!(codes.generate_new());
|
||||||
try!(codes.to_file(&path));
|
try!(codes.to_file(&path));
|
||||||
println!("This key code will authorise your System Signer UI: {}", White.bold().paint(code));
|
println!("This key code will authorise your System Signer UI: {}", code.apply(Colour::White.bold()));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ transient-hashmap = "0.1"
|
|||||||
serde_macros = { version = "0.7.0", optional = true }
|
serde_macros = { version = "0.7.0", optional = true }
|
||||||
clippy = { version = "0.0.78", optional = true}
|
clippy = { version = "0.0.78", optional = true}
|
||||||
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
|
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
|
||||||
|
ethcore-ipc = { path = "../ipc/rpc" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
serde_codegen = { version = "0.7.0", optional = true }
|
serde_codegen = { version = "0.7.0", optional = true }
|
||||||
|
@ -32,6 +32,7 @@ extern crate ethcore;
|
|||||||
extern crate ethsync;
|
extern crate ethsync;
|
||||||
extern crate transient_hashmap;
|
extern crate transient_hashmap;
|
||||||
extern crate json_ipc_server as ipc;
|
extern crate json_ipc_server as ipc;
|
||||||
|
extern crate ethcore_ipc;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate ethjson;
|
extern crate ethjson;
|
||||||
|
@ -30,6 +30,7 @@ use util::sha3::*;
|
|||||||
use util::rlp::{encode, decode, UntrustedRlp, View};
|
use util::rlp::{encode, decode, UntrustedRlp, View};
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
use ethcore::client::{MiningBlockChainClient, BlockID, TransactionID, UncleID};
|
use ethcore::client::{MiningBlockChainClient, BlockID, TransactionID, UncleID};
|
||||||
|
use ethcore::header::Header as BlockHeader;
|
||||||
use ethcore::block::IsBlock;
|
use ethcore::block::IsBlock;
|
||||||
use ethcore::views::*;
|
use ethcore::views::*;
|
||||||
use ethcore::ethereum::Ethash;
|
use ethcore::ethereum::Ethash;
|
||||||
@ -42,7 +43,6 @@ use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncIn
|
|||||||
use v1::helpers::CallRequest as CRequest;
|
use v1::helpers::CallRequest as CRequest;
|
||||||
use v1::impls::{default_gas_price, dispatch_transaction, error_codes};
|
use v1::impls::{default_gas_price, dispatch_transaction, error_codes};
|
||||||
use serde;
|
use serde;
|
||||||
use ethcore::header::Header as BlockHeader;
|
|
||||||
|
|
||||||
/// Eth rpc implementation.
|
/// Eth rpc implementation.
|
||||||
pub struct EthClient<C, S, M, EM> where
|
pub struct EthClient<C, S, M, EM> where
|
||||||
|
@ -56,7 +56,7 @@ pub use self::rpc::RpcClient;
|
|||||||
use v1::helpers::TransactionRequest;
|
use v1::helpers::TransactionRequest;
|
||||||
use v1::types::H256 as NH256;
|
use v1::types::H256 as NH256;
|
||||||
use ethcore::error::Error as EthcoreError;
|
use ethcore::error::Error as EthcoreError;
|
||||||
use ethcore::miner::{AccountDetails, MinerService};
|
use ethcore::miner::MinerService;
|
||||||
use ethcore::client::MiningBlockChainClient;
|
use ethcore::client::MiningBlockChainClient;
|
||||||
use ethcore::transaction::{Action, SignedTransaction, Transaction};
|
use ethcore::transaction::{Action, SignedTransaction, Transaction};
|
||||||
use ethcore::account_provider::{AccountProvider, Error as AccountError};
|
use ethcore::account_provider::{AccountProvider, Error as AccountError};
|
||||||
@ -80,12 +80,7 @@ fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedT
|
|||||||
where C: MiningBlockChainClient, M: MinerService {
|
where C: MiningBlockChainClient, M: MinerService {
|
||||||
let hash = NH256::from(signed_transaction.hash());
|
let hash = NH256::from(signed_transaction.hash());
|
||||||
|
|
||||||
let import = miner.import_own_transaction(client, signed_transaction, |a: &Address| {
|
let import = miner.import_own_transaction(client, signed_transaction);
|
||||||
AccountDetails {
|
|
||||||
nonce: client.latest_nonce(&a),
|
|
||||||
balance: client.latest_balance(&a),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
import
|
import
|
||||||
.map_err(transaction_error)
|
.map_err(transaction_error)
|
||||||
|
@ -200,8 +200,7 @@ const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{
|
|||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
|
"frontierCompatibilityModeLimit": "0xffffffffffffffff"
|
||||||
"daoRescueSoftFork": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -23,7 +23,7 @@ use ethcore::client::{MiningBlockChainClient, Executed, CallAnalytics};
|
|||||||
use ethcore::block::{ClosedBlock, IsBlock};
|
use ethcore::block::{ClosedBlock, IsBlock};
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
use ethcore::receipt::Receipt;
|
use ethcore::receipt::Receipt;
|
||||||
use ethcore::miner::{MinerService, MinerStatus, AccountDetails, TransactionImportResult};
|
use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult};
|
||||||
|
|
||||||
/// Test miner service.
|
/// Test miner service.
|
||||||
pub struct TestMinerService {
|
pub struct TestMinerService {
|
||||||
@ -130,14 +130,13 @@ impl MinerService for TestMinerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Imports transactions to transaction queue.
|
/// Imports transactions to transaction queue.
|
||||||
fn import_transactions<T>(&self, _chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
|
fn import_external_transactions(&self, _chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>) ->
|
||||||
Vec<Result<TransactionImportResult, Error>>
|
Vec<Result<TransactionImportResult, Error>> {
|
||||||
where T: Fn(&Address) -> AccountDetails {
|
|
||||||
// lets assume that all txs are valid
|
// lets assume that all txs are valid
|
||||||
self.imported_transactions.lock().unwrap().extend_from_slice(&transactions);
|
self.imported_transactions.lock().unwrap().extend_from_slice(&transactions);
|
||||||
|
|
||||||
for sender in transactions.iter().filter_map(|t| t.sender().ok()) {
|
for sender in transactions.iter().filter_map(|t| t.sender().ok()) {
|
||||||
let nonce = self.last_nonce(&sender).unwrap_or(fetch_account(&sender).nonce);
|
let nonce = self.last_nonce(&sender).expect("last_nonce must be populated in tests");
|
||||||
self.last_nonces.write().unwrap().insert(sender, nonce + U256::from(1));
|
self.last_nonces.write().unwrap().insert(sender, nonce + U256::from(1));
|
||||||
}
|
}
|
||||||
transactions
|
transactions
|
||||||
@ -147,9 +146,8 @@ impl MinerService for TestMinerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Imports transactions to transaction queue.
|
/// Imports transactions to transaction queue.
|
||||||
fn import_own_transaction<T>(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, _fetch_account: T) ->
|
fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction) ->
|
||||||
Result<TransactionImportResult, Error>
|
Result<TransactionImportResult, Error> {
|
||||||
where T: Fn(&Address) -> AccountDetails {
|
|
||||||
|
|
||||||
// keep the pending nonces up to date
|
// keep the pending nonces up to date
|
||||||
if let Ok(ref sender) = transaction.sender() {
|
if let Ok(ref sender) = transaction.sender() {
|
||||||
|
@ -84,7 +84,7 @@ impl Into<EthFilter> for Filter {
|
|||||||
VariadicValue::Single(t) => Some(vec![t.into()]),
|
VariadicValue::Single(t) => Some(vec![t.into()]),
|
||||||
VariadicValue::Multiple(t) => Some(t.into_iter().map(Into::into).collect())
|
VariadicValue::Multiple(t) => Some(t.into_iter().map(Into::into).collect())
|
||||||
}).filter_map(|m| m).collect()).into_iter();
|
}).filter_map(|m| m).collect()).into_iter();
|
||||||
[iter.next(), iter.next(), iter.next(), iter.next()]
|
vec![iter.next(), iter.next(), iter.next(), iter.next()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ pub enum Diff<T> where T: Serialize {
|
|||||||
Changed(ChangedType<T>),
|
Changed(ChangedType<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> From<account_diff::Diff<T>> for Diff<U> where T: Eq, U: Serialize + From<T> {
|
impl<T, U> From<account_diff::Diff<T>> for Diff<U> where T: Eq + ::ethcore_ipc::BinaryConvertable, U: Serialize + From<T> {
|
||||||
fn from(c: account_diff::Diff<T>) -> Self {
|
fn from(c: account_diff::Diff<T>) -> Self {
|
||||||
match c {
|
match c {
|
||||||
account_diff::Diff::Same => Diff::Same,
|
account_diff::Diff::Same => Diff::Same,
|
||||||
@ -205,7 +205,7 @@ impl Serialize for StateDiff {
|
|||||||
|
|
||||||
impl From<state_diff::StateDiff> for StateDiff {
|
impl From<state_diff::StateDiff> for StateDiff {
|
||||||
fn from(c: state_diff::StateDiff) -> Self {
|
fn from(c: state_diff::StateDiff) -> Self {
|
||||||
StateDiff(c.0.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
|
StateDiff(c.raw.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +44,10 @@
|
|||||||
//! let mut service = NetworkService::new(NetworkConfiguration::new()).unwrap();
|
//! let mut service = NetworkService::new(NetworkConfiguration::new()).unwrap();
|
||||||
//! service.start().unwrap();
|
//! service.start().unwrap();
|
||||||
//! let dir = env::temp_dir();
|
//! let dir = env::temp_dir();
|
||||||
//! let miner = Miner::new(Default::default(), ethereum::new_frontier(true), None);
|
//! let miner = Miner::new(Default::default(), ethereum::new_frontier(), None);
|
||||||
//! let client = Client::new(
|
//! let client = Client::new(
|
||||||
//! ClientConfig::default(),
|
//! ClientConfig::default(),
|
||||||
//! ethereum::new_frontier(true),
|
//! ethereum::new_frontier(),
|
||||||
//! &dir,
|
//! &dir,
|
||||||
//! miner,
|
//! miner,
|
||||||
//! service.io().channel()
|
//! service.io().channel()
|
||||||
|
@ -248,6 +248,13 @@ impl<Message> Handler for IoManager<Message> where Message: Send + Clone + Sync
|
|||||||
IoMessage::RemoveHandler { handler_id } => {
|
IoMessage::RemoveHandler { handler_id } => {
|
||||||
// TODO: flush event loop
|
// TODO: flush event loop
|
||||||
self.handlers.remove(handler_id);
|
self.handlers.remove(handler_id);
|
||||||
|
// unregister timers
|
||||||
|
let mut timers = self.timers.write().unwrap();
|
||||||
|
let to_remove: Vec<_> = timers.keys().cloned().filter(|timer_id| timer_id / TOKENS_PER_HANDLER == handler_id).collect();
|
||||||
|
for timer_id in to_remove {
|
||||||
|
let timer = timers.remove(&timer_id).expect("to_remove only contains keys from timers; qed");
|
||||||
|
event_loop.clear_timeout(timer.timeout);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
IoMessage::AddTimer { handler_id, token, delay } => {
|
IoMessage::AddTimer { handler_id, token, delay } => {
|
||||||
let timer_id = token + handler_id * TOKENS_PER_HANDLER;
|
let timer_id = token + handler_id * TOKENS_PER_HANDLER;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
//! Common log helper functions
|
//! Common log helper functions
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::borrow::Cow;
|
||||||
use rlog::{LogLevelFilter};
|
use rlog::{LogLevelFilter};
|
||||||
use env_logger::LogBuilder;
|
use env_logger::LogBuilder;
|
||||||
use std::sync::{RwLock, RwLockReadGuard};
|
use std::sync::{RwLock, RwLockReadGuard};
|
||||||
@ -28,12 +29,20 @@ lazy_static! {
|
|||||||
static ref USE_COLOR: AtomicBool = AtomicBool::new(false);
|
static ref USE_COLOR: AtomicBool = AtomicBool::new(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Paint, using colour if desired.
|
/// Something which can be apply()ed.
|
||||||
pub fn paint(c: Style, t: String) -> String {
|
pub trait Applyable: AsRef<str> {
|
||||||
match USE_COLOR.load(Ordering::Relaxed) {
|
/// Apply the style `c` to ourself, returning us styled in that manner.
|
||||||
true => format!("{}", c.paint(t)),
|
fn apply(&self, c: Style) -> Cow<str>;
|
||||||
false => t,
|
}
|
||||||
}
|
|
||||||
|
impl<T: AsRef<str>> Applyable for T {
|
||||||
|
fn apply(&self, c: Style) -> Cow<str> {
|
||||||
|
let s = self.as_ref();
|
||||||
|
match USE_COLOR.load(Ordering::Relaxed) {
|
||||||
|
true => Cow::Owned(format!("{}", c.paint(s))),
|
||||||
|
false => Cow::Borrowed(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -32,8 +32,6 @@ use misc::version;
|
|||||||
use crypto::*;
|
use crypto::*;
|
||||||
use sha3::Hashable;
|
use sha3::Hashable;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use log::Colour::White;
|
|
||||||
use log::paint;
|
|
||||||
use network::session::{Session, SessionData};
|
use network::session::{Session, SessionData};
|
||||||
use error::*;
|
use error::*;
|
||||||
use io::*;
|
use io::*;
|
||||||
@ -162,6 +160,8 @@ pub enum NetworkIoMessage<Message> where Message: Send + Sync + Clone {
|
|||||||
Disconnect(PeerId),
|
Disconnect(PeerId),
|
||||||
/// Disconnect and temporary disable peer.
|
/// Disconnect and temporary disable peer.
|
||||||
DisablePeer(PeerId),
|
DisablePeer(PeerId),
|
||||||
|
/// Network has been started with the host as the given enode.
|
||||||
|
NetworkStarted(String),
|
||||||
/// User message
|
/// User message
|
||||||
User(Message),
|
User(Message),
|
||||||
}
|
}
|
||||||
@ -345,12 +345,13 @@ pub struct Host<Message> where Message: Send + Sync + Clone {
|
|||||||
reserved_nodes: RwLock<HashSet<NodeId>>,
|
reserved_nodes: RwLock<HashSet<NodeId>>,
|
||||||
num_sessions: AtomicUsize,
|
num_sessions: AtomicUsize,
|
||||||
stopping: AtomicBool,
|
stopping: AtomicBool,
|
||||||
first_time: AtomicBool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
||||||
/// Create a new instance
|
/// Create a new instance
|
||||||
pub fn new(config: NetworkConfiguration, stats: Arc<NetworkStats>) -> Result<Host<Message>, UtilError> {
|
pub fn new(config: NetworkConfiguration, stats: Arc<NetworkStats>) -> Result<Host<Message>, UtilError> {
|
||||||
|
trace!(target: "host", "Creating new Host object");
|
||||||
|
|
||||||
let mut listen_address = match config.listen_address {
|
let mut listen_address = match config.listen_address {
|
||||||
None => SocketAddr::from_str("0.0.0.0:30304").unwrap(),
|
None => SocketAddr::from_str("0.0.0.0:30304").unwrap(),
|
||||||
Some(addr) => addr,
|
Some(addr) => addr,
|
||||||
@ -401,7 +402,6 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
reserved_nodes: RwLock::new(HashSet::new()),
|
reserved_nodes: RwLock::new(HashSet::new()),
|
||||||
num_sessions: AtomicUsize::new(0),
|
num_sessions: AtomicUsize::new(0),
|
||||||
stopping: AtomicBool::new(false),
|
stopping: AtomicBool::new(false),
|
||||||
first_time: AtomicBool::new(true),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for n in boot_nodes {
|
for n in boot_nodes {
|
||||||
@ -538,9 +538,8 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
|
|
||||||
self.info.write().unwrap().public_endpoint = Some(public_endpoint.clone());
|
self.info.write().unwrap().public_endpoint = Some(public_endpoint.clone());
|
||||||
|
|
||||||
if self.first_time.load(AtomicOrdering::Relaxed) {
|
if let Some(url) = self.external_url() {
|
||||||
info!("Public node URL: {}", paint(White.bold(), self.external_url().unwrap()));
|
io.message(NetworkIoMessage::NetworkStarted(url)).unwrap_or_else(|e| warn!("Error sending IO notification: {:?}", e));
|
||||||
self.first_time.store(false, AtomicOrdering::Relaxed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize discovery.
|
// Initialize discovery.
|
||||||
@ -1038,6 +1037,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
|
|||||||
h.message(&NetworkContext::new(io, p, None, self.sessions.clone(), &reserved), &message);
|
h.message(&NetworkContext::new(io, p, None, self.sessions.clone(), &reserved), &message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {} // ignore others.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,11 @@ impl<Message> NetworkService<Message> where Message: Send + Sync + Clone + 'stat
|
|||||||
&self.stats
|
&self.stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns network configuration.
|
||||||
|
pub fn config(&self) -> &NetworkConfiguration {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns external url if available.
|
/// Returns external url if available.
|
||||||
pub fn external_url(&self) -> Option<String> {
|
pub fn external_url(&self) -> Option<String> {
|
||||||
let host = self.host.read().unwrap();
|
let host = self.host.read().unwrap();
|
||||||
|
Loading…
Reference in New Issue
Block a user