Merge branch 'master' into tx_queue_rpc

This commit is contained in:
Tomasz Drwięga 2016-03-10 09:44:46 +01:00
commit cc47c80243
11 changed files with 166 additions and 38 deletions

30
Cargo.lock generated
View File

@ -15,6 +15,7 @@ dependencies = [
"fdlimit 0.1.0", "fdlimit 0.1.0",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -236,8 +237,8 @@ dependencies = [
"ethcore 0.9.99", "ethcore 0.9.99",
"ethcore-util 0.9.99", "ethcore-util 0.9.99",
"ethsync 0.9.99", "ethsync 0.9.99",
"jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -409,7 +410,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-core" name = "jsonrpc-core"
version = "1.2.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -420,11 +421,11 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-http-server" name = "jsonrpc-http-server"
version = "2.1.0" version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -699,6 +700,17 @@ dependencies = [
"librocksdb-sys 0.2.1 (git+https://github.com/arkpar/rust-rocksdb.git)", "librocksdb-sys 0.2.1 (git+https://github.com/arkpar/rust-rocksdb.git)",
] ]
[[package]]
name = "rpassword"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rust-crypto" name = "rust-crypto"
version = "0.2.34" version = "0.2.34"
@ -832,6 +844,14 @@ dependencies = [
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "termios"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.34" version = "0.1.34"

View File

@ -21,6 +21,7 @@ fdlimit = { path = "util/fdlimit" }
daemonize = "0.2" daemonize = "0.2"
ethcore-devtools = { path = "devtools" } ethcore-devtools = { path = "devtools" }
number_prefix = "0.2" number_prefix = "0.2"
rpassword = "0.1"
[features] [features]
default = ["rpc"] default = ["rpc"]

View File

@ -320,6 +320,9 @@ impl BlockQueue {
/// Mark given block and all its children as bad. Stops verification. /// Mark given block and all its children as bad. Stops verification.
pub fn mark_as_bad(&mut self, block_hashes: &[H256]) { pub fn mark_as_bad(&mut self, block_hashes: &[H256]) {
if block_hashes.is_empty() {
return;
}
let mut verification_lock = self.verification.lock().unwrap(); let mut verification_lock = self.verification.lock().unwrap();
let mut processing = self.processing.write().unwrap(); let mut processing = self.processing.write().unwrap();
@ -345,6 +348,9 @@ impl BlockQueue {
/// Mark given block as processed /// Mark given block as processed
pub fn mark_as_good(&mut self, block_hashes: &[H256]) { pub fn mark_as_good(&mut self, block_hashes: &[H256]) {
if block_hashes.is_empty() {
return;
}
let mut processing = self.processing.write().unwrap(); let mut processing = self.processing.write().unwrap();
for hash in block_hashes { for hash in block_hashes {
processing.remove(&hash); processing.remove(&hash);
@ -385,7 +391,7 @@ impl BlockQueue {
} }
} }
pub fn collect_garbage(&self) { pub fn collect_garbage(&self) {
{ {
let mut verification = self.verification.lock().unwrap(); let mut verification = self.verification.lock().unwrap();
verification.unverified.shrink_to_fit(); verification.unverified.shrink_to_fit();

View File

@ -409,8 +409,12 @@ impl<V> Client<V> where V: Verifier {
{ {
let mut block_queue = self.block_queue.write().unwrap(); let mut block_queue = self.block_queue.write().unwrap();
block_queue.mark_as_bad(&bad_blocks); if !bad_blocks.is_empty() {
block_queue.mark_as_good(&good_blocks); block_queue.mark_as_bad(&bad_blocks);
}
if !good_blocks.is_empty() {
block_queue.mark_as_good(&good_blocks);
}
} }
{ {

View File

@ -17,9 +17,11 @@
pub mod verification; pub mod verification;
pub mod verifier; pub mod verifier;
mod canon_verifier; mod canon_verifier;
#[cfg(test)]
mod noop_verifier; mod noop_verifier;
pub use self::verification::*; pub use self::verification::*;
pub use self::verifier::Verifier; pub use self::verifier::Verifier;
pub use self::canon_verifier::CanonVerifier; pub use self::canon_verifier::CanonVerifier;
#[cfg(test)]
pub use self::noop_verifier::NoopVerifier; pub use self::noop_verifier::NoopVerifier;

View File

@ -32,6 +32,7 @@ extern crate fdlimit;
extern crate daemonize; extern crate daemonize;
extern crate time; extern crate time;
extern crate number_prefix; extern crate number_prefix;
extern crate rpassword;
#[cfg(feature = "rpc")] #[cfg(feature = "rpc")]
extern crate ethcore_rpc as rpc; extern crate ethcore_rpc as rpc;
@ -43,7 +44,7 @@ use std::path::PathBuf;
use env_logger::LogBuilder; use env_logger::LogBuilder;
use ctrlc::CtrlC; use ctrlc::CtrlC;
use util::*; use util::*;
use util::panics::MayPanic; use util::panics::{MayPanic, ForwardPanic, PanicHandler};
use ethcore::spec::*; use ethcore::spec::*;
use ethcore::client::*; use ethcore::client::*;
use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::service::{ClientService, NetSyncMessage};
@ -70,6 +71,7 @@ Parity. Ethereum Client.
Usage: Usage:
parity daemon <pid-file> [options] [ --no-bootstrap | <enode>... ] parity daemon <pid-file> [options] [ --no-bootstrap | <enode>... ]
parity account (new | list)
parity [options] [ --no-bootstrap | <enode>... ] parity [options] [ --no-bootstrap | <enode>... ]
Protocol Options: Protocol Options:
@ -79,6 +81,7 @@ Protocol Options:
--networkid INDEX Override the network identifier from the chain we are on. --networkid INDEX Override the network identifier from the chain we are on.
--archive Client should not prune the state/storage trie. --archive Client should not prune the state/storage trie.
-d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity]
--keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys]
--identity NAME Specify your node's name. --identity NAME Specify your node's name.
Networking Options: Networking Options:
@ -113,7 +116,7 @@ Memory Footprint Options:
--cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384].
--cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144].
--queue-max-size BYTES Specify the maximum size of memory to use for block queue [default: 52428800]. --queue-max-size BYTES Specify the maximum size of memory to use for block queue [default: 52428800].
--cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with
other cache options (geth-compatible). other cache options (geth-compatible).
Miscellaneous Options: Miscellaneous Options:
@ -125,11 +128,14 @@ Miscellaneous Options:
#[derive(Debug, RustcDecodable)] #[derive(Debug, RustcDecodable)]
struct Args { struct Args {
cmd_daemon: bool, cmd_daemon: bool,
cmd_account: bool,
cmd_new: bool,
cmd_list: bool,
arg_pid_file: String, arg_pid_file: String,
arg_enode: Vec<String>, arg_enode: Vec<String>,
flag_chain: String, flag_chain: String,
flag_testnet: bool, flag_testnet: bool,
flag_db_path: String, flag_datadir: String,
flag_networkid: Option<String>, flag_networkid: Option<String>,
flag_identity: String, flag_identity: String,
flag_cache: Option<usize>, flag_cache: Option<usize>,
@ -189,10 +195,10 @@ fn setup_log(init: &Option<String>) {
} }
#[cfg(feature = "rpc")] #[cfg(feature = "rpc")]
fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>, url: &str, cors_domain: &str, apis: Vec<&str>) { fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>, url: &str, cors_domain: &str, apis: Vec<&str>) -> Option<Arc<PanicHandler>> {
use rpc::v1::*; use rpc::v1::*;
let mut server = rpc::HttpServer::new(1); let server = rpc::RpcServer::new();
for api in apis.into_iter() { for api in apis.into_iter() {
match api { match api {
"web3" => server.add_delegate(Web3Client::new().to_delegate()), "web3" => server.add_delegate(Web3Client::new().to_delegate()),
@ -206,11 +212,12 @@ fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>, url: &str, cors_dom
} }
} }
} }
server.start_async(url, cors_domain); Some(server.start_http(url, cors_domain, 1))
} }
#[cfg(not(feature = "rpc"))] #[cfg(not(feature = "rpc"))]
fn setup_rpc_server(_client: Arc<Client>, _sync: Arc<EthSync>, _url: &str) { fn setup_rpc_server(_client: Arc<Client>, _sync: Arc<EthSync>, _url: &str) -> Option<Arc<PanicHandler>> {
None
} }
fn print_version() { fn print_version() {
@ -238,7 +245,7 @@ impl Configuration {
} }
fn path(&self) -> String { fn path(&self) -> String {
self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) self.args.flag_datadir.replace("$HOME", env::home_dir().unwrap().to_str().unwrap())
} }
fn author(&self) -> Address { fn author(&self) -> Address {
@ -335,10 +342,44 @@ impl Configuration {
.start() .start()
.unwrap_or_else(|e| die!("Couldn't daemonize; {}", e)); .unwrap_or_else(|e| die!("Couldn't daemonize; {}", e));
} }
if self.args.cmd_account {
self.execute_account_cli();
return;
}
self.execute_client(); self.execute_client();
} }
fn execute_account_cli(&self) {
use util::keys::store::SecretStore;
use rpassword::read_password;
let mut secret_store = SecretStore::new();
if self.args.cmd_new {
println!("Please note that password is NOT RECOVERABLE.");
println!("Type password: ");
let password = read_password().unwrap();
println!("Repeat password: ");
let password_repeat = read_password().unwrap();
if password != password_repeat {
println!("Passwords do not match!");
return;
}
println!("New account address:");
let new_address = secret_store.new_account(&password).unwrap();
println!("{:?}", new_address);
return;
}
if self.args.cmd_list {
println!("Known addresses:");
for &(addr, _) in secret_store.accounts().unwrap().iter() {
println!("{:?}", addr);
}
}
}
fn execute_client(&self) { fn execute_client(&self) {
// Setup panic handler
let panic_handler = PanicHandler::new_in_arc();
// Setup logging // Setup logging
setup_log(&self.args.flag_logging); setup_log(&self.args.flag_logging);
// Raise fdlimit // Raise fdlimit
@ -365,6 +406,7 @@ impl Configuration {
client_config.name = self.args.flag_identity.clone(); client_config.name = self.args.flag_identity.clone();
client_config.queue.max_mem_use = self.args.flag_queue_max_size; client_config.queue.max_mem_use = self.args.flag_queue_max_size;
let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap();
panic_handler.forward_from(&service);
let client = service.client().clone(); let client = service.client().clone();
client.set_author(self.author()); client.set_author(self.author());
client.set_extra_data(self.extra_data()); client.set_extra_data(self.extra_data());
@ -382,30 +424,36 @@ impl Configuration {
let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors);
// TODO: use this as the API list. // TODO: use this as the API list.
let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis);
setup_rpc_server(service.client(), sync.clone(), &url, cors, apis.split(",").collect()); let server_handler = setup_rpc_server(service.client(), sync.clone(), &url, cors, apis.split(",").collect());
if let Some(handler) = server_handler {
panic_handler.forward_from(handler.deref());
}
} }
// Register IO handler // Register IO handler
let io_handler = Arc::new(ClientIoHandler { let io_handler = Arc::new(ClientIoHandler {
client: service.client(), client: service.client(),
info: Default::default(), info: Default::default(),
sync: sync sync: sync.clone(),
}); });
service.io().register_handler(io_handler).expect("Error registering IO handler"); service.io().register_handler(io_handler).expect("Error registering IO handler");
// Handle exit // Handle exit
wait_for_exit(&service); wait_for_exit(panic_handler);
} }
} }
fn wait_for_exit(client_service: &ClientService) { fn wait_for_exit(panic_handler: Arc<PanicHandler>) {
let exit = Arc::new(Condvar::new()); let exit = Arc::new(Condvar::new());
// Handle possible exits // Handle possible exits
let e = exit.clone(); let e = exit.clone();
CtrlC::set_handler(move || { e.notify_all(); }); CtrlC::set_handler(move || { e.notify_all(); });
// Handle panics
let e = exit.clone(); let e = exit.clone();
client_service.on_panic(move |_reason| { e.notify_all(); }); panic_handler.on_panic(move |_reason| { e.notify_all(); });
// Wait for signal // Wait for signal
let mutex = Mutex::new(()); let mutex = Mutex::new(());

View File

@ -12,8 +12,8 @@ build = "build.rs"
log = "0.3" log = "0.3"
serde = "0.7.0" serde = "0.7.0"
serde_json = "0.7.0" serde_json = "0.7.0"
jsonrpc-core = "1.2" jsonrpc-core = "2.0"
jsonrpc-http-server = "2.1" jsonrpc-http-server = "3.0"
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" } ethcore = { path = "../ethcore" }
ethash = { path = "../ethash" } ethash = { path = "../ethash" }

View File

@ -29,33 +29,43 @@ extern crate ethcore;
extern crate ethsync; extern crate ethsync;
extern crate transient_hashmap; extern crate transient_hashmap;
use std::sync::Arc;
use std::thread;
use util::panics::PanicHandler;
use self::jsonrpc_core::{IoHandler, IoDelegate}; use self::jsonrpc_core::{IoHandler, IoDelegate};
pub mod v1; pub mod v1;
/// Http server. /// Http server.
pub struct HttpServer { pub struct RpcServer {
handler: IoHandler, handler: Arc<IoHandler>,
threads: usize
} }
impl HttpServer { impl RpcServer {
/// Construct new http server object with given number of threads. /// Construct new http server object with given number of threads.
pub fn new(threads: usize) -> HttpServer { pub fn new() -> RpcServer {
HttpServer { RpcServer {
handler: IoHandler::new(), handler: Arc::new(IoHandler::new()),
threads: threads
} }
} }
/// Add io delegate. /// Add io delegate.
pub fn add_delegate<D>(&mut self, delegate: IoDelegate<D>) where D: Send + Sync + 'static { pub fn add_delegate<D>(&self, delegate: IoDelegate<D>) where D: Send + Sync + 'static {
self.handler.add_delegate(delegate); self.handler.add_delegate(delegate);
} }
/// Start server asynchronously in new thread /// Start server asynchronously in new thread and returns panic handler.
pub fn start_async(self, addr: &str, cors_domain: &str) { pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Arc<PanicHandler> {
let server = jsonrpc_http_server::Server::new(self.handler, self.threads); let addr = addr.to_owned();
server.start_async(addr, jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain.to_owned())) let cors_domain = cors_domain.to_owned();
let panic_handler = PanicHandler::new_in_arc();
let ph = panic_handler.clone();
let server = jsonrpc_http_server::Server::new(self.handler.clone());
thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || {
ph.catch_panic(move || {
server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads);
}).unwrap()
}).expect("Error while creating jsonrpc http thread");
panic_handler
} }
} }

