From 4a8fe6c99d2bfd3b558f1e96b978aa19c9c02299 Mon Sep 17 00:00:00 2001 From: Brian Muhia Date: Sun, 27 Mar 2016 21:38:59 +0300 Subject: [PATCH 01/14] Update error message --- devtools/src/random_path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/src/random_path.rs b/devtools/src/random_path.rs index b037867fa..990d375e3 100644 --- a/devtools/src/random_path.rs +++ b/devtools/src/random_path.rs @@ -59,7 +59,7 @@ impl RandomTempPath { impl Drop for RandomTempPath { fn drop(&mut self) { if let Err(e) = fs::remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); + panic!("Failed to remove temp directory. Here's what prevented this from happening: ({})", e); } } } From d5d5b0918cca6c4cc9b61f271ad3fd7295c9f72a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 13 May 2016 13:11:50 +0300 Subject: [PATCH 02/14] mod for paths & ethereum default paths --- util/src/keys/geth_import.rs | 26 ++-------------- util/src/lib.rs | 1 + util/src/path.rs | 57 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 util/src/path.rs diff --git a/util/src/keys/geth_import.rs b/util/src/keys/geth_import.rs index 9886a61a8..56e73f790 100644 --- a/util/src/keys/geth_import.rs +++ b/util/src/keys/geth_import.rs @@ -20,6 +20,7 @@ use common::*; use keys::store::SecretStore; use keys::directory::KeyFileContent; use std::path::PathBuf; +use path; /// Enumerates all geth keys in the directory and returns collection of tuples `(accountId, filename)` pub fn enumerate_geth_keys(path: &Path) -> Result, ImportError> { @@ -98,30 +99,7 @@ pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: /// /// Based on https://github.com/ethereum/go-ethereum/blob/e553215/common/path.go#L75 pub fn keystore_dir() -> PathBuf { - #[cfg(target_os = "macos")] - fn data_dir(mut home: PathBuf) -> PathBuf { - home.push("Library"); - home.push("Ethereum"); - home - } - - #[cfg(windows)] - fn data_dir(mut home: PathBuf) -> PathBuf { - home.push("AppData"); - home.push("Roaming"); - home.push("Ethereum"); - home - } - - #[cfg(not(any(target_os = "macos", windows)))] - fn data_dir(mut home: PathBuf) -> PathBuf { - home.push(".ethereum"); - home - } - - let mut data_dir = data_dir(::std::env::home_dir().expect("Failed to get home dir")); - data_dir.push("keystore"); - data_dir + path::ethereum::with_default("keystore") } #[cfg(test)] diff --git a/util/src/lib.rs b/util/src/lib.rs index 530f2b4c5..a97282198 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -148,6 +148,7 @@ pub mod panics; pub mod keys; pub mod table; pub mod network_settings; +pub mod path; pub use common::*; pub use misc::*; diff --git a/util/src/path.rs b/util/src/path.rs new file mode 100644 index 000000000..10aaca44a --- /dev/null +++ b/util/src/path.rs @@ -0,0 +1,57 @@ +// 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 . + +//! Path utilities + +/// Default ethereum paths +pub mod ethereum { + use std::path::PathBuf; + + #[cfg(target_os = "macos")] + /// Default path for ethereum installation on Mac Os + pub fn default() -> PathBuf { + let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + home.push("Library"); + home.push("Ethereum"); + home + } + + #[cfg(windows)] + /// Default path for ethereum installation on Windows + pub fn default() -> PathBuf { + let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + home.push("AppData"); + home.push("Roaming"); + home.push("Ethereum"); + home + } + + #[cfg(not(any(target_os = "macos", windows)))] + /// Default path for ethereum installation on posix system which and not Mac OS + pub fn default() -> PathBuf { + let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + home.push(".ethereum"); + home + } + + /// Get the specific folder inside default ethereum installation + pub fn with_default(s: &str) -> PathBuf { + let mut pth = default(); + pth.push(s); + pth + } +} + From 9150538ac4503db1a691fba97ba226168ad570a7 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 13 May 2016 13:53:33 +0300 Subject: [PATCH 03/14] refactoring in configuration --- parity/configuration.rs | 27 +++++++++++++++------------ util/src/path.rs | 3 +-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/parity/configuration.rs b/parity/configuration.rs index 8d0eea9bb..90b5b3d1d 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -61,8 +61,7 @@ impl Configuration { } pub fn path(&self) -> String { - let d = self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path); - d.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + Configuration::replace_home(&self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path)) } pub fn author(&self) -> Address { @@ -114,7 +113,7 @@ impl Configuration { } pub fn keys_path(&self) -> String { - self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + Configuration::replace_home(&self.args.flag_keys_path) } pub fn spec(&self) -> Spec { @@ -266,20 +265,24 @@ impl Configuration { pub fn rpc_cors(&self) -> Option { self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone()) } - - fn geth_ipc_path() -> &'static str { - if cfg!(target_os = "macos") { - "$HOME/Library/Ethereum/geth.ipc" - } else { - "$HOME/.ethereum/geth.ipc" - } + + fn geth_ipc_path() -> String { + path::ethereum::with_default("geth.ipc").to_str().unwrap().to_owned() + } + + fn replace_home(arg: &str) -> String { + arg.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + } + + fn ipc_path(&self) -> String { + if self.args.flag_geth { Self::geth_ipc_path() } + else { Configuration::replace_home(&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) } } pub fn ipc_settings(&self) -> IpcConfiguration { IpcConfiguration { enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off), - socket_addr: if self.args.flag_geth { Self::geth_ipc_path().to_owned() } else { self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone()) } - .replace("$HOME", env::home_dir().unwrap().to_str().unwrap()), + socket_addr: self.ipc_path(), apis: self.args.flag_ipcapi.clone().unwrap_or(self.args.flag_ipc_apis.clone()), } } diff --git a/util/src/path.rs b/util/src/path.rs index 10aaca44a..3a8dcaaae 100644 --- a/util/src/path.rs +++ b/util/src/path.rs @@ -40,7 +40,7 @@ pub mod ethereum { } #[cfg(not(any(target_os = "macos", windows)))] - /// Default path for ethereum installation on posix system which and not Mac OS + /// Default path for ethereum installation on posix system which is not Mac OS pub fn default() -> PathBuf { let mut home = ::std::env::home_dir().expect("Failed to get home dir"); home.push(".ethereum"); @@ -54,4 +54,3 @@ pub mod ethereum { pth } } - From 7c19930efa01c391262b320a34d711114d594957 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 13 May 2016 18:32:32 +0300 Subject: [PATCH 04/14] creating all in one place --- parity/configuration.rs | 52 +++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/parity/configuration.rs b/parity/configuration.rs index 90b5b3d1d..ed28d0725 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -37,6 +37,11 @@ pub struct Configuration { pub args: Args } +pub struct Directories { + pub keys: String, + pub db: String, +} + impl Configuration { pub fn parse() -> Self { Configuration { @@ -60,10 +65,6 @@ impl Configuration { self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32 } - pub fn path(&self) -> String { - Configuration::replace_home(&self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path)) - } - pub fn author(&self) -> Address { let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author); Address::from_str(clean_0x(d)).unwrap_or_else(|_| { @@ -112,10 +113,6 @@ impl Configuration { } } - pub fn keys_path(&self) -> String { - Configuration::replace_home(&self.args.flag_keys_path) - } - pub fn spec(&self) -> Spec { match self.chain().as_str() { "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(), @@ -270,15 +267,6 @@ impl Configuration { path::ethereum::with_default("geth.ipc").to_str().unwrap().to_owned() } - fn replace_home(arg: &str) -> String { - arg.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) - } - - fn ipc_path(&self) -> String { - if self.args.flag_geth { Self::geth_ipc_path() } - else { Configuration::replace_home(&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) } - } - pub fn ipc_settings(&self) -> IpcConfiguration { IpcConfiguration { enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off), @@ -299,6 +287,36 @@ impl Configuration { rpc_port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port), } } + + pub fn directories(&self) -> Directories { + let db_path = Configuration::replace_home( + &self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path)); + std::fs::create_dir_all(db_path).unwrap_or_else(|e| die_with_io_error(e)); + + let keys_path = Configuration::replace_home(&self.args.flag_keys_path); + + Directories { + keys: keys_path, + db: db_path, + } + } + + pub fn keys_path(&self) -> String { + self.directories().keys + } + + pub fn path(&self) -> String { + self.directories().db + } + + fn replace_home(arg: &str) -> String { + arg.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + } + + fn ipc_path(&self) -> String { + if self.args.flag_geth { Self::geth_ipc_path() } + else { Configuration::replace_home(&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) } + } } #[cfg(test)] From 96496d634953d8de4838608bc24b4ba04960eb34 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 13 May 2016 18:36:18 +0300 Subject: [PATCH 05/14] by ref --- parity/configuration.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/parity/configuration.rs b/parity/configuration.rs index ed28d0725..920cb7eed 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -291,9 +291,10 @@ impl Configuration { pub fn directories(&self) -> Directories { let db_path = Configuration::replace_home( &self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path)); - std::fs::create_dir_all(db_path).unwrap_or_else(|e| die_with_io_error(e)); + ::std::fs::create_dir_all(&db_path).unwrap_or_else(|e| die_with_io_error("main", e)); let keys_path = Configuration::replace_home(&self.args.flag_keys_path); + ::std::fs::create_dir_all(&db_path).unwrap_or_else(|e| die_with_io_error("main", e)); Directories { keys: keys_path, From 9b914446389b2f5755625720eeb618a7e6bbcacd Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 14 May 2016 13:29:26 +0200 Subject: [PATCH 06/14] comma delimeting multiple cors headers (#1078) --- Cargo.lock | 12 +++++++++++- parity/configuration.rs | 9 +++++---- parity/rpc.rs | 6 +++--- rpc/Cargo.toml | 2 +- rpc/src/lib.rs | 8 +++++--- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b3fbd44a..c409cf58a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,7 +301,7 @@ dependencies = [ "ethsync 1.2.0", "json-ipc-server 0.1.0 (git+https://github.com/ethcore/json-ipc-server.git)", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)", + "jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git?branch=multiple_cors_domains)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -577,6 +577,16 @@ dependencies = [ "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "jsonrpc-http-server" +version = "5.1.0" +source = "git+https://github.com/ethcore/jsonrpc-http-server.git?branch=multiple_cors_domains#9c026feeb6573c82c99c8005c5d8244de68a2e30" +dependencies = [ + "hyper 0.9.3 (git+https://github.com/ethcore/hyper)", + "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" diff --git a/parity/configuration.rs b/parity/configuration.rs index 8d0eea9bb..c7c3480f9 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -263,10 +263,11 @@ impl Configuration { self.args.flag_rpcapi.clone().unwrap_or(self.args.flag_jsonrpc_apis.clone()) } - pub fn rpc_cors(&self) -> Option { - self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone()) + pub fn rpc_cors(&self) -> Vec { + let cors = self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone()); + cors.map_or_else(Vec::new, |c| c.split(',').map(|s| s.to_owned()).collect()) } - + fn geth_ipc_path() -> &'static str { if cfg!(target_os = "macos") { "$HOME/Library/Ethereum/geth.ipc" @@ -338,7 +339,7 @@ mod tests { assert_eq!(net.rpc_enabled, true); assert_eq!(net.rpc_interface, "all".to_owned()); assert_eq!(net.rpc_port, 8000); - assert_eq!(conf.rpc_cors(), Some("*".to_owned())); + assert_eq!(conf.rpc_cors(), vec!["*".to_owned()]); assert_eq!(conf.rpc_apis(), "web3,eth".to_owned()); } diff --git a/parity/rpc.rs b/parity/rpc.rs index a48af6401..e1782e9b6 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -41,7 +41,7 @@ pub struct HttpConfiguration { pub interface: String, pub port: u16, pub apis: String, - pub cors: Option, + pub cors: Vec, } pub struct IpcConfiguration { @@ -139,11 +139,11 @@ pub fn setup_http_rpc_server( pub fn setup_http_rpc_server( dependencies: &Arc, url: &SocketAddr, - cors_domain: Option, + cors_domains: Vec, apis: Vec<&str>, ) -> RpcServer { let server = setup_rpc_server(apis, dependencies); - let start_result = server.start_http(url, cors_domain); + let start_result = server.start_http(url, cors_domains); let deps = dependencies.clone(); match start_result { Err(RpcServerError::IoError(err)) => die_with_io_error("RPC", err), diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 326634ab2..c4de059bf 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -13,7 +13,7 @@ log = "0.3" serde = "0.7.0" serde_json = "0.7.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", branch = "multiple_cors_domains" } ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index d4998fdc3..7d9818615 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -59,9 +59,11 @@ impl RpcServer { } /// Start http server asynchronously and returns result with `Server` handle on success or an error. - pub fn start_http(&self, addr: &SocketAddr, cors_domain: Option) -> Result { - let cors_domain = cors_domain.to_owned(); - Server::start(addr, self.handler.clone(), cors_domain.map(jsonrpc_http_server::AccessControlAllowOrigin::Value)) + pub fn start_http(&self, addr: &SocketAddr, cors_domains: Vec) -> Result { + let cors_domains = cors_domains.into_iter() + .map(jsonrpc_http_server::AccessControlAllowOrigin::Value) + .collect(); + Server::start(addr, self.handler.clone(), cors_domains) } /// Start ipc server asynchronously and returns result with `Server` handle on success or an error. From 2b78e511c9e08af9647d91cf6e8718900c753a55 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 14 May 2016 14:30:25 +0300 Subject: [PATCH 07/14] Configurable keys security (#1080) * adding options & cli flags * adding it to the key deriving * removed duplicated option --- parity/cli.rs | 4 ++++ parity/configuration.rs | 6 +++++- parity/main.rs | 2 +- util/src/keys/store.rs | 25 +++++++++++++++++++------ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/parity/cli.rs b/parity/cli.rs index 84c941d33..009f03b89 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -42,6 +42,9 @@ Account Options: ACCOUNTS is a comma-delimited list of addresses. --password FILE Provide a file containing a password for unlocking an account. + --keys-iterations NUM Specify the number of iterations to use when deriving key + from the password (bigger is more secure) + [default: 10240]. Networking Options: --port PORT Override the port on which the node should listen @@ -182,6 +185,7 @@ pub struct Args { pub flag_password: Vec, pub flag_cache: Option, pub flag_keys_path: String, + pub flag_keys_iterations: u32, pub flag_bootnodes: Option, pub flag_network_id: Option, pub flag_pruning: String, diff --git a/parity/configuration.rs b/parity/configuration.rs index c7c3480f9..96885f83b 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -117,6 +117,10 @@ impl Configuration { self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } + pub fn keys_iterations(&self) -> u32 { + self.args.flag_keys_iterations + } + pub fn spec(&self) -> Spec { match self.chain().as_str() { "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(), @@ -245,7 +249,7 @@ impl Configuration { .collect::>() .into_iter() }).collect::>(); - let account_service = AccountService::new_in(Path::new(&self.keys_path())); + let account_service = AccountService::with_security(Path::new(&self.keys_path()), self.keys_iterations()); if let Some(ref unlocks) = self.args.flag_unlock { for d in unlocks.split(',') { let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| { diff --git a/parity/main.rs b/parity/main.rs index ded07505c..dd70d39cc 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -219,7 +219,7 @@ fn flush_stdout() { fn execute_account_cli(conf: Configuration) { use util::keys::store::SecretStore; use rpassword::read_password; - let mut secret_store = SecretStore::new_in(Path::new(&conf.keys_path())); + let mut secret_store = SecretStore::with_security(Path::new(&conf.keys_path()), conf.keys_iterations()); if conf.args.cmd_new { println!("Please note that password is NOT RECOVERABLE."); print!("Type password: "); diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index a879a4cd2..bf5edf3c9 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -73,6 +73,7 @@ pub enum SigningError { pub struct SecretStore { directory: KeyDirectory, unlocks: RwLock>, + key_iterations: u32, } struct AccountUnlock { @@ -128,10 +129,15 @@ impl AccountProvider for AccountService { impl AccountService { /// New account service with the keys store in specific location pub fn new_in(path: &Path) -> Self { - let secret_store = RwLock::new(SecretStore::new_in(path)); + AccountService::with_security(path, KEY_ITERATIONS) + } + + /// New account service with the keys store in specific location and configured security parameters + pub fn with_security(path: &Path, key_iterations: u32) -> Self { + let secret_store = RwLock::new(SecretStore::with_security(path, key_iterations)); secret_store.write().unwrap().try_import_existing(); AccountService { - secret_store: secret_store + secret_store: secret_store, } } @@ -157,10 +163,16 @@ impl AccountService { impl SecretStore { /// new instance of Secret Store in specific directory pub fn new_in(path: &Path) -> Self { + SecretStore::with_security(path, KEY_ITERATIONS) + } + + /// new instance of Secret Store in specific directory and configured security parameters + pub fn with_security(path: &Path, key_iterations: u32) -> Self { ::std::fs::create_dir_all(&path).expect("Cannot access requested key directory - critical"); SecretStore { directory: KeyDirectory::new(path), unlocks: RwLock::new(HashMap::new()), + key_iterations: key_iterations, } } @@ -206,6 +218,7 @@ impl SecretStore { SecretStore { directory: KeyDirectory::new(path.as_path()), unlocks: RwLock::new(HashMap::new()), + key_iterations: KEY_ITERATIONS, } } @@ -289,8 +302,8 @@ fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) (derived_right_bits.to_vec(), derived_left_bits.to_vec()) } -fn derive_key(password: &str, salt: &H256) -> (Bytes, Bytes) { - derive_key_iterations(password, salt, KEY_ITERATIONS) +fn derive_key(password: &str, salt: &H256, iterations: u32) -> (Bytes, Bytes) { + derive_key_iterations(password, salt, iterations) } fn derive_key_scrypt(password: &str, salt: &H256, n: u32, p: u32, r: u32) -> (Bytes, Bytes) { @@ -346,7 +359,7 @@ impl EncryptedHashMap for SecretStore { // two parts of derived key // DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits] - let (derived_left_bits, derived_right_bits) = derive_key(password, &salt); + let (derived_left_bits, derived_right_bits) = derive_key(password, &salt, self.key_iterations); let mut cipher_text = vec![0u8; value.as_slice().len()]; // aes-128-ctr with initial vector of iv @@ -361,7 +374,7 @@ impl EncryptedHashMap for SecretStore { iv, salt, mac, - KEY_ITERATIONS, + self.key_iterations, KEY_LENGTH)); key_file.id = key; if let Err(io_error) = self.directory.save(key_file) { From 354ac7d6e596ae5c5752d3863884a43ecb625a84 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 14 May 2016 15:28:44 +0300 Subject: [PATCH 08/14] Limiting result of the execution to execution-specific errors (#1071) * execution error/result limiting * missing trailing comma * fix executive tests * adding original error as string to the generic transaction error * 'mallformed'-s all around --- ethcore/src/client/client.rs | 7 +++++-- ethcore/src/client/mod.rs | 4 ++-- ethcore/src/client/test_client.rs | 4 ++-- ethcore/src/error.rs | 4 +++- ethcore/src/executive.rs | 19 +++++++++++-------- miner/src/lib.rs | 4 ++-- miner/src/miner.rs | 7 +++++-- rpc/src/v1/tests/helpers/miner_service.rs | 4 ++-- sync/src/chain.rs | 4 ++-- util/src/keys/directory.rs | 2 +- 10 files changed, 35 insertions(+), 24 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 23b81b34e..e385f39a8 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -424,7 +424,7 @@ impl Client where V: Verifier { } impl BlockChainClient for Client where V: Verifier { - fn call(&self, t: &SignedTransaction) -> Result { + fn call(&self, t: &SignedTransaction) -> Result { let header = self.block_header(BlockId::Latest).unwrap(); let view = HeaderView::new(&header); let last_hashes = self.build_last_hashes(view.hash()); @@ -439,7 +439,10 @@ impl BlockChainClient for Client where V: Verifier { }; // that's just a copy of the state. let mut state = self.state(); - let sender = try!(t.sender()); + let sender = try!(t.sender().map_err(|e| { + let message = format!("Transaction malformed: {:?}", e); + ExecutionError::TransactionMalformed(message) + })); let balance = state.balance(&sender); // give the sender max balance state.sub_balance(&sender, &balance); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 90dd78015..9dddeceb7 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -42,7 +42,7 @@ use header::{BlockNumber, Header}; use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; -use error::{ImportResult, Error}; +use error::{ImportResult, ExecutionError}; use receipt::LocalizedReceipt; use engine::{Engine}; use trace::LocalizedTrace; @@ -133,7 +133,7 @@ pub trait BlockChainClient : Sync + Send { fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result; /// Makes a non-persistent transaction call. - fn call(&self, t: &SignedTransaction) -> Result; + fn call(&self, t: &SignedTransaction) -> Result; /// Attempt to seal the block internally. See `Engine`. fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option> { self.engine().generate_seal(block, accounts) } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index c3df57b76..4ec993fe5 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -31,7 +31,7 @@ use error::{ImportResult}; use block_queue::BlockQueueInfo; use block::{SealedBlock, ClosedBlock, LockedBlock}; use executive::Executed; -use error::Error; +use error::{ExecutionError}; use engine::Engine; use trace::LocalizedTrace; @@ -221,7 +221,7 @@ impl TestBlockChainClient { } impl BlockChainClient for TestBlockChainClient { - fn call(&self, _t: &SignedTransaction) -> Result { + fn call(&self, _t: &SignedTransaction) -> Result { Ok(self.execution_result.read().unwrap().clone().unwrap()) } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 922d72700..2e007703b 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -59,7 +59,9 @@ pub enum ExecutionError { got: U512 }, /// Returned when internal evm error occurs. - Internal + Internal, + /// Returned when generic transaction occurs + TransactionMalformed(String), } #[derive(Debug, PartialEq)] diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 4247114ef..179195078 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -119,7 +119,7 @@ impl<'a> Executive<'a> { } /// This function should be used to execute transaction. - pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result { + pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result { let check = options.check_nonce; match options.tracing { true => self.transact_with_tracer(t, check, ExecutiveTracer::default()), @@ -128,8 +128,11 @@ impl<'a> Executive<'a> { } /// Execute transaction/call with tracing enabled - pub fn transact_with_tracer(&'a mut self, t: &SignedTransaction, check_nonce: bool, mut tracer: T) -> Result where T: Tracer { - let sender = try!(t.sender()); + pub fn transact_with_tracer(&'a mut self, t: &SignedTransaction, check_nonce: bool, mut tracer: T) -> Result where T: Tracer { + let sender = try!(t.sender().map_err(|e| { + let message = format!("Transaction malformed: {:?}", e); + ExecutionError::TransactionMalformed(message) + })); let nonce = self.state.nonce(&sender); let schedule = self.engine.schedule(self.info); @@ -983,8 +986,8 @@ mod tests { }; match res { - Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))) => (), - _ => assert!(false, "Expected invalid signature error.") + Err(ExecutionError::TransactionMalformed(_)) => (), + _ => assert!(false, "Expected an invalid transaction error.") } } @@ -1015,7 +1018,7 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) + Err(ExecutionError::InvalidNonce { expected, got }) if expected == U256::zero() && got == U256::one() => (), _ => assert!(false, "Expected invalid nonce error.") } @@ -1049,7 +1052,7 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) + Err(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas }) if gas_limit == U256::from(100_000) && gas_used == U256::from(20_000) && gas == U256::from(80_001) => (), _ => assert!(false, "Expected block gas limit error.") } @@ -1083,7 +1086,7 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::NotEnoughCash { required , got })) + Err(ExecutionError::NotEnoughCash { required , got }) if required == U512::from(100_018) && got == U512::from(100_017) => (), _ => assert!(false, "Expected not enough cash error. {:?}", res) } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index bd2904fc2..f92e0de52 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -63,7 +63,7 @@ pub use external::{ExternalMiner, ExternalMinerService}; use util::{H256, U256, Address, Bytes}; use ethcore::client::{BlockChainClient, Executed}; use ethcore::block::{ClosedBlock}; -use ethcore::error::{Error}; +use ethcore::error::{Error, ExecutionError}; use ethcore::transaction::SignedTransaction; /// Miner client API @@ -150,7 +150,7 @@ pub trait MinerService : Send + Sync { fn balance(&self, chain: &BlockChainClient, address: &Address) -> U256; /// Call into contract code using pending state. - fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result; + fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result; /// Get storage value in pending state. fn storage_at(&self, chain: &BlockChainClient, address: &Address, position: &H256) -> H256; diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 78ff824f6..33d21613f 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -240,7 +240,7 @@ impl MinerService for Miner { } } - fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result { + fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result { let sealing_work = self.sealing_work.lock().unwrap(); match sealing_work.peek_last_ref() { Some(work) => { @@ -258,7 +258,10 @@ impl MinerService for Miner { }; // that's just a copy of the state. let mut state = block.state().clone(); - let sender = try!(t.sender()); + let sender = try!(t.sender().map_err(|e| { + let message = format!("Transaction malformed: {:?}", e); + ExecutionError::TransactionMalformed(message) + })); let balance = state.balance(&sender); // give the sender max balance state.sub_balance(&sender, &balance); diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index cd4157fa9..1fbe15ca4 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -18,7 +18,7 @@ use util::{Address, H256, Bytes, U256, FixedHash, Uint}; use util::standard::*; -use ethcore::error::Error; +use ethcore::error::{Error, ExecutionError}; use ethcore::client::{BlockChainClient, Executed}; use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::transaction::SignedTransaction; @@ -179,7 +179,7 @@ impl MinerService for TestMinerService { self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone()) } - fn call(&self, _chain: &BlockChainClient, _t: &SignedTransaction) -> Result { + fn call(&self, _chain: &BlockChainClient, _t: &SignedTransaction) -> Result { unimplemented!(); } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 14809fdc4..bd94fb9be 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1193,7 +1193,7 @@ impl ChainSync { let mut rlp_stream = RlpStream::new_list(route.blocks.len()); for block_hash in route.blocks { let mut hash_rlp = RlpStream::new_list(2); - let difficulty = chain.block_total_difficulty(BlockId::Hash(block_hash.clone())).expect("Mallformed block without a difficulty on the chain!"); + let difficulty = chain.block_total_difficulty(BlockId::Hash(block_hash.clone())).expect("Malformed block without a difficulty on the chain!"); hash_rlp.append(&block_hash); hash_rlp.append(&difficulty); rlp_stream.append_raw(&hash_rlp.out(), 1); @@ -1570,7 +1570,7 @@ mod tests { } #[test] - fn handles_peer_new_block_mallformed() { + fn handles_peer_new_block_malformed() { let mut client = TestBlockChainClient::new(); client.add_blocks(10, EachBlockWith::Uncle); diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index d9268a95f..3f4100163 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -381,7 +381,7 @@ impl KeyFileContent { } } - /// Loads key from valid json, returns error and records warning if key is mallformed + /// Loads key from valid json, returns error and records warning if key is malformed pub fn load(json: &Json) -> Result { match Self::from_json(json) { Ok(key_file) => Ok(key_file), From 33248528b9ed1f1f8d168b98f3b2d1f13d86584f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 14 May 2016 14:53:46 +0100 Subject: [PATCH 09/14] Provide fallback for usd-per-eth option when offline. Fixes #1073. --- parity/cli.rs | 4 +++- parity/configuration.rs | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/parity/cli.rs b/parity/cli.rs index 009f03b89..90d7167dc 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -102,7 +102,9 @@ Sealing/Mining Options: [default: 0.005]. The minimum gas price is set accordingly. --usd-per-eth SOURCE USD value of a single ETH. SOURCE may be either an - amount in USD or a web service [default: etherscan]. + amount in USD, a web service or 'auto' to use each + web service in turn and fallback on the last known + good value [default: auto]. --gas-floor-target GAS Amount of gas per block to target when sealing a new block [default: 4712388]. --author ADDRESS Specify the block author (aka "coinbase") address diff --git a/parity/configuration.rs b/parity/configuration.rs index 96885f83b..ede71029c 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -91,11 +91,18 @@ impl Configuration { die!("{}: Invalid basic transaction price given in USD. Must be a decimal number.", self.args.flag_usd_per_tx) }); let usd_per_eth = match self.args.flag_usd_per_eth.as_str() { + "auto" => PriceInfo::get().map_or_else(|| { + let last_known_good = 9.69696; + // TODO: use #1083 to read last known good value. + last_known_good + }, |x| x.ethusd), "etherscan" => PriceInfo::get().map_or_else(|| { die!("Unable to retrieve USD value of ETH from etherscan. Rerun with a different value for --usd-per-eth.") }, |x| x.ethusd), x => FromStr::from_str(x).unwrap_or_else(|_| die!("{}: Invalid ether price given in USD. Must be a decimal number.", x)) }; + // TODO: use #1083 to write last known good value as use_per_eth. + let wei_per_usd: f32 = 1.0e18 / usd_per_eth; let gas_per_tx: f32 = 21000.0; let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; From 3ea26fcb0a5f699b7695c8c692b5475954f4d98c Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 14 May 2016 20:43:29 +0300 Subject: [PATCH 10/14] merged out function return --- parity/configuration.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/parity/configuration.rs b/parity/configuration.rs index 2f2a1cc74..67fc30f32 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -268,6 +268,10 @@ impl Configuration { path::ethereum::with_default("geth.ipc").to_str().unwrap().to_owned() } + pub fn keys_iterations(&self) -> u32 { + self.args.flag_keys_iterations + } + pub fn ipc_settings(&self) -> IpcConfiguration { IpcConfiguration { enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off), From f4d5c7b48e0cf2ed9f5407674d32b8e309a26164 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 16 May 2016 12:46:09 +0200 Subject: [PATCH 11/14] Fix uncle getter Uncle blocks don't necessarily have BlockDetails, so can't get total difficulty directly. Closes #1057 --- ethcore/src/client/ids.rs | 1 + rpc/src/v1/impls/eth.rs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ethcore/src/client/ids.rs b/ethcore/src/client/ids.rs index 39a19c82d..693cab528 100644 --- a/ethcore/src/client/ids.rs +++ b/ethcore/src/client/ids.rs @@ -53,6 +53,7 @@ pub struct TraceId { } /// Uniquely identifies Uncle. +#[derive(Debug)] pub struct UncleId ( /// Block id. pub BlockId, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 51946b97b..b6abbaa47 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -123,8 +123,8 @@ impl EthClient fn uncle(&self, id: UncleId) -> Result { let client = take_weak!(self.client); - match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.hash())).map(|diff| (diff, u))) { - Some((difficulty, uncle)) => { + match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.parent_hash().clone())).map(|diff| (diff, u))) { + Some((parent_difficulty, uncle)) => { let block = Block { hash: OptionalValue::Value(uncle.hash()), parent_hash: uncle.parent_hash, @@ -138,8 +138,8 @@ impl EthClient gas_limit: uncle.gas_limit, logs_bloom: uncle.log_bloom, timestamp: U256::from(uncle.timestamp), - difficulty: uncle.difficulty, - total_difficulty: difficulty, + difficulty: uncle.difficulty + parent_difficulty, + total_difficulty: uncle.difficulty, receipts_root: uncle.receipts_root, extra_data: Bytes::new(uncle.extra_data), seal_fields: uncle.seal.into_iter().map(Bytes::new).collect(), From 56c705968b0323298e2552f6449347ba7b9049bc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 16 May 2016 13:33:29 +0200 Subject: [PATCH 12/14] Fix typo. --- rpc/src/v1/impls/eth.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index b6abbaa47..6fddf7b4f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -138,8 +138,8 @@ impl EthClient gas_limit: uncle.gas_limit, logs_bloom: uncle.log_bloom, timestamp: U256::from(uncle.timestamp), - difficulty: uncle.difficulty + parent_difficulty, - total_difficulty: uncle.difficulty, + difficulty: uncle.difficulty, + total_difficulty: uncle.difficulty + parent_difficulty, receipts_root: uncle.receipts_root, extra_data: Bytes::new(uncle.extra_data), seal_fields: uncle.seal.into_iter().map(Bytes::new).collect(), From 9301963d984b80f88c908a6f5331509148346cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 16 May 2016 16:08:52 +0200 Subject: [PATCH 13/14] Subdomains support in content server (webapps server). (#1082) * Proxy.pac serving * Subdomains router for dapps * Proper handling of prefixed and non-prefixed apps * Changing dapps domain to parity --- webapp/src/api.rs | 51 +--------- webapp/src/apps.rs | 15 ++- webapp/src/endpoint.rs | 65 ++++++++++++- webapp/src/lib.rs | 3 + webapp/src/page/mod.rs | 53 +++++++---- webapp/src/proxypac.rs | 48 ++++++++++ webapp/src/router/mod.rs | 198 +++++++++++++++++++++++++++++---------- webapp/src/rpc.rs | 6 +- 8 files changed, 316 insertions(+), 123 deletions(-) create mode 100644 webapp/src/proxypac.rs diff --git a/webapp/src/api.rs b/webapp/src/api.rs index bad49ec61..75cdb4c58 100644 --- a/webapp/src/api.rs +++ b/webapp/src/api.rs @@ -16,12 +16,8 @@ //! Simple REST API -use std::io::Write; use std::sync::Arc; -use hyper::status::StatusCode; -use hyper::{header, server, Decoder, Encoder, Next}; -use hyper::net::HttpStream; -use endpoint::{Endpoint, Endpoints}; +use endpoint::{Endpoint, Endpoints, ContentHandler, Handler, EndpointPath}; pub struct RestApi { endpoints: Arc, @@ -46,49 +42,8 @@ impl RestApi { } impl Endpoint for RestApi { - fn to_handler(&self, _prefix: &str) -> Box> { - Box::new(RestApiHandler { - pages: self.list_pages(), - write_pos: 0, - }) + fn to_handler(&self, _path: EndpointPath) -> Box { + Box::new(ContentHandler::new(self.list_pages(), "application/json".to_owned())) } } -struct RestApiHandler { - pages: String, - write_pos: usize, -} - -impl server::Handler for RestApiHandler { - fn on_request(&mut self, _request: server::Request) -> Next { - Next::write() - } - - fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next { - Next::write() - } - - fn on_response(&mut self, res: &mut server::Response) -> Next { - res.set_status(StatusCode::Ok); - res.headers_mut().set(header::ContentType("application/json".parse().unwrap())); - Next::write() - } - - fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next { - let bytes = self.pages.as_bytes(); - if self.write_pos == bytes.len() { - return Next::end(); - } - - match encoder.write(&bytes[self.write_pos..]) { - Ok(bytes) => { - self.write_pos += bytes; - Next::write() - }, - Err(e) => match e.kind() { - ::std::io::ErrorKind::WouldBlock => Next::write(), - _ => Next::end() - }, - } - } -} diff --git a/webapp/src/apps.rs b/webapp/src/apps.rs index b0a4472f7..c07e9919c 100644 --- a/webapp/src/apps.rs +++ b/webapp/src/apps.rs @@ -16,27 +16,36 @@ use endpoint::Endpoints; use page::PageEndpoint; +use proxypac::ProxyPac; +use parity_webapp::WebApp; extern crate parity_status; #[cfg(feature = "parity-wallet")] extern crate parity_wallet; - pub fn main_page() -> &'static str { "/status/" } pub fn all_endpoints() -> Endpoints { let mut pages = Endpoints::new(); - pages.insert("status".to_owned(), Box::new(PageEndpoint::new(parity_status::App::default()))); + pages.insert("proxy".to_owned(), ProxyPac::boxed()); + + insert::(&mut pages, "status"); + insert::(&mut pages, "parity"); + wallet_page(&mut pages); pages } #[cfg(feature = "parity-wallet")] fn wallet_page(pages: &mut Endpoints) { - pages.insert("wallet".to_owned(), Box::new(PageEndpoint::new(parity_wallet::App::default()))); + insert::(pages, "wallet"); } #[cfg(not(feature = "parity-wallet"))] fn wallet_page(_pages: &mut Endpoints) {} + +fn insert(pages: &mut Endpoints, id: &str) { + pages.insert(id.to_owned(), Box::new(PageEndpoint::new(T::default()))); +} diff --git a/webapp/src/endpoint.rs b/webapp/src/endpoint.rs index dee2cadd8..d367734c4 100644 --- a/webapp/src/endpoint.rs +++ b/webapp/src/endpoint.rs @@ -16,12 +16,73 @@ //! URL Endpoint traits -use hyper::server; +use hyper::status::StatusCode; +use hyper::{header, server, Decoder, Encoder, Next}; use hyper::net::HttpStream; + +use std::io::Write; use std::collections::HashMap; +#[derive(Debug, PartialEq, Default, Clone)] +pub struct EndpointPath { + pub app_id: String, + pub host: String, + pub port: u16, +} + pub trait Endpoint : Send + Sync { - fn to_handler(&self, prefix: &str) -> Box>; + fn to_handler(&self, path: EndpointPath) -> Box>; } pub type Endpoints = HashMap>; +pub type Handler = server::Handler; + +pub struct ContentHandler { + content: String, + mimetype: String, + write_pos: usize, +} + +impl ContentHandler { + pub fn new(content: String, mimetype: String) -> Self { + ContentHandler { + content: content, + mimetype: mimetype, + write_pos: 0 + } + } +} + +impl server::Handler for ContentHandler { + fn on_request(&mut self, _request: server::Request) -> Next { + Next::write() + } + + fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next { + Next::write() + } + + fn on_response(&mut self, res: &mut server::Response) -> Next { + res.set_status(StatusCode::Ok); + res.headers_mut().set(header::ContentType(self.mimetype.parse().unwrap())); + Next::write() + } + + fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next { + let bytes = self.content.as_bytes(); + if self.write_pos == bytes.len() { + return Next::end(); + } + + match encoder.write(&bytes[self.write_pos..]) { + Ok(bytes) => { + self.write_pos += bytes; + Next::write() + }, + Err(e) => match e.kind() { + ::std::io::ErrorKind::WouldBlock => Next::write(), + _ => Next::end() + }, + } + } +} diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 30431578f..2c74dbdc3 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -57,12 +57,15 @@ mod page; mod router; mod rpc; mod api; +mod proxypac; use std::sync::{Arc, Mutex}; use std::net::SocketAddr; use jsonrpc_core::{IoHandler, IoDelegate}; use router::auth::{Authorization, NoAuth, HttpBasicAuth}; +static DAPPS_DOMAIN : &'static str = ".parity"; + /// Webapps HTTP+RPC server build. pub struct ServerBuilder { handler: Arc, diff --git a/webapp/src/page/mod.rs b/webapp/src/page/mod.rs index cd527578b..abcd1930b 100644 --- a/webapp/src/page/mod.rs +++ b/webapp/src/page/mod.rs @@ -22,7 +22,7 @@ use hyper::header; use hyper::status::StatusCode; use hyper::net::HttpStream; use hyper::{Decoder, Encoder, Next}; -use endpoint::Endpoint; +use endpoint::{Endpoint, EndpointPath}; use parity_webapp::WebApp; pub struct PageEndpoint { @@ -38,12 +38,11 @@ impl PageEndpoint { } impl Endpoint for PageEndpoint { - fn to_handler(&self, prefix: &str) -> Box> { + fn to_handler(&self, path: EndpointPath) -> Box> { Box::new(PageHandler { app: self.app.clone(), - prefix: prefix.to_owned(), - prefix_with_slash: prefix.to_owned() + "/", - path: None, + path: path, + file: None, write_pos: 0, }) } @@ -51,21 +50,41 @@ impl Endpoint for PageEndpoint { struct PageHandler { app: Arc, - prefix: String, - prefix_with_slash: String, - path: Option, + path: EndpointPath, + file: Option, write_pos: usize, } +impl PageHandler { + fn extract_path(&self, path: &str) -> String { + let prefix = "/".to_owned() + &self.path.app_id; + let prefix_with_slash = prefix.clone() + "/"; + + // Index file support + match path == "/" || path == &prefix || path == &prefix_with_slash { + true => "index.html".to_owned(), + false => if path.starts_with(&prefix_with_slash) { + path[prefix_with_slash.len()..].to_owned() + } else if path.starts_with("/") { + path[1..].to_owned() + } else { + path.to_owned() + } + } + } +} + impl server::Handler for PageHandler { fn on_request(&mut self, req: server::Request) -> Next { - if let RequestUri::AbsolutePath(ref path) = *req.uri() { - // Index file support - self.path = match path == &self.prefix || path == &self.prefix_with_slash { - true => Some("index.html".to_owned()), - false => Some(path[self.prefix_with_slash.len()..].to_owned()), - }; - } + self.file = match *req.uri() { + RequestUri::AbsolutePath(ref path) => { + Some(self.extract_path(path)) + }, + RequestUri::AbsoluteUri(ref url) => { + Some(self.extract_path(url.path())) + }, + _ => None, + }; Next::write() } @@ -74,7 +93,7 @@ impl server::Handler for PageHandler { } fn on_response(&mut self, res: &mut server::Response) -> Next { - if let Some(f) = self.path.as_ref().and_then(|f| self.app.file(f)) { + if let Some(f) = self.file.as_ref().and_then(|f| self.app.file(f)) { res.set_status(StatusCode::Ok); res.headers_mut().set(header::ContentType(f.content_type.parse().unwrap())); Next::write() @@ -86,7 +105,7 @@ impl server::Handler for PageHandler { fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next { let (wrote, res) = { - let file = self.path.as_ref().and_then(|f| self.app.file(f)); + let file = self.file.as_ref().and_then(|f| self.app.file(f)); match file { None => (None, Next::end()), Some(f) if self.write_pos == f.content.len() => (None, Next::end()), diff --git a/webapp/src/proxypac.rs b/webapp/src/proxypac.rs new file mode 100644 index 000000000..da2cab916 --- /dev/null +++ b/webapp/src/proxypac.rs @@ -0,0 +1,48 @@ +// 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 . + +//! Serving ProxyPac file + +use endpoint::{Endpoint, Handler, ContentHandler, EndpointPath}; +use DAPPS_DOMAIN; + +pub struct ProxyPac; + +impl ProxyPac { + pub fn boxed() -> Box { + Box::new(ProxyPac) + } +} + +impl Endpoint for ProxyPac { + fn to_handler(&self, path: EndpointPath) -> Box { + let content = format!( +r#" +function FindProxyForURL(url, host) {{ + if (shExpMatch(host, "*{0}")) + {{ + return "PROXY {1}:{2}"; + }} + + return "DIRECT"; +}} +"#, + DAPPS_DOMAIN, path.host, path.port); + Box::new(ContentHandler::new(content, "application/javascript".to_owned())) + } +} + + diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index 15fc496f9..11205068a 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -21,16 +21,25 @@ mod url; mod redirect; pub mod auth; +use DAPPS_DOMAIN; use std::sync::Arc; +use url::Host; use hyper; use hyper::{server, uri, header}; use hyper::{Next, Encoder, Decoder}; use hyper::net::HttpStream; -use endpoint::{Endpoint, Endpoints}; +use endpoint::{Endpoint, Endpoints, EndpointPath}; use self::url::Url; use self::auth::{Authorization, Authorized}; use self::redirect::Redirection; +#[derive(Debug, PartialEq)] +enum SpecialEndpoint { + Rpc, + Api, + None +} + pub struct Router { main_page: &'static str, endpoints: Arc, @@ -43,32 +52,43 @@ pub struct Router { impl server::Handler for Router { fn on_request(&mut self, req: server::Request) -> Next { + // Check authorization let auth = self.authorization.is_authorized(&req); + + // Choose proper handler depending on path / domain self.handler = match auth { Authorized::No(handler) => handler, Authorized::Yes => { - let path = self.extract_request_path(&req); - match path { - Some(ref url) if self.endpoints.contains_key(url) => { - let prefix = "/".to_owned() + url; - self.endpoints.get(url).unwrap().to_handler(&prefix) + let url = extract_url(&req); + let endpoint = extract_endpoint(&url); + + match endpoint { + // First check RPC requests + (ref path, SpecialEndpoint::Rpc) if *req.method() != hyper::method::Method::Get => { + self.rpc.to_handler(path.clone().unwrap_or_default()) }, - Some(ref url) if url == "api" => { - self.api.to_handler("/api") + // Check API requests + (ref path, SpecialEndpoint::Api) => { + self.api.to_handler(path.clone().unwrap_or_default()) }, + // Then delegate to dapp + (Some(ref path), _) if self.endpoints.contains_key(&path.app_id) => { + self.endpoints.get(&path.app_id).unwrap().to_handler(path.clone()) + }, + // Redirection to main page _ if *req.method() == hyper::method::Method::Get => { Redirection::new(self.main_page) }, + // RPC by default _ => { - self.rpc.to_handler(&"/") + self.rpc.to_handler(EndpointPath::default()) } } } }; - self.handler.on_request(req) - // Check authorization - // Choose proper handler depending on path + // Delegate on_request to proper handler + self.handler.on_request(req) } /// This event occurs each time the `Request` is ready to be read from. @@ -95,7 +115,7 @@ impl Router { api: Arc>, authorization: Arc) -> Self { - let handler = rpc.to_handler(&"/"); + let handler = rpc.to_handler(EndpointPath::default()); Router { main_page: main_page, endpoints: endpoints, @@ -105,43 +125,123 @@ impl Router { handler: handler, } } +} - fn extract_url(&self, req: &server::Request) -> Option { - 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::() { - Some(ref host) => { - format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) - }, - None => return None, - }; +fn extract_url(req: &server::Request) -> Option { + 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::() { + 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_request_path(&self, req: &server::Request) -> Option { - let url = self.extract_url(&req); - match url { - Some(ref url) if url.path.len() > 1 => { - let part = url.path[0].clone(); - Some(part) - }, - _ => { - None - }, - } + match Url::parse(&url_string) { + Ok(url) => Some(url), + _ => None, + } + }, + _ => None, } } + +fn extract_endpoint(url: &Option) -> (Option, SpecialEndpoint) { + fn special_endpoint(url: &Url) -> SpecialEndpoint { + if url.path.len() <= 1 { + return SpecialEndpoint::None; + } + match url.path[0].as_ref() { + "rpc" => SpecialEndpoint::Rpc, + "api" => SpecialEndpoint::Api, + _ => SpecialEndpoint::None, + } + } + + match *url { + Some(ref url) => match url.host { + Host::Domain(ref domain) if domain.ends_with(DAPPS_DOMAIN) => { + let len = domain.len() - DAPPS_DOMAIN.len(); + let id = domain[0..len].to_owned(); + + (Some(EndpointPath { + app_id: id, + host: domain.clone(), + port: url.port, + }), special_endpoint(url)) + }, + _ if url.path.len() > 1 => { + let id = url.path[0].clone(); + (Some(EndpointPath { + app_id: id.clone(), + host: format!("{}", url.host), + port: url.port, + }), special_endpoint(url)) + }, + _ => (None, special_endpoint(url)), + }, + _ => (None, SpecialEndpoint::None) + } +} + +#[test] +fn should_extract_endpoint() { + assert_eq!(extract_endpoint(&None), (None, SpecialEndpoint::None)); + + // With path prefix + assert_eq!( + extract_endpoint(&Url::parse("http://localhost:8080/status/index.html").ok()), + (Some(EndpointPath { + app_id: "status".to_owned(), + host: "localhost".to_owned(), + port: 8080, + }), SpecialEndpoint::None) + ); + + // With path prefix + assert_eq!( + extract_endpoint(&Url::parse("http://localhost:8080/rpc/").ok()), + (Some(EndpointPath { + app_id: "rpc".to_owned(), + host: "localhost".to_owned(), + port: 8080, + }), SpecialEndpoint::Rpc) + ); + + // By Subdomain + assert_eq!( + extract_endpoint(&Url::parse("http://my.status.dapp/test.html").ok()), + (Some(EndpointPath { + app_id: "my.status".to_owned(), + host: "my.status.dapp".to_owned(), + port: 80, + }), SpecialEndpoint::None) + ); + + // RPC by subdomain + assert_eq!( + extract_endpoint(&Url::parse("http://my.status.dapp/rpc/").ok()), + (Some(EndpointPath { + app_id: "my.status".to_owned(), + host: "my.status.dapp".to_owned(), + port: 80, + }), SpecialEndpoint::Rpc) + ); + + // API by subdomain + assert_eq!( + extract_endpoint(&Url::parse("http://my.status.dapp/rpc/").ok()), + (Some(EndpointPath { + app_id: "my.status".to_owned(), + host: "my.status.dapp".to_owned(), + port: 80, + }), SpecialEndpoint::Api) + ); +} diff --git a/webapp/src/rpc.rs b/webapp/src/rpc.rs index 51e171d8d..7ba0b9584 100644 --- a/webapp/src/rpc.rs +++ b/webapp/src/rpc.rs @@ -15,11 +15,9 @@ // along with Parity. If not, see . use std::sync::{Arc, Mutex}; -use hyper::server; -use hyper::net::HttpStream; use jsonrpc_core::IoHandler; use jsonrpc_http_server::{ServerHandler, PanicHandler, AccessControlAllowOrigin}; -use endpoint::Endpoint; +use endpoint::{Endpoint, EndpointPath, Handler}; pub fn rpc(handler: Arc, panic_handler: Arc () + Send>>>>) -> Box { Box::new(RpcEndpoint { @@ -36,7 +34,7 @@ struct RpcEndpoint { } impl Endpoint for RpcEndpoint { - fn to_handler(&self, _prefix: &str) -> Box> { + fn to_handler(&self, _path: EndpointPath) -> Box { let panic_handler = PanicHandler { handler: self.panic_handler.clone() }; Box::new(ServerHandler::new(self.handler.clone(), self.cors_domain.clone(), panic_handler)) } From 4e41cbca81a8555a7a3bef97403a3cf81685bb31 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 16 May 2016 19:33:32 +0300 Subject: [PATCH 14/14] Moving all Client public API types to separate mod & binary serialization codegen for that mod (#1051) * transaction moved * trash remove * ids move * receipt * tree-route * blockchain info * log_entry move * trace filter moved * executed & trace moved * localized trace moved * block status moved * build scripts and codegen refs * Cargo.lock update * binary for blockstatus, blockchaininfo * binary for trace * trace filters binary ser * binary for log entries & executed * binary for receipt * special case for u8 & transaction binary attribute * resolved remaining issues & error binary serialization * json-tests util import * fix warnings * ids attr * add missing attributes * Update build.rs --- Cargo.lock | 3 + ethcore/Cargo.toml | 6 + ethcore/build.rs | 33 ++++++ ethcore/src/blockchain/blockchain.rs | 2 +- ethcore/src/blockchain/mod.rs | 3 +- ethcore/src/client/client.rs | 30 +---- ethcore/src/client/mod.rs | 3 +- ethcore/src/error.rs | 44 +------ ethcore/src/executive.rs | 41 +------ ethcore/src/lib.rs | 7 +- ethcore/src/trace/flat.rs | 2 + ethcore/src/trace/mod.rs | 10 +- ethcore/src/types/block_status.rs | 33 ++++++ ethcore/src/types/blockchain_info.rs | 38 ++++++ ethcore/src/types/executed.rs | 109 ++++++++++++++++++ ethcore/src/{client => types}/ids.rs | 13 +-- ethcore/src/{ => types}/log_entry.rs | 16 ++- ethcore/src/types/mod.rs | 20 ++++ ethcore/src/types/mod.rs.in | 25 ++++ ethcore/src/{ => types}/receipt.rs | 13 ++- .../{trace => types/trace_types}/filter.rs | 29 +++-- .../{trace => types/trace_types}/localized.rs | 7 +- ethcore/src/types/trace_types/mod.rs | 21 ++++ .../src/{trace => types/trace_types}/trace.rs | 18 +-- ethcore/src/{ => types}/transaction.rs | 24 ++-- .../src/{blockchain => types}/tree_route.rs | 2 + ipc/codegen/src/serialization.rs | 91 ++++++++++++--- ipc/rpc/src/binary.rs | 32 ++++- ipc/tests/binary.rs.in | 6 + ipc/tests/run.rs | 2 - util/bigint/src/uint.rs | 8 +- util/src/hash.rs | 4 +- 32 files changed, 503 insertions(+), 192 deletions(-) create mode 100644 ethcore/build.rs create mode 100644 ethcore/src/types/block_status.rs create mode 100644 ethcore/src/types/blockchain_info.rs create mode 100644 ethcore/src/types/executed.rs rename ethcore/src/{client => types}/ids.rs (85%) rename ethcore/src/{ => types}/log_entry.rs (91%) create mode 100644 ethcore/src/types/mod.rs create mode 100644 ethcore/src/types/mod.rs.in rename ethcore/src/{ => types}/receipt.rs (80%) rename ethcore/src/{trace => types/trace_types}/filter.rs (93%) rename ethcore/src/{trace => types/trace_types}/localized.rs (89%) create mode 100644 ethcore/src/types/trace_types/mod.rs rename ethcore/src/{trace => types/trace_types}/trace.rs (96%) rename ethcore/src/{ => types}/transaction.rs (91%) rename ethcore/src/{blockchain => types}/tree_route.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index c409cf58a..c6d78d700 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,6 +240,8 @@ dependencies = [ "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.2.0", "ethcore-devtools 1.2.0", + "ethcore-ipc 1.2.0", + "ethcore-ipc-codegen 1.2.0", "ethcore-util 1.2.0", "ethjson 0.1.0", "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -248,6 +250,7 @@ dependencies = [ "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index b5f50b207..d0b1927f6 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -5,6 +5,11 @@ license = "GPL-3.0" name = "ethcore" version = "1.2.0" authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +syntex = "*" +"ethcore-ipc-codegen" = { path = "../ipc/codegen" } [dependencies] log = "0.3" @@ -23,6 +28,7 @@ lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } ethjson = { path = "../json" } bloomchain = "0.1" +"ethcore-ipc" = { path = "../ipc/rpc" } [features] jit = ["evmjit"] diff --git a/ethcore/build.rs b/ethcore/build.rs new file mode 100644 index 000000000..dadcce13a --- /dev/null +++ b/ethcore/build.rs @@ -0,0 +1,33 @@ +// 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 . + +extern crate syntex; +extern crate ethcore_ipc_codegen as codegen; + +use std::env; +use std::path::Path; + +fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + // serialization pass + { + let src = Path::new("src/types/mod.rs.in"); + let dst = Path::new(&out_dir).join("types.rs"); + let mut registry = syntex::Registry::new(); + codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7e5f896fd..d95152341 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -27,7 +27,7 @@ use chainfilter::{ChainFilter, BloomIndex, FilterDataSource}; use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData}; use blockchain::best_block::BestBlock; use blockchain::bloom_indexer::BloomIndexer; -use blockchain::tree_route::TreeRoute; +use types::tree_route::TreeRoute; use blockchain::update::ExtrasUpdate; use blockchain::{CacheSize, ImportRoute}; use db::{Writable, Readable, Key, CacheUpdatePolicy}; diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 29a4ee684..62196825f 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -21,7 +21,6 @@ mod best_block; mod block_info; mod bloom_indexer; mod cache; -mod tree_route; mod update; mod import_route; #[cfg(test)] @@ -29,5 +28,5 @@ mod generator; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::cache::CacheSize; -pub use self::tree_route::TreeRoute; +pub use types::tree_route::TreeRoute; pub use self::import_route::ImportRoute; diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index e385f39a8..0d61325d9 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -44,34 +44,8 @@ use receipt::LocalizedReceipt; pub use blockchain::CacheSize as BlockChainCacheSize; use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; use trace; - -/// General block status -#[derive(Debug, Eq, PartialEq)] -pub enum BlockStatus { - /// Part of the blockchain. - InChain, - /// Queued for import. - Queued, - /// Known as bad. - Bad, - /// Unknown. - Unknown, -} - -/// Information about the blockchain gathered together. -#[derive(Debug)] -pub struct BlockChainInfo { - /// Blockchain difficulty. - pub total_difficulty: U256, - /// Block queue difficulty. - pub pending_total_difficulty: U256, - /// Genesis block hash. - pub genesis_hash: H256, - /// Best blockchain block hash. - pub best_block_hash: H256, - /// Best blockchain block number. - pub best_block_number: BlockNumber -} +pub use types::blockchain_info::BlockChainInfo; +pub use types::block_status::BlockStatus; impl fmt::Display for BlockChainInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 9dddeceb7..a748ff900 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -18,13 +18,12 @@ mod client; mod config; -mod ids; mod test_client; mod trace; pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch}; -pub use self::ids::{BlockId, TransactionId, UncleId, TraceId}; +pub use types::ids::*; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use self::trace::Filter as TraceFilter; pub use executive::{Executed, Executive, TransactOptions}; diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 2e007703b..edec7c959 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -20,49 +20,7 @@ use util::*; use header::BlockNumber; use basic_types::LogBloom; -/// Result of executing the transaction. -#[derive(PartialEq, Debug)] -pub enum ExecutionError { - /// Returned when there gas paid for transaction execution is - /// lower than base gas required. - NotEnoughBaseGas { - /// Absolute minimum gas required. - required: U256, - /// Gas provided. - got: U256 - }, - /// Returned when block (gas_used + gas) > gas_limit. - /// - /// If gas =< gas_limit, upstream may try to execute the transaction - /// in next block. - BlockGasLimitReached { - /// Gas limit of block for transaction. - gas_limit: U256, - /// Gas used in block prior to transaction. - gas_used: U256, - /// Amount of gas in block. - gas: U256 - }, - /// Returned when transaction nonce does not match state nonce. - InvalidNonce { - /// Nonce expected. - expected: U256, - /// Nonce found. - got: U256 - }, - /// Returned when cost of transaction (value + gas_price * gas) exceeds - /// current sender balance. - NotEnoughCash { - /// Minimum required balance. - required: U512, - /// Actual balance. - got: U512 - }, - /// Returned when internal evm error occurs. - Internal, - /// Returned when generic transaction occurs - TransactionMalformed(String), -} +pub use types::executed::ExecutionError; #[derive(Debug, PartialEq)] /// Errors concerning transaction processing. diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 179195078..74e0499c1 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -24,6 +24,8 @@ use substate::*; use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer}; use crossbeam; +pub use types::executed::{Executed, ExecutionResult}; + /// Max depth to avoid stack overflow (when it's reached we start a new thread with VM) /// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132) /// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp` @@ -45,45 +47,6 @@ pub struct TransactOptions { pub check_nonce: bool, } -/// Transaction execution receipt. -#[derive(Debug, PartialEq, Clone)] -pub struct Executed { - /// Gas paid up front for execution of transaction. - pub gas: U256, - - /// Gas used during execution of transaction. - pub gas_used: U256, - - /// Gas refunded after the execution of transaction. - /// To get gas that was required up front, add `refunded` and `gas_used`. - pub refunded: U256, - - /// Cumulative gas used in current block so far. - /// - /// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)` - /// - /// where `tn` is current transaction. - pub cumulative_gas_used: U256, - - /// Vector of logs generated by transaction. - pub logs: Vec, - - /// Addresses of contracts created during execution of transaction. - /// Ordered from earliest creation. - /// - /// eg. sender creates contract A and A in constructor creates contract B - /// - /// B creation ends first, and it will be the first element of the vector. - pub contracts_created: Vec
, - /// Transaction output. - pub output: Bytes, - /// The trace of this transaction. - pub trace: Option, -} - -/// Transaction execution result. -pub type ExecutionResult = Result; - /// Transaction executor. pub struct Executive<'a> { state: &'a mut State, diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 43b4c5099..0b62ec4fb 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -85,6 +85,7 @@ extern crate num_cpus; extern crate crossbeam; extern crate ethjson; extern crate bloomchain; +#[macro_use] extern crate ethcore_ipc as ipc; #[cfg(test)] extern crate ethcore_devtools as devtools; #[cfg(feature = "jit" )] extern crate evmjit; @@ -98,12 +99,9 @@ pub mod ethereum; pub mod filter; pub mod header; pub mod service; -pub mod log_entry; pub mod trace; pub mod spec; -pub mod transaction; pub mod views; -pub mod receipt; pub mod pod_state; mod db; @@ -128,9 +126,12 @@ mod executive; mod externalities; mod verification; mod blockchain; +mod types; #[cfg(test)] mod tests; #[cfg(test)] #[cfg(feature="json-tests")] mod json_tests; + +pub use types::*; diff --git a/ethcore/src/trace/flat.rs b/ethcore/src/trace/flat.rs index ae3f22050..f9d3b0831 100644 --- a/ethcore/src/trace/flat.rs +++ b/ethcore/src/trace/flat.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Flat trace module + use trace::BlockTraces; use super::trace::{Trace, Action, Res}; diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index 831a55cd5..01763a167 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -21,20 +21,18 @@ mod bloom; mod config; mod db; mod executive_tracer; -mod filter; -mod flat; +pub mod flat; mod import; -mod localized; mod noop_tracer; -pub mod trace; +pub use types::trace_types::*; pub use self::block::BlockTraces; pub use self::config::{Config, Switch}; pub use self::db::TraceDB; -pub use self::trace::Trace; +pub use types::trace_types::trace::Trace; pub use self::noop_tracer::NoopTracer; pub use self::executive_tracer::ExecutiveTracer; -pub use self::filter::{Filter, AddressesFilter}; +pub use types::trace_types::filter::{Filter, AddressesFilter}; pub use self::import::ImportRequest; pub use self::localized::LocalizedTrace; use util::{Bytes, Address, U256, H256}; diff --git a/ethcore/src/types/block_status.rs b/ethcore/src/types/block_status.rs new file mode 100644 index 000000000..ca0f47227 --- /dev/null +++ b/ethcore/src/types/block_status.rs @@ -0,0 +1,33 @@ +// 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 . + +//! Block status description module + +use ipc::binary::BinaryConvertError; +use std::collections::VecDeque; + +/// General block status +#[derive(Debug, Eq, PartialEq, Binary)] +pub enum BlockStatus { + /// Part of the blockchain. + InChain, + /// Queued for import. + Queued, + /// Known as bad. + Bad, + /// Unknown. + Unknown, +} diff --git a/ethcore/src/types/blockchain_info.rs b/ethcore/src/types/blockchain_info.rs new file mode 100644 index 000000000..4e8634dba --- /dev/null +++ b/ethcore/src/types/blockchain_info.rs @@ -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 . + +//! Blockhain info type definition + +use util::numbers::*; +use header::BlockNumber; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; + +/// Information about the blockchain gathered together. +#[derive(Debug, Binary)] +pub struct BlockChainInfo { + /// Blockchain difficulty. + pub total_difficulty: U256, + /// Block queue difficulty. + pub pending_total_difficulty: U256, + /// Genesis block hash. + pub genesis_hash: H256, + /// Best blockchain block hash. + pub best_block_hash: H256, + /// Best blockchain block number. + pub best_block_number: BlockNumber +} diff --git a/ethcore/src/types/executed.rs b/ethcore/src/types/executed.rs new file mode 100644 index 000000000..f03a1c26b --- /dev/null +++ b/ethcore/src/types/executed.rs @@ -0,0 +1,109 @@ +// 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 . + +//! Transaction execution format module. + +use util::numbers::*; +use util::Bytes; +use trace::Trace; +use types::log_entry::LogEntry; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; + +/// Transaction execution receipt. +#[derive(Debug, PartialEq, Clone, Binary)] +pub struct Executed { + /// Gas paid up front for execution of transaction. + pub gas: U256, + + /// Gas used during execution of transaction. + pub gas_used: U256, + + /// Gas refunded after the execution of transaction. + /// To get gas that was required up front, add `refunded` and `gas_used`. + pub refunded: U256, + + /// Cumulative gas used in current block so far. + /// + /// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)` + /// + /// where `tn` is current transaction. + pub cumulative_gas_used: U256, + + /// Vector of logs generated by transaction. + pub logs: Vec, + + /// Addresses of contracts created during execution of transaction. + /// Ordered from earliest creation. + /// + /// eg. sender creates contract A and A in constructor creates contract B + /// + /// B creation ends first, and it will be the first element of the vector. + pub contracts_created: Vec
, + /// Transaction output. + pub output: Bytes, + /// The trace of this transaction. + pub trace: Option, +} + +/// Result of executing the transaction. +#[derive(PartialEq, Debug, Binary)] +pub enum ExecutionError { + /// Returned when there gas paid for transaction execution is + /// lower than base gas required. + NotEnoughBaseGas { + /// Absolute minimum gas required. + required: U256, + /// Gas provided. + got: U256 + }, + /// Returned when block (gas_used + gas) > gas_limit. + /// + /// If gas =< gas_limit, upstream may try to execute the transaction + /// in next block. + BlockGasLimitReached { + /// Gas limit of block for transaction. + gas_limit: U256, + /// Gas used in block prior to transaction. + gas_used: U256, + /// Amount of gas in block. + gas: U256 + }, + /// Returned when transaction nonce does not match state nonce. + InvalidNonce { + /// Nonce expected. + expected: U256, + /// Nonce found. + got: U256 + }, + /// Returned when cost of transaction (value + gas_price * gas) exceeds + /// current sender balance. + NotEnoughCash { + /// Minimum required balance. + required: U512, + /// Actual balance. + got: U512 + }, + /// Returned when internal evm error occurs. + Internal, + /// Returned when generic transaction occurs + TransactionMalformed(String), +} + + +/// Transaction execution result. +pub type ExecutionResult = Result; diff --git a/ethcore/src/client/ids.rs b/ethcore/src/types/ids.rs similarity index 85% rename from ethcore/src/client/ids.rs rename to ethcore/src/types/ids.rs index 693cab528..8fffcb8f7 100644 --- a/ethcore/src/client/ids.rs +++ b/ethcore/src/types/ids.rs @@ -18,10 +18,13 @@ use util::hash::H256; use header::BlockNumber; -use util::bytes::{FromRawBytes, FromBytesError, ToBytesWithMap, Populatable}; +use ipc::binary::BinaryConvertError; +use ipc::binary::BinaryConvertable; +use std::mem; +use std::collections::VecDeque; /// Uniquely identifies block. -#[derive(Debug, PartialEq, Clone, Hash, Eq)] +#[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)] pub enum BlockId { /// Block's sha3. /// Querying by hash is always faster. @@ -35,7 +38,7 @@ pub enum BlockId { } /// Uniquely identifies transaction. -#[derive(Debug, PartialEq, Clone, Hash, Eq)] +#[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)] pub enum TransactionId { /// Transaction's sha3. Hash(H256), @@ -60,7 +63,3 @@ pub struct UncleId ( /// Position in block. pub usize ); - -sized_binary_map!(TransactionId); -sized_binary_map!(UncleId); -sized_binary_map!(BlockId); diff --git a/ethcore/src/log_entry.rs b/ethcore/src/types/log_entry.rs similarity index 91% rename from ethcore/src/log_entry.rs rename to ethcore/src/types/log_entry.rs index 2a7ca080f..7d8dccc6c 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/types/log_entry.rs @@ -14,15 +14,23 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Block log. +//! Log entry type definition. -use util::*; +use util::numbers::*; +use std::ops::Deref; +use util::rlp::*; +use util::Bytes; +use util::HeapSizeOf; +use util::sha3::*; use basic_types::LogBloom; use header::BlockNumber; use ethjson; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// A record of execution for a `LOG` operation. -#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq, Binary)] pub struct LogEntry { /// The address of the contract executing at the point of the `LOG` operation. pub address: Address, @@ -77,7 +85,7 @@ impl From for LogEntry { } /// Log localized in a blockchain. -#[derive(Default, Debug, PartialEq, Clone)] +#[derive(Default, Debug, PartialEq, Clone, Binary)] pub struct LocalizedLogEntry { /// Plain log entry. pub entry: LogEntry, diff --git a/ethcore/src/types/mod.rs b/ethcore/src/types/mod.rs new file mode 100644 index 000000000..112f79c32 --- /dev/null +++ b/ethcore/src/types/mod.rs @@ -0,0 +1,20 @@ +// 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 . + +//! Types used in the public api + +#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues +include!(concat!(env!("OUT_DIR"), "/types.rs")); diff --git a/ethcore/src/types/mod.rs.in b/ethcore/src/types/mod.rs.in new file mode 100644 index 000000000..1f67a9184 --- /dev/null +++ b/ethcore/src/types/mod.rs.in @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +pub mod transaction; +pub mod ids; +pub mod receipt; +pub mod tree_route; +pub mod blockchain_info; +pub mod log_entry; +pub mod trace_types; +pub mod executed; +pub mod block_status; diff --git a/ethcore/src/receipt.rs b/ethcore/src/types/receipt.rs similarity index 80% rename from ethcore/src/receipt.rs rename to ethcore/src/types/receipt.rs index 2fbd3f14c..cc83e2f97 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/types/receipt.rs @@ -16,13 +16,18 @@ //! Receipt -use util::*; +use util::numbers::*; +use util::rlp::*; +use util::HeapSizeOf; use basic_types::LogBloom; use header::BlockNumber; use log_entry::{LogEntry, LocalizedLogEntry}; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// Information describing execution of a transaction. -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Binary)] pub struct Receipt { /// The state root after executing the transaction. pub state_root: H256, @@ -76,7 +81,7 @@ impl HeapSizeOf for Receipt { } /// Receipt with additional info. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub struct LocalizedReceipt { /// Transaction hash. pub transaction_hash: H256, @@ -98,7 +103,7 @@ pub struct LocalizedReceipt { #[test] fn test_basic() { - let expected = FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let expected = ::rustc_serialize::hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap(); let r = Receipt::new( x!("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee"), x!(0x40cae), diff --git a/ethcore/src/trace/filter.rs b/ethcore/src/types/trace_types/filter.rs similarity index 93% rename from ethcore/src/trace/filter.rs rename to ethcore/src/types/trace_types/filter.rs index d1f699c52..c02a15c03 100644 --- a/ethcore/src/trace/filter.rs +++ b/ethcore/src/types/trace_types/filter.rs @@ -14,41 +14,49 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Trace filters type definitions + use std::ops::Range; use bloomchain::{Filter as BloomFilter, Bloom, Number}; use util::{Address, FixedHash}; use util::sha3::Hashable; use basic_types::LogBloom; -use super::flat::FlatTrace; -use super::trace::Action; +use trace::flat::FlatTrace; +use types::trace_types::trace::Action; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// Addresses filter. /// /// Used to create bloom possibilities and match filters. -pub struct AddressesFilter(Vec
); +#[derive(Binary)] +pub struct AddressesFilter { + list: Vec
+} impl From> for AddressesFilter { fn from(addresses: Vec
) -> Self { - AddressesFilter(addresses) + AddressesFilter { list: addresses } } } impl AddressesFilter { /// Returns true if address matches one of the searched addresses. pub fn matches(&self, address: &Address) -> bool { - self.matches_all() || self.0.contains(address) + self.matches_all() || self.list.contains(address) } /// Returns true if this address filter matches everything. pub fn matches_all(&self) -> bool { - self.0.is_empty() + self.list.is_empty() } /// Returns blooms of this addresses filter. pub fn blooms(&self) -> Vec { - match self.0.is_empty() { + match self.list.is_empty() { true => vec![LogBloom::new()], - false => self.0.iter() + false => self.list.iter() .map(|address| LogBloom::from_bloomed(&address.sha3())) .collect() } @@ -56,11 +64,11 @@ impl AddressesFilter { /// Returns vector of blooms zipped with blooms of this addresses filter. pub fn with_blooms(&self, blooms: Vec) -> Vec { - match self.0.is_empty() { + match self.list.is_empty() { true => blooms, false => blooms .into_iter() - .flat_map(|bloom| self.0.iter() + .flat_map(|bloom| self.list.iter() .map(|address| bloom.with_bloomed(&address.sha3())) .collect::>()) .collect() @@ -68,6 +76,7 @@ impl AddressesFilter { } } +#[derive(Binary)] /// Traces filter. pub struct Filter { /// Block range. diff --git a/ethcore/src/trace/localized.rs b/ethcore/src/types/trace_types/localized.rs similarity index 89% rename from ethcore/src/trace/localized.rs rename to ethcore/src/types/trace_types/localized.rs index ef18d6898..334d7b518 100644 --- a/ethcore/src/trace/localized.rs +++ b/ethcore/src/types/trace_types/localized.rs @@ -14,12 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Localized traces type definitions + use util::H256; use super::trace::{Action, Res}; use header::BlockNumber; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// Localized trace. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Binary)] pub struct LocalizedTrace { /// Type of action performed by a transaction. pub action: Action, diff --git a/ethcore/src/types/trace_types/mod.rs b/ethcore/src/types/trace_types/mod.rs new file mode 100644 index 000000000..db429a8f4 --- /dev/null +++ b/ethcore/src/types/trace_types/mod.rs @@ -0,0 +1,21 @@ +// 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 . + +//! Types used in the public api + +pub mod filter; +pub mod trace; +pub mod localized; diff --git a/ethcore/src/trace/trace.rs b/ethcore/src/types/trace_types/trace.rs similarity index 96% rename from ethcore/src/trace/trace.rs rename to ethcore/src/types/trace_types/trace.rs index f7efe9721..f8fe07360 100644 --- a/ethcore/src/trace/trace.rs +++ b/ethcore/src/types/trace_types/trace.rs @@ -15,14 +15,18 @@ // along with Parity. If not, see . //! Tracing datatypes. + use util::{U256, Bytes, Address, FixedHash}; use util::rlp::*; use util::sha3::Hashable; use action_params::ActionParams; use basic_types::LogBloom; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// `Call` result. -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Binary)] pub struct CallResult { /// Gas used by call. pub gas_used: U256, @@ -51,7 +55,7 @@ impl Decodable for CallResult { } /// `Create` result. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub struct CreateResult { /// Gas used by create. pub gas_used: U256, @@ -84,7 +88,7 @@ impl Decodable for CreateResult { } /// Description of a _call_ action, either a `CALL` operation or a message transction. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub struct Call { /// The sending account. pub from: Address, @@ -146,7 +150,7 @@ impl Call { } /// Description of a _create_ action, either a `CREATE` operation or a create transction. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub struct Create { /// The address of the creator. pub from: Address, @@ -202,7 +206,7 @@ impl Create { } /// Description of an action that we trace; will be either a call or a create. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub enum Action { /// It's a call action. Call(Call), @@ -249,7 +253,7 @@ impl Action { } /// The result of the performed action. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub enum Res { /// Successful call action result. Call(CallResult), @@ -300,7 +304,7 @@ impl Decodable for Res { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] /// A trace; includes a description of the action being traced and sub traces of each interior action. pub struct Trace { /// The number of EVM execution environments active when this action happened; 0 if it's diff --git a/ethcore/src/transaction.rs b/ethcore/src/types/transaction.rs similarity index 91% rename from ethcore/src/transaction.rs rename to ethcore/src/types/transaction.rs index ca54f26bb..842decd88 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -16,13 +16,21 @@ //! Transaction data structure. -use util::*; +use util::numbers::*; +use std::ops::Deref; +use util::rlp::*; +use util::sha3::*; +use util::{UtilError, CryptoError, Bytes, Signature, Secret, ec}; +use std::cell::*; use error::*; use evm::Schedule; use header::BlockNumber; use ethjson; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Binary)] /// Transaction action type. pub enum Action { /// Create creates new contract. @@ -48,7 +56,7 @@ impl Decodable for Action { /// A set of information describing an externally-originating message call /// or contract creation operation. -#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq, Binary)] pub struct Transaction { /// Nonce. pub nonce: U256, @@ -183,7 +191,7 @@ impl Transaction { } /// Signed transaction information. -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone, Eq, Binary)] pub struct SignedTransaction { /// Plain Transaction. unsigned: Transaction, @@ -310,7 +318,7 @@ impl SignedTransaction { } try!(self.sender()); if self.gas < U256::from(self.gas_required(&schedule)) { - Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) + Err(From::from(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) } else { Ok(self) } @@ -318,7 +326,7 @@ impl SignedTransaction { } /// Signed Transaction that is a part of canon blockchain. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Binary)] pub struct LocalizedTransaction { /// Signed part. pub signed: SignedTransaction, @@ -340,7 +348,7 @@ impl Deref for LocalizedTransaction { #[test] fn sender_test() { - let t: SignedTransaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); + let t: SignedTransaction = decode(&::rustc_serialize::hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); assert_eq!(t.data, b""); assert_eq!(t.gas, U256::from(0x5208u64)); assert_eq!(t.gas_price, U256::from(0x01u64)); @@ -354,7 +362,7 @@ fn sender_test() { #[test] fn signing() { - let key = KeyPair::create().unwrap(); + let key = ::util::crypto::KeyPair::create().unwrap(); let t = Transaction { action: Action::Create, nonce: U256::from(42), diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/types/tree_route.rs similarity index 96% rename from ethcore/src/blockchain/tree_route.rs rename to ethcore/src/types/tree_route.rs index 3c4906449..2ad0aa240 100644 --- a/ethcore/src/blockchain/tree_route.rs +++ b/ethcore/src/types/tree_route.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Tree route info type definition + use util::numbers::H256; /// Represents a tree route between `from` block and `to` block: diff --git a/ipc/codegen/src/serialization.rs b/ipc/codegen/src/serialization.rs index 6a9784790..e8f3d2cd8 100644 --- a/ipc/codegen/src/serialization.rs +++ b/ipc/codegen/src/serialization.rs @@ -175,6 +175,11 @@ fn binary_expr_struct( ) -> Result { let size_exprs: Vec> = fields.iter().enumerate().map(|(index, field)| { + + if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { + return quote_expr!(cx, 1); + } + let field_type_ident = builder.id( &::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))); @@ -228,23 +233,34 @@ fn binary_expr_struct( }, }; - write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() { - 0 => mem::size_of::<$field_type_ident>(), - _ => { let size = $member_expr .size(); length_stack.push_back(size); size }, - }).unwrap()); - - write_stmts.push(quote_stmt!(cx, - if let Err(e) = $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack) { return Err(e) };).unwrap()); + if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { + write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).unwrap()); + write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).unwrap()); + } + else { + write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() { + 0 => mem::size_of::<$field_type_ident>(), + _ => { let size = $member_expr .size(); length_stack.push_back(size); size }, + }).unwrap()); + write_stmts.push(quote_stmt!(cx, + if let Err(e) = $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack) { return Err(e) };).unwrap()); + } write_stmts.push(quote_stmt!(cx, offset = next_line; ).unwrap()); let field_index = builder.id(&format!("{}", index)); map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap()); - map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() { - 0 => mem::size_of::<$field_type_ident>(), - _ => length_stack.pop_front().unwrap(), - }).unwrap()); - map_stmts.push(quote_stmt!(cx, total = total + size;).unwrap()); + + if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { + map_stmts.push(quote_stmt!(cx, total = total + 1;).unwrap()); + } + else { + map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() { + 0 => mem::size_of::<$field_type_ident>(), + _ => length_stack.pop_front().unwrap(), + }).unwrap()); + map_stmts.push(quote_stmt!(cx, total = total + size;).unwrap()); + } }; let read_expr = match fields.iter().any(|f| codegen::has_ptr(&f.ty)) { @@ -366,6 +382,8 @@ fn fields_sequence( use syntax::parse::token; use syntax::ast::TokenTree::Token; + let named_members = fields.iter().any(|f| f.ident.is_some()); + ::quasi::parse_expr_panic(&mut ::syntax::parse::new_parser_from_tts( ext_cx.parse_sess(), ext_cx.cfg(), @@ -373,7 +391,12 @@ fn fields_sequence( let _sp = ext_cx.call_site(); let mut tt = ::std::vec::Vec::new(); tt.push(Token(_sp, token::Ident(variant_ident.clone()))); - tt.push(Token(_sp, token::OpenDelim(token::Paren))); + if named_members { + tt.push(Token(_sp, token::OpenDelim(token::Brace))); + } + else { + tt.push(Token(_sp, token::OpenDelim(token::Paren))); + } for (idx, field) in fields.iter().enumerate() { if field.ident.is_some() { @@ -381,6 +404,21 @@ fn fields_sequence( tt.push(Token(_sp, token::Colon)); } + // special case for u8, it just takes byte form sequence + if ::syntax::print::pprust::ty_to_string(&field.ty) == "u8" { + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer")))); + + tt.push(Token(_sp, token::OpenDelim(token::Bracket))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map")))); + tt.push(Token(_sp, token::OpenDelim(token::Bracket))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx))))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + + tt.push(Token(_sp, token::Comma)); + continue; + } + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!")))); tt.push(Token(_sp, token::OpenDelim(token::Paren))); tt.push( @@ -393,6 +431,7 @@ fn fields_sequence( tt.push(Token(_sp, token::OpenDelim(token::Paren))); tt.push(Token(_sp, token::BinOp(token::And))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer")))); tt.push(Token(_sp, token::OpenDelim(token::Bracket))); @@ -418,8 +457,12 @@ fn fields_sequence( tt.push(Token(_sp, token::CloseDelim(token::Paren))); tt.push(Token(_sp, token::Comma)); } - tt.push(Token(_sp, token::CloseDelim(token::Paren))); - + if named_members { + tt.push(Token(_sp, token::CloseDelim(token::Brace))); + } + else { + tt.push(Token(_sp, token::CloseDelim(token::Paren))); + } tt }) ).unwrap() @@ -455,6 +498,21 @@ fn named_fields_sequence( tt.push(Token(_sp, token::Ident(field.ident.clone().unwrap()))); tt.push(Token(_sp, token::Colon)); + // special case for u8, it just takes byte form sequence + if ::syntax::print::pprust::ty_to_string(&field.ty) == "u8" { + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer")))); + + tt.push(Token(_sp, token::OpenDelim(token::Bracket))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map")))); + tt.push(Token(_sp, token::OpenDelim(token::Bracket))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx))))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + + tt.push(Token(_sp, token::Comma)); + continue; + } + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!")))); tt.push(Token(_sp, token::OpenDelim(token::Paren))); tt.push(Token( @@ -573,7 +631,6 @@ fn binary_expr_variant( .map(|(id, field)|(field.ident.unwrap(), builder.pat().ref_id(id)))) .build(); - let binary_expr = try!(binary_expr_struct( cx, &builder, @@ -593,7 +650,7 @@ fn binary_expr_variant( let buffer = &mut buffer[1..]; $write_expr }), - read: quote_arm!(cx, $pat => { $read_expr } ), + read: quote_arm!(cx, $variant_index_ident => { $read_expr } ), }) }, } diff --git a/ipc/rpc/src/binary.rs b/ipc/rpc/src/binary.rs index 3ba172c6e..4fb359f7c 100644 --- a/ipc/rpc/src/binary.rs +++ b/ipc/rpc/src/binary.rs @@ -17,9 +17,10 @@ //! Binary representation of types use util::bytes::Populatable; -use util::numbers::{U256, H256, H2048, Address}; +use util::numbers::{U256, U512, H256, H2048, Address}; use std::mem; use std::collections::VecDeque; +use std::ops::Range; #[derive(Debug)] pub struct BinaryConvertError; @@ -232,6 +233,29 @@ impl BinaryConvertable for ::std::cell::RefCell where T: BinaryConvertable } } +impl BinaryConvertable for ::std::cell::Cell where T: BinaryConvertable + Copy { + fn size(&self) -> usize { + self.get().size() + } + + fn from_empty_bytes() -> Result { + Ok(::std::cell::Cell::new(try!(T::from_empty_bytes()))) + } + + fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result { + Ok(::std::cell::Cell::new(try!(T::from_bytes(buffer, length_stack)))) + } + + fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> { + try!(self.get().to_bytes(buffer, length_stack)); + Ok(()) + } + + fn len_params() -> usize { + T::len_params() + } +} + impl BinaryConvertable for Vec { fn size(&self) -> usize { self.len() @@ -365,8 +389,9 @@ pub fn serialize(t: &T) -> Result, BinaryConvertEr Ok(buff.into_inner()) } +#[macro_export] macro_rules! binary_fixed_size { - ($target_ty: ident) => { + ($target_ty: ty) => { impl BinaryConvertable for $target_ty { fn from_bytes(bytes: &[u8], _length_stack: &mut VecDeque) -> Result { match bytes.len().cmp(&::std::mem::size_of::<$target_ty>()) { @@ -398,9 +423,12 @@ binary_fixed_size!(usize); binary_fixed_size!(i32); binary_fixed_size!(bool); binary_fixed_size!(U256); +binary_fixed_size!(U512); binary_fixed_size!(H256); binary_fixed_size!(H2048); binary_fixed_size!(Address); +binary_fixed_size!(Range); +binary_fixed_size!(Range); #[test] fn vec_serialize() { diff --git a/ipc/tests/binary.rs.in b/ipc/tests/binary.rs.in index 710752237..74dd39c1b 100644 --- a/ipc/tests/binary.rs.in +++ b/ipc/tests/binary.rs.in @@ -36,3 +36,9 @@ pub struct DoubleRoot { pub struct ReferenceStruct<'a> { pub ref_data: &'a u64, } + +#[derive(Binary, PartialEq, Debug)] +pub enum EnumWithStruct { + Left, + Right { how_much: u64 }, +} diff --git a/ipc/tests/run.rs b/ipc/tests/run.rs index c07145f77..cdda5275b 100644 --- a/ipc/tests/run.rs +++ b/ipc/tests/run.rs @@ -16,9 +16,7 @@ #![allow(dead_code)] -extern crate bincode; extern crate ethcore_ipc as ipc; -extern crate serde; extern crate ethcore_devtools as devtools; extern crate semver; extern crate nanomsg; diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index be9941589..f87b494a9 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -517,7 +517,7 @@ pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Displa /// Return single byte fn byte(&self, index: usize) -> u8; /// Get this Uint as slice of bytes - fn to_bytes(&self, bytes: &mut[u8]); + fn to_raw_bytes(&self, bytes: &mut[u8]); /// Create `Uint(10**n)` fn exp10(n: usize) -> Self; @@ -621,7 +621,7 @@ macro_rules! construct_uint { (arr[index / 8] >> (((index % 8)) * 8)) as u8 } - fn to_bytes(&self, bytes: &mut[u8]) { + fn to_raw_bytes(&self, bytes: &mut[u8]) { assert!($n_words * 8 == bytes.len()); let &$name(ref arr) = self; for i in 0..bytes.len() { @@ -780,7 +780,7 @@ macro_rules! construct_uint { where S: serde::Serializer { let mut hex = "0x".to_owned(); let mut bytes = [0u8; 8 * $n_words]; - self.to_bytes(&mut bytes); + self.to_raw_bytes(&mut bytes); let len = cmp::max((self.bits() + 7) / 8, 1); hex.push_str(bytes[bytes.len() - len..].to_hex().as_ref()); serializer.serialize_str(hex.as_ref()) @@ -1482,7 +1482,7 @@ mod tests { let hex = "8090a0b0c0d0e0f00910203040506077583a2cf8264910e1436bda32571012f0"; let uint = U256::from_str(hex).unwrap(); let mut bytes = [0u8; 32]; - uint.to_bytes(&mut bytes); + uint.to_raw_bytes(&mut bytes); let uint2 = U256::from(&bytes[..]); assert_eq!(uint, uint2); } diff --git a/util/src/hash.rs b/util/src/hash.rs index 69ed17c79..e1b82b14c 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -517,7 +517,7 @@ impl From for H256 { fn from(value: U256) -> H256 { unsafe { let mut ret: H256 = ::std::mem::uninitialized(); - value.to_bytes(&mut ret); + value.to_raw_bytes(&mut ret); ret } } @@ -527,7 +527,7 @@ impl<'_> From<&'_ U256> for H256 { fn from(value: &'_ U256) -> H256 { unsafe { let mut ret: H256 = ::std::mem::uninitialized(); - value.to_bytes(&mut ret); + value.to_raw_bytes(&mut ret); ret } }