View File

@ -853,8 +853,8 @@ impl ChainSync {
self.downloading_bodies.remove(&n); self.downloading_bodies.remove(&n);
self.downloading_headers.remove(&n); self.downloading_headers.remove(&n);
} }
self.headers.remove_tail(&start); self.headers.remove_from(&start);
self.bodies.remove_tail(&start); self.bodies.remove_from(&start);
} }
/// Request headers from a peer by block hash /// Request headers from a peer by block hash

View File

@ -42,6 +42,8 @@ pub trait RangeCollection<K, V> {
fn remove_head(&mut self, start: &K); fn remove_head(&mut self, start: &K);
/// Remove all elements >= `start` in the range that contains `start` /// Remove all elements >= `start` in the range that contains `start`
fn remove_tail(&mut self, start: &K); fn remove_tail(&mut self, start: &K);
/// Remove all elements >= `start`
fn remove_from(&mut self, start: &K);
/// Remove all elements >= `tail` /// Remove all elements >= `tail`
fn insert_item(&mut self, key: K, value: V); fn insert_item(&mut self, key: K, value: V);
/// Get an iterator over ranges /// Get an iterator over ranges
@ -137,6 +139,28 @@ impl<K, V> RangeCollection<K, V> for Vec<(K, Vec<V>)> where K: Ord + PartialEq +
} }
} }
/// Remove the element and all following it.
fn remove_from(&mut self, key: &K) {
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(index) => { self.drain(.. index + 1); },
Err(index) =>{
let mut empty = false;
match self.get_mut(index) {
Some(&mut (ref k, ref mut v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => {
v.truncate((*key - *k).to_usize());
empty = v.is_empty();
}
_ => {}
}
if empty {
self.drain(.. index + 1);
} else {
self.drain(.. index);
}
},
}
}
/// Remove range elements up to key /// Remove range elements up to key
fn remove_head(&mut self, key: &K) { fn remove_head(&mut self, key: &K) {
if *key == FromUsize::from_usize(0) { if *key == FromUsize::from_usize(0) {
@ -272,5 +296,17 @@ fn test_range() {
assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal); assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal);
r.remove_tail(&2); r.remove_tail(&2);
assert_eq!(r.range_iter().next(), None); assert_eq!(r.range_iter().next(), None);
let mut r = ranges.clone();
r.remove_from(&20);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_from(&17);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p'][..])]), Ordering::Equal);
r.remove_from(&15);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..])]), Ordering::Equal);
r.remove_from(&3);
assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal);
r.remove_from(&2);
assert_eq!(r.range_iter().next(), None);
} }

View File

@ -84,6 +84,7 @@ impl SecretStore {
let mut path = ::std::env::home_dir().expect("Failed to get home dir"); let mut path = ::std::env::home_dir().expect("Failed to get home dir");
path.push(".parity"); path.push(".parity");
path.push("keys"); path.push("keys");
::std::fs::create_dir_all(&path).expect("Should panic since it is critical to be able to access home dir");
Self::new_in(&path) Self::new_in(&path)
} }